Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
78.95% covered (warning)
78.95%
15 / 19
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ShadowRoot
78.95% covered (warning)
78.95%
15 / 19
75.00% covered (warning)
75.00%
3 / 4
7.46
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 slots
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 collectSlots
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
 shallowClone
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Html\Dom;
6
7/**
8 * Shadow root attached to an Element host. Created by the parser when it
9 * encounters <template shadowrootmode="open|closed"> (declarative shadow DOM)
10 * or by Element::attachShadow() at author request.
11 *
12 * Inherits DocumentFragment so it composes into the tree the same way and
13 * carries no host-document state of its own.
14 */
15final class ShadowRoot extends DocumentFragment
16{
17    public readonly Element $host;
18    public readonly ShadowRootMode $mode;
19    public readonly bool $delegatesFocus;
20    public readonly bool $clonable;
21    public readonly bool $serializable;
22    public readonly SlotAssignment $slotAssignment;
23
24    public function __construct(
25        Element $host,
26        ShadowRootMode $mode,
27        ShadowRootInit $init = new ShadowRootInit(),
28    ) {
29        parent::__construct($host->ownerDocument);
30        $this->host = $host;
31        $this->mode = $mode;
32        $this->delegatesFocus = $init->delegatesFocus;
33        $this->clonable = $init->clonable;
34        $this->serializable = $init->serializable;
35        $this->slotAssignment = $init->slotAssignment;
36    }
37
38    /**
39     * Slots in tree order. Walks the entire shadow tree, depth-first.
40     *
41     * @return list<HTMLSlotElement>
42     */
43    public function slots(): array
44    {
45        $out = [];
46        $this->collectSlots($this, $out);
47        return $out;
48    }
49
50    /** @param list<HTMLSlotElement> $out */
51    private function collectSlots(Node $scope, array &$out): void
52    {
53        for ($n = $scope->firstChild; $n !== null; $n = $n->nextSibling) {
54            if ($n instanceof HTMLSlotElement) {
55                $out[] = $n;
56            }
57            if ($n->hasChildNodes()) {
58                $this->collectSlots($n, $out);
59            }
60        }
61    }
62
63    protected function shallowClone(): static
64    {
65        throw new \LogicException(
66            'ShadowRoot::shallowClone requires a host context; clone via Element::cloneNode(deep: true) ' .
67            'which delegates to the host clone path.',
68        );
69    }
70}