From 9bb9de1019f6f33941dcedaf736f410c4e718b19 Mon Sep 17 00:00:00 2001 From: Tab Atkins-Bittner Date: Thu, 5 Sep 2024 14:36:34 -0700 Subject: [PATCH] [css-shadow-parts][css-pseudo] Move various ::part() details to 'part-like pseudo-elements'. #10083 --- css-pseudo-4/Overview.bs | 54 +++++++++++----- css-shadow-parts-1/Overview.bs | 115 +++++++++++++++++++++++++++------ 2 files changed, 134 insertions(+), 35 deletions(-) diff --git a/css-pseudo-4/Overview.bs b/css-pseudo-4/Overview.bs index d94c56cc09e..7433e90bd22 100644 --- a/css-pseudo-4/Overview.bs +++ b/css-pseudo-4/Overview.bs @@ -1305,27 +1305,47 @@ Tree-Abiding and Part-Like Pseudo-elements parsing/tree-abiding-pseudo-elements.html +

+Part-Like Pseudo-Elements

+ A subset of [=tree-abiding pseudo-elements=], - the part-like pseudo-elements, + the part-like pseudo-elements, have slightly stronger requirements: they act as if they have a well-defined location in the document tree. This enables them to interact with some other platform features - as if they were real elements. - -
- For example, a [=part-like pseudo-element=] - can be used in the <{html-global/exportparts}> attribute, - to masquerade as a ''::part()'' - for the component it's in: - - - <template id=custom-element-template> - <p exportparts="::before : preceding-text"> - You can style my ::before pseudo-element - by using ::part(preceding-text), too! - </template> - -
+ as if they were real elements + (and, in fact, they often are real elements, + such as in the case of ''::part()'', + which simply aren't accessible in the current tree). + + [=Part-like pseudo-elements=] inherit from their [=originating element=] by default, + like a standard [=tree-abiding pseudo-element=], + but can declare that they inherit from another element instead + (possibly not accessible). + (For example, ''::part()'' inherits from + the parent of the element it represents in the shadow tree.) + + All pseudo-classes and pseudo-elements + are syntactically allowed after a [=part-like pseudo-element=], + such as ''x-button::part(label):hover'' + or ''x-button::part(label)::before'', + but some are disallowed from matching: + + * The [=structural pseudo-classes=], + '':has()'' pseudo-class, + '':scope'' pseudo-class, + and '':host''/'':host()''/'':host-context()'' pseudo-classes + never match. + * ''::part()'' never matches. (Other [=part-like pseudo-elements=] can, however.) + + A [=part-like pseudo-element=] can define itself as representing a real element + (possibly not accessible in the current tree). + If it does so, all pseudo-classes and pseudo-elements match according to that element, + if not disallowed by the previous restrictions. + If it does not do so, + it must define which pseudo-classes it matches and when + (besides the pseudo-classes defined to work on all pseudo-elements, + or all [=tree-abiding pseudo-elements=]). Unless otherwise specified, any CSS property that applies to elements diff --git a/css-shadow-parts-1/Overview.bs b/css-shadow-parts-1/Overview.bs index 915b47e842b..bc00bee090d 100644 --- a/css-shadow-parts-1/Overview.bs +++ b/css-shadow-parts-1/Overview.bs @@ -109,7 +109,16 @@ from the sub-parts that it merely happens to contain, it also helps with encapsulation, as authors can use ''::part()'' without fear of accidental over-styling. - + Exposing a Shadow Element: {#exposing} ============================================================= Elements in a shadow tree may be exported for styling by stylesheets outside the tree @@ -146,12 +155,25 @@ and changes to the [=part name lists=] and [=forwarded part name lists=] of elem then let |innerRoot| be its shadow root. 3. [=calculate the part element map|Calculate=] |innerRoot|'s [=part element map=]. 4. For each |innerName|/|outerName| in |el|'s [=forwarded part name list=]: - 1. Let |innerParts| be |innerRoot|'s [=part element map=][|innerName|] - 2. [=list/Append=] the elements in |innerParts| - to |outerRoot|'s [=part element map=][|outerName|] + 1. If |innerName| is an ident: + 1. Let |innerParts| be |innerRoot|'s [=part element map=][|innerName|] + 2. [=list/Append=] the elements in |innerParts| + to |outerRoot|'s [=part element map=][|outerName|] + 2. If |innerName| is a pseudo-element name: + 1. [=list/Append=] |innerRoot|'s pseudo-element(s) with that name + to |outerRoot|'s [=part element map=][|outerName|]. + Naming a Shadow Element: the <{html-global/part}> attribute {#part-attr} ------------------------------------------------------------------------ @@ -179,6 +201,16 @@ not an id or tagname. </script> + Forwarding a Shadow Element: the <{html-global/exportparts}> attribute {#exportparts-attr} ---------------------------------------------------------------------------------- Any element in a shadow tree can have a exportparts attribute. @@ -200,6 +232,12 @@ Each part mapping is one of: Note: This is shorthand for ident : ident. + : ::ident : outerIdent + :: If ::ident is the name of a [=part-like pseudo-element=], + adds ::ident/outerIdent + to el's [=forward part name list=]. + Otherwise, does nothing. + : anything else :: Ignored for error-recovery / future compatibility. @@ -235,8 +273,40 @@ Note: It's okay to map a sub-part to several names. </script> +
+ For example, a [=part-like pseudo-element=] + can be used in the <{html-global/exportparts}> attribute, + to masquerade as a ''::part()'' + for the component it's in: + + + <template id=custom-element-template> + <p exportparts="::before : preceding-text, ::after : following-text"> + Main text. + </template> + + + An element using that template + can use a selector like ''x-component::part(preceding-text)'' + to target the ''p::before'' pseudo-element in its shadow, + so users of the component don't need to know + that the preceding text is implemented as a pseudo-element. +
+ + + + Selecting a Shadow Element: the ''::part()'' pseudo-element {#part} -============================================================================================ +=================================================================== The ::part() pseudo-element allows you to select elements that have been exposed via a <{html-global/part}> attribute. @@ -248,10 +318,6 @@ The syntax is: The ''::part()'' pseudo-element only matches anything when the originating element is a shadow host. -If the originating element's shadow root's part element map -[=map/contains=] all of the specified <>s, -''::part()'' matches the element or elements keyed to that <>. -Otherwise, it matches nothing.
For example, @@ -259,7 +325,7 @@ Otherwise, it matches nothing. that contains a "label" element that is exposed for styling (via part="label"), you can select it with - ''#the-button::part(label)''. + ''x-button::part(label)''.
@@ -277,15 +343,16 @@ Otherwise, it matches nothing. (or ''::part(active tab)'', as order doesn't matter).
-The ''::part()'' pseudo-element can take additional pseudo-classes after it, -such as ''x-button::part(label):hover'', -but never matches the structural pseudo-classes -or any other pseudo-classes that match based on tree information -rather than local element information. +The ''::part()'' pseudo-element is a [=part-like pseudo-element=]. +If the originating element's shadow root's part element map +[=map/contains=] the specified <>, +''::part()'' represents the elements keyed to that ident; +if multiple idents are provided and the [=part element map=] contains them all, +it represents the intersection of the elements keyed to each ident. +Otherwise, it matches nothing. -The ''::part()'' pseudo-element can also take additional pseudo-elements after it, -such as ''x-button::part(label)::before'', -but never match additional ''::part()''s. +''::part()'' pseudo-elements inherit according to their position +in the [=originating element's=] shadow tree.
For example, @@ -303,6 +370,18 @@ but never match additional ''::part()''s. ignoring any other labels.
+ + + Extensions to the {{Element}} Interface {#idl} ==============================================