From 9137b506bcff399d86166a7c1ac7da903077033e Mon Sep 17 00:00:00 2001 From: Anne van Kesteren Date: Tue, 17 Dec 2024 18:29:50 +0100 Subject: [PATCH 1/8] Add Scoped Custom Element Registries HTML PR: https://github.com/whatwg/html/pull/10869. Tests: ... Closes #1339. --- dom.bs | 364 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 252 insertions(+), 112 deletions(-) diff --git a/dom.bs b/dom.bs index 04d9bb20..8e3cd872 100644 --- a/dom.bs +++ b/dom.bs @@ -2830,9 +2830,22 @@ before a child, with an optional suppress observers flag, run
  • Run the insertion steps with inclusiveDescendant.

  • -

    If inclusiveDescendant is connected: +

    If inclusiveDescendant is connected and is an element:

      +
    1. If inclusiveDescendant's custom element registry is + null, then set inclusiveDescendant's custom element registry to + the result of looking up a custom element registry given + inclusiveDescendant's parent. + + +

    2. Otherwise, if inclusiveDescendant's + custom element registry's is scoped is true, append + inclusiveDescendant's node document to + inclusiveDescendant's custom element registry's + scoped document set. + +

    3. If inclusiveDescendant is custom, then enqueue a custom element callback reaction with inclusiveDescendant, callback name "connectedCallback", and « ». @@ -2845,9 +2858,29 @@ before a child, with an optional suppress observers flag, run connectedCallback will be enqueued automatically during the upgrade an element algorithm.

    -
  • + +
  • +

    Otherwise, if inclusiveDescendant is connected and is a + shadow root: + +

      +
    1. If

    2. inclusiveDescendant's custom element registry + is null and
    3. inclusiveDescendant's + keep custom element registry null is false, then set + inclusiveDescendant's custom element registry to the result + of looking up a custom element registry given inclusiveDescendant's + host. + + +
    4. Otherwise, if inclusiveDescendant's + custom element registry is non-null and + inclusiveDescendant's custom element registry's + is scoped is true, append inclusiveDescendant's + node document to inclusiveDescendant's + custom element registry's scoped document set. + +

    -
  • If suppress observers flag is unset, then queue a tree mutation record for @@ -4555,15 +4588,17 @@ and <{template}>. SVG ought to do the same for its <{script}> elements, but does

    To clone a node given a node node and an optional document document (default node's node document), boolean -subtree (default false), and -node-or-null parent (default null): +subtree (default false), node-or-null +parent (default null), and null or a +{{CustomElementRegistry}} object fallbackRegistry +(default null):

    1. Assert: node is not a document or node is document. -

    2. Let copy be the result of cloning a single node given node and - document. +

    3. Let copy be the result of cloning a single node given node, + document, and fallbackRegistry.

    4. Run any cloning steps defined for node in other applicable specifications and pass node, copy, and @@ -4575,8 +4610,9 @@ and an optional document docume

    5. If subtree is true, then for each child of node's children, in tree order: clone a node given child with document set to document, - subtree set to subtree, and - parent set to copy. + subtree set to subtree, + parent set to copy, and + fallbackRegistry set to fallbackRegistry.

    6. If node is an element, node is a @@ -4586,11 +4622,18 @@ and an optional document docume

      1. Assert: copy is not a shadow host. +

      2. Let shadowRootRegistry be node's shadow root's + custom element registry. + +

      3. If shadowRootRegistry is null, then set shadowRootRegistry to + fallbackRegistry. +

      4. Attach a shadow root with copy, node's shadow root's mode, true, node's shadow root's serializable, node's - shadow root's delegates focus, and node's - shadow root's slot assignment. + shadow root's delegates focus, node's + shadow root's slot assignment, and + shadowRootRegistry.

      5. Set copy's shadow root's declarative to node's shadow root's declarative. @@ -4598,8 +4641,9 @@ and an optional document docume

      6. For each child of node's shadow root's children, in tree order: clone a node given child with document set to document, - subtree set to subtree, and - parent set to copy's shadow root. + subtree set to subtree, + parent set to copy's shadow root, + and fallbackRegistry set to fallbackRegistry.

    7. Return copy. @@ -4607,8 +4651,9 @@ and an optional document docume

      -

      To clone a single node given a node node and -document document: +

      To clone a single node given a node node, +document document, and null or a {{CustomElementRegistry}} object +fallbackRegistry:

      1. Let copy be null. @@ -4617,10 +4662,15 @@ and an optional document docume

        If node is an element:

          +
        1. Let registry be node's custom element registry. + +

        2. If registry is null, then set registry to + fallbackRegistry. +

        3. Set copy to the result of creating an element, given document, node's local name, node's - namespace, node's namespace prefix, and - node's is value. + namespace, node's namespace prefix, + node's is value, false, and registry.

        4. For each attribute of node's @@ -4628,7 +4678,7 @@ and an optional document docume

          1. Let copyAttribute be the result of cloning a single node given - attribute and document. + attribute, document, and null.

          2. Append copyAttribute to copy.

          @@ -6059,6 +6109,9 @@ interface ShadowRoot : DocumentFragment { readonly attribute boolean clonable; readonly attribute boolean serializable; readonly attribute Element host; + + readonly attribute CustomElementRegistry? customElements; + attribute EventHandler onslotchange; }; @@ -6069,22 +6122,23 @@ enum SlotAssignmentMode { "manual", "named" };

          {{ShadowRoot}} nodes are simply known as shadow roots. +

          Shadow roots's associated host is never null.

          + +

          Shadow roots have an associated mode ("open" or "closed").

          -

          Shadow roots have an associated delegates focus. -It is initially set to false.

          +

          Shadow roots have an associated delegates focus +(a boolean). It is initially set to false.

          Shadow roots have an associated -available to element internals. It is initially set to false.

          +available to element internals (a boolean). It is initially set to +false.

          Shadow roots have an associated declarative (a boolean). It is initially set to false.

          -

          Shadow roots's associated host is never null.

          - -

          Shadow roots have an associated slot assignment ("manual" or "named"). @@ -6094,12 +6148,26 @@ It is initially set to false.

          Shadow roots have an associated serializable (a boolean). It is initially set to false.

          +

          Shadow roots have an associated custom element registry +(null or a {{CustomElementRegistry}} object).

          + +

          Shadow roots have an associated +keep custom element registry null (a boolean). It is initially false. + +

          This can only ever be true in combination with declarative shadow roots. And it only +matters for as long as the shadow root's custom element registry +is null. + +


          +

          A shadow root's get the parent algorithm, given an event, returns null if event's composed flag is unset and shadow root is the root of event's path's first struct's invocation target; otherwise shadow root's host. +


          +

          The mode getter steps are to return this's mode.

          @@ -6118,6 +6186,13 @@ null if event's composed flag is unset and shadow roo

          The host getter steps are to return this's host. +


          + +

          The customElements getter steps are to return +this's custom element registry. + +


          +

          The onslotchange attribute is an event handler IDL attribute for the onslotchange event handler, whose @@ -6230,6 +6305,8 @@ interface Element : Node { ShadowRoot attachShadow(ShadowRootInit init); readonly attribute ShadowRoot? shadowRoot; + readonly attribute CustomElementRegistry? customElements; + Element? closest(DOMString selectors); boolean matches(DOMString selectors); boolean webkitMatchesSelector(DOMString selectors); // legacy alias of .matches @@ -6248,28 +6325,47 @@ dictionary ShadowRootInit { SlotAssignmentMode slotAssignment = "named"; boolean clonable = false; boolean serializable = false; + CustomElementRegistry customElements; };

          {{Element}} nodes are simply known as elements. -

          Elements have an associated -namespace, -namespace prefix, -local name, -custom element state, -custom element definition, -is value. When an -element is created, all of these values are +

          Elements have an associated: + +

          +
          namespace +
          Null or a non-empty string. + +
          namespace prefix +
          Null or a non-empty string. + +
          local name +
          A non-empty string. + +
          custom element registry +
          Null or a {{CustomElementRegistry}} object. + +
          custom element state +
          "undefined", "failed", "uncustomized", + "precustomized", or "custom". + +
          custom element definition +
          Null or a custom element definition. + + +
          is value +
          Null or a valid custom element name. +
          + +

          When an element is created, all of these values are initialized. -

          An element's custom element state is one of -"undefined", "failed", "uncustomized", -"precustomized", or "custom". An element whose -custom element state is "uncustomized" or "custom" is -said to be defined. An element -whose custom element state is "custom" is said to be +

          An element whose custom element state is +"uncustomized" or "custom" is said to be +defined. An element whose +custom element state is "custom" is said to be custom.

          Whether or not an element is defined is used to determine the @@ -6342,14 +6438,18 @@ value of these steps:

          To create an element, given a document document, string localName, string-or-null namespace, and optionally a string-or-null prefix (default null), string-or-null is (default -null), and boolean synchronousCustomElements (default false): +null), boolean synchronousCustomElements (default false), and null or a +{{CustomElementRegistry}} object registry:

          1. Let result be null. -

          2. Let definition be the result of - looking up a custom element definition given - document, namespace, localName, and is. +

          3. If registry is not given, then set registry to the result of + looking up a custom element registry given document. + + +

          4. Let definition be the result of looking up a custom element definition + given registry, namespace, localName, and is.

          5. If definition is non-null, and definition's @@ -6361,13 +6461,9 @@ null), and boolean synchronousCustomElements (default false):

          6. Let interface be the element interface for localName and the HTML namespace. -

          7. Set result to a new element that implements interface, - with no attributes, namespace set to the HTML namespace, - namespace prefix set to prefix, local name set - to localName, custom element state set to "undefined", - custom element definition set to null, - is value set to is, and node document set to - document. +

          8. Set result to the result of creating an element internal given + document, interface, localName, the HTML namespace, + prefix, "undefined", is, and registry.

          9. If synchronousCustomElements is true, then run this step while catching any @@ -6399,74 +6495,82 @@ null), and boolean synchronousCustomElements (default false):

            1. -

              If synchronousCustomElements is true, then run these steps while catching any - exceptions: +

              If synchronousCustomElements is true:

              1. Let C be definition's constructor. -

              2. Set result to the result of constructing C, with no - arguments. - -

              3. Assert: result's custom element state and - custom element definition are initialized. +

              4. Set the surrounding agent's + active custom element constructor map[C] to registry. +

              5. -

                Assert: result's namespace is the HTML namespace. +

                Run these steps while catching any exceptions: -

                IDL enforces that result is an {{HTMLElement}} object, which all use - the HTML namespace. +

                  +
                1. Set result to the result of constructing C, with no + arguments. -

                2. If result's attribute list is not empty, - then throw a "{{NotSupportedError!!exception}}" {{DOMException}}. +

                3. Assert: result's custom element state and + custom element definition are initialized. -

                4. If result has children, then throw a - "{{NotSupportedError!!exception}}" {{DOMException}}. +

                5. +

                  Assert: result's namespace is the HTML namespace. -

                6. If result's parent is not null, then throw a - "{{NotSupportedError!!exception}}" {{DOMException}}. +

                  IDL enforces that result is an {{HTMLElement}} object, which all + use the HTML namespace. -

                7. If result's node document is not document, then - throw a "{{NotSupportedError!!exception}}" {{DOMException}}. +

                8. If result's attribute list is not empty, + then throw a "{{NotSupportedError!!exception}}" {{DOMException}}. -

                9. If result's local name is not equal to - localName, then throw a "{{NotSupportedError!!exception}}" {{DOMException}}. +

                10. If result has children, then throw a + "{{NotSupportedError!!exception}}" {{DOMException}}. -

                11. Set result's namespace prefix to prefix. +

                12. If result's parent is not null, then throw a + "{{NotSupportedError!!exception}}" {{DOMException}}. -

                13. Set result's is value to null. -

                +
              6. If result's node document is not document, then + throw a "{{NotSupportedError!!exception}}" {{DOMException}}. -

                If any of these steps threw an exception exception: +

              7. If result's local name is not equal to + localName, then throw a "{{NotSupportedError!!exception}}" {{DOMException}}. -

                  -
                1. Report exception for definition's - constructor's corresponding JavaScript object's - associated realm's global object. +

                2. Set result's namespace prefix to prefix. + +

                3. Set result's is value to null. -

                4. Set result to a new element that implements the - {{HTMLUnknownElement}} interface, with no attributes, namespace set to the - HTML namespace, namespace prefix set to prefix, - local name set to localName, - custom element state set to "failed", - custom element definition set to null, - is value set to null, and node document set to - document. +

                5. Set result's custom element registry to + registry. +

                + +

                If any of these steps threw an exception exception: + +

                  +
                1. Report exception for + definition's constructor's corresponding + JavaScript object's associated realm's global object. + +

                2. Set result to the result of creating an element internal given + document, {{HTMLUnknownElement}}, localName, the HTML namespace, + prefix, "failed", null, and registry. +

                + +
              8. +

                Remove the surrounding agent's + active custom element constructor map[C]. + + +

                Under normal circumstances it will already have been removed at this point.

              -
            2. Otherwise:

                -
              1. Set result to a new element that implements the {{HTMLElement}} - interface, with no attributes, namespace set to the HTML namespace, - namespace prefix set to prefix, local name set - to localName, custom element state set to - "undefined", custom element definition set to null, - is value set to null, and node document set to - document. +

              2. Set result to the result of creating an element internal given + document, {{HTMLElement}}, localName, the HTML namespace, + prefix, "undefined", null, and registry.

              3. Enqueue a custom element upgrade reaction given result and definition. @@ -6482,13 +6586,9 @@ null), and boolean synchronousCustomElements (default false):

              4. Let interface be the element interface for localName and namespace. -

              5. Set result to a new element that implements interface, - with no attributes, namespace set to namespace, - namespace prefix set to prefix, local name set - to localName, custom element state set to - "uncustomized", custom element definition set to null, - is value set to is, and node document set to - document. +

              6. Set result to the result of creating an element internal given + document, interface, localName, namespace, + prefix, "uncustomized", is, and registry.

              7. If namespace is the HTML namespace, and either localName is a valid custom element name or is is non-null, then set result's @@ -6499,6 +6599,26 @@ null), and boolean synchronousCustomElements (default false):

              8. Return result.

              +

              To create an element internal given a document document, an +interface interface a string localName, a string-or-null namespace, +a string-or-null prefix, a string state, a string-or-null is, and +null or a {{CustomElementRegistry}} object registry: + +

                +
              1. Let element be a new element that implements interface, + with namespace set to namespace, namespace prefix + set to prefix, local name set to localName, + custom element registry set to registry, + custom element state set to state, + custom element definition set to null, is value + set to is, and node document set to document. + +

              2. Assert: element's attribute list + is empty. + +

              3. Return element. +

              +

              Elements also have an attribute list, which is a list exposed through a {{NamedNodeMap}}. Unless explicitly given when an @@ -7069,12 +7189,12 @@ are:


              -
              var shadow = element . {{attachShadow(init)}} +
              shadow = element . {{attachShadow(init)}}

              Creates a shadow root for element and returns it. -

              var shadow = element . {{shadowRoot}} +
              shadow = element . {{shadowRoot}}

              Returns element's shadow root, if any, and if - shadow root's mode is "open", and null otherwise. + shadow root's mode is "open"; otherwise null.

              A valid shadow host name is: @@ -7105,11 +7225,16 @@ are:

              The attachShadow(init) method steps are:

                +
              1. Let registry be this's custom element registry. + +

              2. If init["{{ShadowRootInit/customElements}}"] exists, then set + registry to it. +

              3. Run attach a shadow root with this, init["{{ShadowRootInit/mode}}"], init["{{ShadowRootInit/clonable}}"], init["{{ShadowRootInit/serializable}}"], - init["{{ShadowRootInit/delegatesFocus}}"], and - init["{{ShadowRootInit/slotAssignment}}"]. + init["{{ShadowRootInit/delegatesFocus}}"], + init["{{ShadowRootInit/slotAssignment}}"], and registry.

              4. Return this's shadow root.

              @@ -7118,8 +7243,8 @@ are:

              To attach a shadow root, given an element element, a string mode, a boolean clonable, -a boolean serializable, a boolean delegatesFocus, and a string -slotAssignment: +a boolean serializable, a boolean delegatesFocus, a string +slotAssignment, and null or a {{CustomElementRegistry}} object registry:

              1. If element's namespace is not the HTML namespace, @@ -7134,10 +7259,10 @@ a boolean serializable, a boolean delegatesFocus, and a st element's is value is non-null:

                  -
                1. Let definition be the result of - looking up a custom element definition given - element's node document, its namespace, its - local name, and its is value. +

                2. Let definition be the result of looking up a custom element definition + given element's custom element registry, its + namespace, its local name, and its + is value.

                3. If definition is not null and definition's disable shadow is true, then throw a @@ -7193,6 +7318,9 @@ a boolean serializable, a boolean delegatesFocus, and a st

                4. Set shadow's serializable to serializable. +

                5. Set shadow's custom element registry to + registry. +

                6. Set element's shadow root to shadow.

              @@ -7212,6 +7340,18 @@ a boolean serializable, a boolean delegatesFocus, and a st
              +
              +
              registry = element . {{Element/customElements}} +

              Returns element's {{CustomElementRegistry}} object, if any; otherwise null. +

              + +
              +

              The customElements getter steps are to return +this's custom element registry. +

              + +
              +
              element . {{closest(selectors)}}
              Returns the first (starting at element) From 7e04bae9b66947485e4946d10f96e44e81c9cbe2 Mon Sep 17 00:00:00 2001 From: Anne van Kesteren Date: Fri, 21 Feb 2025 10:39:46 +0100 Subject: [PATCH 2/8] Fix createElement and importNode --- dom.bs | 110 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 24 deletions(-) diff --git a/dom.bs b/dom.bs index 8e3cd872..e05e317d 100644 --- a/dom.bs +++ b/dom.bs @@ -5208,7 +5208,7 @@ interface Document : Node { [NewObject] Comment createComment(DOMString data); [NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data); - [CEReactions, NewObject] Node importNode(Node node, optional boolean subtree = false); + [CEReactions, NewObject] Node importNode(Node node, optional (boolean or ImportNodeOptions) options = false); [CEReactions] Node adoptNode(Node node); [NewObject] Attr createAttribute(DOMString localName); @@ -5227,8 +5227,14 @@ interface Document : Node { interface XMLDocument : Document {}; dictionary ElementCreationOptions { + CustomElementRegistry customElements; DOMString is; }; + +dictionary ImportNodeOptions { + CustomElementRegistry customElements; + selfOnly = false; +}

              {{Document}} nodes are simply @@ -5450,12 +5456,19 @@ method steps are to return the list of elements with class names classNa document is an HTML document or document's content type is "application/xhtml+xml"; otherwise null. -

              If localName does not match the Name production an - "{{InvalidCharacterError!!exception}}" {{DOMException}} will be thrown. +

              When supplied, options's {{ElementCreationOptions/customElements}} can be used to + set the {{CustomElementRegistry}}.

              When supplied, options's {{ElementCreationOptions/is}} can be used to create a customized built-in element. +

              If localName does not match the Name production an + "{{InvalidCharacterError!!exception}}" {{DOMException}} will be thrown. + +

              When both options's {{ElementCreationOptions/customElements}} and + options's {{ElementCreationOptions/is}} are supplied, a + "{{NotSupportedError!!exception}}" {{DOMException}} will be thrown. +

              element = document . createElementNS(namespace, qualifiedName [, options])
              @@ -5464,6 +5477,12 @@ method steps are to return the list of elements with class names classNa qualifiedName or null. Its local name will be everything after U+003A (:) in qualifiedName or qualifiedName. +

              When supplied, options's {{ElementCreationOptions/customElements}} can be used to + set the {{CustomElementRegistry}}. + +

              When supplied, options's {{ElementCreationOptions/is}} can be used to create a + customized built-in element. +

              If qualifiedName does not match the QName production an "{{InvalidCharacterError!!exception}}" {{DOMException}} will be thrown. @@ -5486,8 +5505,9 @@ method steps are to return the list of elements with class names classNa is "xmlns". -

              When supplied, options's {{ElementCreationOptions/is}} can be used to create a - customized built-in element. +

              When both options's {{ElementCreationOptions/customElements}} and + options's {{ElementCreationOptions/is}} are supplied, a + "{{NotSupportedError!!exception}}" {{DOMException}} will be thrown.

              documentFragment = document . {{createDocumentFragment()}}
              Returns a {{DocumentFragment}} node. @@ -5533,18 +5553,15 @@ method steps are:
            3. If this is an HTML document, then set localName to localName in ASCII lowercase. -

            4. Let is be null. - -

            5. If options is a dictionary and - options["{{ElementCreationOptions/is}}"] exists, then set is - to it. +

            6. Let registry and is be the result of + flattening element creation options given options and this.

            7. Let namespace be the HTML namespace, if this is an HTML document or this's content type is "application/xhtml+xml"; otherwise null.

            8. Return the result of creating an element given this, localName, - namespace, null, is, and true. + namespace, null, is, true, and registry.

            The internal createElementNS steps, given document, @@ -5554,14 +5571,12 @@ method steps are:

          10. Let namespace, prefix, and localName be the result of passing namespace and qualifiedName to validate and extract. -

          11. Let is be null. - -

          12. If options is a dictionary and - options["{{ElementCreationOptions/is}}"] exists, then set is - to it. +

          13. Let registry and is be the result of + flattening element creation options given options and this.

          14. Return the result of creating an element given document, - localName, namespace, prefix, is, and true. + localName, namespace, prefix, is, true, and + registry.

          The @@ -5570,6 +5585,31 @@ method steps are to return the result of running the internal createElementNS steps, given this, namespace, qualifiedName, and options. +

          To flatten element creation options, given a string or {{ElementCreationOptions}} +dictionary options and a document document: + +

            +
          1. Let registry be null. + +

          2. Let is be null. + +
          3. +

            If options is a dictionary: + +

              +
            1. If options["{{ElementCreationOptions/customElements}}"] exists, + then set registry to it. + +

            2. If options["{{ElementCreationOptions/is}}"] exists, then set + is to it. +

            + +
          4. If registry is non-null and is is non-null, then throw a + "{{NotSupportedError!!exception}}" {{DOMException}}. + +

          5. Return registry and is. +

          +

          {{Document/createElement()}} and {{Document/createElementNS()}}'s options parameter is allowed to be a string for web compatibility. @@ -5635,11 +5675,15 @@ method steps are:


          -
          clone = document . importNode(node [, subtree = false]) +
          clone = document . importNode(node [, options = false])
          -

          Returns a copy of node. If subtree is true, the copy also includes the +

          Returns a copy of node. If options is true or options is a + dictionary whose {{ImportNodeOptions/selfOnly}} is false, the copy also includes the node's descendants. +

          If options's {{ImportNodeOptions/customElements}} can be used to set the + {{CustomelementRegistry}} of elements that have none. +

          If node is a document or a shadow root, throws a "{{NotSupportedError!!exception}}" {{DOMException}}. @@ -5655,16 +5699,34 @@ method steps are:

          -

          The importNode(node, subtree) +

          The importNode(node, options) method steps are:

          1. If node is a document or shadow root, then throw a "{{NotSupportedError!!exception}}" {{DOMException}}. +

          2. Let subtree be false. + +

          3. Let registry be false. + +

          4. If options is a boolean, then set subtree to options. + +

          5. +

            Otherwise: + +

              +
            1. Set subtree to the negation of + options["{{ImportNodeOptions/selfOnly}}"]. + +

            2. If options["{{ImportNodeOptions/customElements}}"] exists, then + set registry to it. +

            +
          6. Return the result of cloning a node given node with - document set to this and - subtree set to subtree. + document set to this, + subtree set to subtree, and + fallbackRegistry set to registry.

          @@ -6439,12 +6501,12 @@ value of these steps: document, string localName, string-or-null namespace, and optionally a string-or-null prefix (default null), string-or-null is (default null), boolean synchronousCustomElements (default false), and null or a -{{CustomElementRegistry}} object registry: +{{CustomElementRegistry}} object registry (default null):
          1. Let result be null. -

          2. If registry is not given, then set registry to the result of +

          3. If registry is null, then set registry to the result of looking up a custom element registry given document. From f441601dbd39d597d55c3b6a7de671a2c36d3350 Mon Sep 17 00:00:00 2001 From: Anne van Kesteren Date: Fri, 21 Feb 2025 10:44:21 +0100 Subject: [PATCH 3/8] CI --- dom.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dom.bs b/dom.bs index e05e317d..40395af2 100644 --- a/dom.bs +++ b/dom.bs @@ -5233,7 +5233,7 @@ dictionary ElementCreationOptions { dictionary ImportNodeOptions { CustomElementRegistry customElements; - selfOnly = false; + boolean selfOnly = false; } @@ -5682,7 +5682,7 @@ method steps are: node's descendants.

            If options's {{ImportNodeOptions/customElements}} can be used to set the - {{CustomelementRegistry}} of elements that have none. + {{CustomElementRegistry}} of elements that have none.

            If node is a document or a shadow root, throws a "{{NotSupportedError!!exception}}" {{DOMException}}. From 71537d2df85f7865e936c9e5fda37724afb93c4e Mon Sep 17 00:00:00 2001 From: Anne van Kesteren Date: Fri, 21 Feb 2025 10:54:03 +0100 Subject: [PATCH 4/8] CI again --- dom.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom.bs b/dom.bs index 40395af2..09359953 100644 --- a/dom.bs +++ b/dom.bs @@ -5234,7 +5234,7 @@ dictionary ElementCreationOptions { dictionary ImportNodeOptions { CustomElementRegistry customElements; boolean selfOnly = false; -} +};

            {{Document}} nodes are simply From 2038a336efc058a0061a411fb3efd892adc1d085 Mon Sep 17 00:00:00 2001 From: Anne van Kesteren Date: Wed, 26 Feb 2025 14:05:27 +0100 Subject: [PATCH 5/8] Do not make registries cross the shadow boundary --- dom.bs | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/dom.bs b/dom.bs index 09359953..09db1adc 100644 --- a/dom.bs +++ b/dom.bs @@ -4625,9 +4625,6 @@ and an optional document docume

          4. Let shadowRootRegistry be node's shadow root's custom element registry. -

          5. If shadowRootRegistry is null, then set shadowRootRegistry to - fallbackRegistry. -

          6. Attach a shadow root with copy, node's shadow root's mode, true, node's shadow root's serializable, node's @@ -4638,12 +4635,15 @@ and an optional document docume

          7. Set copy's shadow root's declarative to node's shadow root's declarative. -

          8. For each child of node's shadow root's - children, in tree order: clone a node given child with - document set to document, - subtree set to subtree, - parent set to copy's shadow root, - and fallbackRegistry set to fallbackRegistry. +

          9. +

            For each child of node's shadow root's + children, in tree order: clone a node given child with + document set to document, + subtree set to subtree, and + parent set to copy's shadow root. + +

            This intentionally leaves fallbackRegistry set + to null.

        5. Return copy. @@ -5607,6 +5607,9 @@ dictionary options and a document document:

        6. If registry is non-null and is is non-null, then throw a "{{NotSupportedError!!exception}}" {{DOMException}}. +

        7. If registry is null, then set registry to the result of + looking up a custom element registry given document. +

        8. Return registry and is.

        @@ -5708,7 +5711,7 @@ method steps are:
      2. Let subtree be false. -

      3. Let registry be false. +

      4. Let registry be null.

      5. If options is a boolean, then set subtree to options. @@ -5723,6 +5726,9 @@ method steps are: set registry to it.

      +
    8. If registry is null, then set registry to the result of + looking up a custom element registry given document. +

    9. Return the result of cloning a node given node with document set to this, subtree set to subtree, and @@ -6500,14 +6506,14 @@ value of these steps:

      To create an element, given a document document, string localName, string-or-null namespace, and optionally a string-or-null prefix (default null), string-or-null is (default -null), boolean synchronousCustomElements (default false), and null or a -{{CustomElementRegistry}} object registry (default null): +null), boolean synchronousCustomElements (default false), and "default", +null, or a {{CustomElementRegistry}} object registry (default "default"):

      1. Let result be null. -

      2. If registry is null, then set registry to the result of - looking up a custom element registry given document. +

      3. If registry is "default", then set registry to the result + of looking up a custom element registry given document.

      4. Let definition be the result of looking up a custom element definition From 2b06524009fc118e1b4831459d280e4d999ce94c Mon Sep 17 00:00:00 2001 From: Anne van Kesteren Date: Wed, 26 Feb 2025 14:34:17 +0100 Subject: [PATCH 6/8] Nice one CI --- dom.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom.bs b/dom.bs index 09db1adc..975dff40 100644 --- a/dom.bs +++ b/dom.bs @@ -5727,7 +5727,7 @@ method steps are:

    10. If registry is null, then set registry to the result of - looking up a custom element registry given document. + looking up a custom element registry given this.

    11. Return the result of cloning a node given node with document set to this, From da94abcde75412a515bec7a4b46a362cf5c66bbb Mon Sep 17 00:00:00 2001 From: Anne van Kesteren Date: Mon, 3 Mar 2025 10:34:54 +0100 Subject: [PATCH 7/8] Account for polyfill nonsense --- dom.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom.bs b/dom.bs index 975dff40..53e1aefc 100644 --- a/dom.bs +++ b/dom.bs @@ -6178,7 +6178,7 @@ interface ShadowRoot : DocumentFragment { readonly attribute boolean serializable; readonly attribute Element host; - readonly attribute CustomElementRegistry? customElements; + [Replaceable] readonly attribute CustomElementRegistry? customElements; attribute EventHandler onslotchange; }; @@ -6393,7 +6393,7 @@ dictionary ShadowRootInit { SlotAssignmentMode slotAssignment = "named"; boolean clonable = false; boolean serializable = false; - CustomElementRegistry customElements; + any customElements; }; @@ -7295,8 +7295,8 @@ are:

      1. Let registry be this's custom element registry. -

      2. If init["{{ShadowRootInit/customElements}}"] exists, then set - registry to it. +

      3. If init["{{ShadowRootInit/customElements}}"] exists and is a + {{CustomElementRegistry}} object, then set registry to it.

      4. Run attach a shadow root with this, init["{{ShadowRootInit/mode}}"], init["{{ShadowRootInit/clonable}}"], From 5a1943cf4896ef82c747cb1d569fda905e274b49 Mon Sep 17 00:00:00 2001 From: Anne van Kesteren Date: Thu, 6 Mar 2025 12:56:09 +0100 Subject: [PATCH 8/8] Polyfill rename, expose document.customElementRegistry --- dom.bs | 67 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/dom.bs b/dom.bs index 53e1aefc..ef3c994c 100644 --- a/dom.bs +++ b/dom.bs @@ -3177,12 +3177,30 @@ otherwise, if there is no such element, null.

         interface mixin DocumentOrShadowRoot {
        +  readonly attribute CustomElementRegistry? customElementRegistry;
         };
         Document includes DocumentOrShadowRoot;
         ShadowRoot includes DocumentOrShadowRoot;
         
        -

        The {{DocumentOrShadowRoot}} mixin is expected to be used by other +

        +
        registry = documentOrShadowRoot . {{DocumentOrShadowRoot/customElementRegistry}} +

        Returns documentOrShadowRoot's {{CustomElementRegistry}} object, if any; + otherwise null. +

        + +

        The customElementRegistry getter steps +are: + +

          +
        1. Handle the document node case. + +

        2. Assert: this is a {{ShadowRoot}} node. + +

        3. Return this's custom element registry. +

        + +

        The {{DocumentOrShadowRoot}} mixin is also expected to be used by other standards that want to define APIs shared between documents and shadow roots. @@ -5227,12 +5245,12 @@ interface Document : Node { interface XMLDocument : Document {}; dictionary ElementCreationOptions { - CustomElementRegistry customElements; + CustomElementRegistry customElementRegistry; DOMString is; }; dictionary ImportNodeOptions { - CustomElementRegistry customElements; + CustomElementRegistry customElementRegistry; boolean selfOnly = false; }; @@ -5456,8 +5474,8 @@ method steps are to return the list of elements with class names classNa document is an HTML document or document's content type is "application/xhtml+xml"; otherwise null. -

        When supplied, options's {{ElementCreationOptions/customElements}} can be used to - set the {{CustomElementRegistry}}. +

        When supplied, options's {{ElementCreationOptions/customElementRegistry}} can be + used to set the {{CustomElementRegistry}}.

        When supplied, options's {{ElementCreationOptions/is}} can be used to create a customized built-in element. @@ -5465,7 +5483,7 @@ method steps are to return the list of elements with class names classNa

        If localName does not match the Name production an "{{InvalidCharacterError!!exception}}" {{DOMException}} will be thrown. -

        When both options's {{ElementCreationOptions/customElements}} and +

        When both options's {{ElementCreationOptions/customElementRegistry}} and options's {{ElementCreationOptions/is}} are supplied, a "{{NotSupportedError!!exception}}" {{DOMException}} will be thrown. @@ -5477,8 +5495,8 @@ method steps are to return the list of elements with class names classNa qualifiedName or null. Its local name will be everything after U+003A (:) in qualifiedName or qualifiedName. -

        When supplied, options's {{ElementCreationOptions/customElements}} can be used to - set the {{CustomElementRegistry}}. +

        When supplied, options's {{ElementCreationOptions/customElementRegistry}} can be + used to set the {{CustomElementRegistry}}.

        When supplied, options's {{ElementCreationOptions/is}} can be used to create a customized built-in element. @@ -5505,7 +5523,7 @@ method steps are to return the list of elements with class names classNa is "xmlns". -

        When both options's {{ElementCreationOptions/customElements}} and +

        When both options's {{ElementCreationOptions/customElementRegistry}} and options's {{ElementCreationOptions/is}} are supplied, a "{{NotSupportedError!!exception}}" {{DOMException}} will be thrown. @@ -5597,8 +5615,8 @@ dictionary options and a document document:

        If options is a dictionary:

          -
        1. If options["{{ElementCreationOptions/customElements}}"] exists, - then set registry to it. +

        2. If options["{{ElementCreationOptions/customElementRegistry}}"] + exists, then set registry to it.

        3. If options["{{ElementCreationOptions/is}}"] exists, then set is to it. @@ -5684,7 +5702,7 @@ method steps are: dictionary whose {{ImportNodeOptions/selfOnly}} is false, the copy also includes the node's descendants. -

          If options's {{ImportNodeOptions/customElements}} can be used to set the +

          If options's {{ImportNodeOptions/customElementRegistry}} can be used to set the {{CustomElementRegistry}} of elements that have none.

          If node is a document or a shadow root, throws a @@ -5722,8 +5740,8 @@ method steps are:

        4. Set subtree to the negation of options["{{ImportNodeOptions/selfOnly}}"]. -

        5. If options["{{ImportNodeOptions/customElements}}"] exists, then - set registry to it. +

        6. If options["{{ImportNodeOptions/customElementRegistry}}"] + exists, then set registry to it.

      5. If registry is null, then set registry to the result of @@ -6178,8 +6196,6 @@ interface ShadowRoot : DocumentFragment { readonly attribute boolean serializable; readonly attribute Element host; - [Replaceable] readonly attribute CustomElementRegistry? customElements; - attribute EventHandler onslotchange; }; @@ -6256,11 +6272,6 @@ null if event's composed flag is unset and shadow roo


        -

        The customElements getter steps are to return -this's custom element registry. - -


        -

        The onslotchange attribute is an event handler IDL attribute for the onslotchange event handler, whose @@ -6373,7 +6384,7 @@ interface Element : Node { ShadowRoot attachShadow(ShadowRootInit init); readonly attribute ShadowRoot? shadowRoot; - readonly attribute CustomElementRegistry? customElements; + readonly attribute CustomElementRegistry? customElementRegistry; Element? closest(DOMString selectors); boolean matches(DOMString selectors); @@ -6393,7 +6404,7 @@ dictionary ShadowRootInit { SlotAssignmentMode slotAssignment = "named"; boolean clonable = false; boolean serializable = false; - any customElements; + CustomElementRegistry customElementRegistry; }; @@ -7295,8 +7306,8 @@ are:

        1. Let registry be this's custom element registry. -

        2. If init["{{ShadowRootInit/customElements}}"] exists and is a - {{CustomElementRegistry}} object, then set registry to it. +

        3. If init["{{ShadowRootInit/customElementRegistry}}"] exists, then + set registry to it.

        4. Run attach a shadow root with this, init["{{ShadowRootInit/mode}}"], init["{{ShadowRootInit/clonable}}"], @@ -7409,13 +7420,13 @@ a boolean serializable, a boolean delegatesFocus, a string


          -
          registry = element . {{Element/customElements}} +
          registry = element . {{Element/customElementRegistry}}

          Returns element's {{CustomElementRegistry}} object, if any; otherwise null.

          -

          The customElements getter steps are to return -this's custom element registry. +

          The customElementRegistry getter steps are to +return this's custom element registry.