Skip to content

Commit 291eb20

Browse files
committed
Rewrite (un)registerProperty into proper algorithmic style. Define computationally idempotent.
1 parent 5a82886 commit 291eb20

File tree

1 file changed

+167
-75
lines changed

1 file changed

+167
-75
lines changed

css-properties-values-api/Overview.bs

+167-75
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Repository: w3c/css-houdini-drafts
3737
<pre class='link-defaults'>
3838
spec:css-transforms-1; type:type; text:<transform-function>
3939
spec:cssom-1; type:interface; text:CSS
40+
spec:css-color-4; type:property; text:color
4041
</pre>
4142

4243
Introduction {#intro}
@@ -74,6 +75,9 @@ partial interface CSS {
7475
};
7576
</pre>
7677

78+
Additional, the {{Window}} object gains a new <dfn attribute for=Window>\[[registeredPropertySet]]</dfn> private slot,
79+
which is a set of records that describe registered custom properties.
80+
7781
The {{PropertyDescriptor}} dictionary {#the-propertydescriptor-dictionary}
7882
--------------------------------------------------------------------------
7983

@@ -93,97 +97,185 @@ following members:
9397
: <dfn dict-member for=PropertyDescriptor>initialValue</dfn>
9498
:: The initial value of this custom property.
9599

96-
The {{registerProperty()}} function {#the-registerproperty-function}
97-
--------------------------------------------------------------------
100+
The {{registerProperty()}} and {{unregisterProperty()}} functions {#the-registerproperty-function}
101+
--------------------------------------------------------------------------------------------------
98102

99103
The <dfn method for=CSS>registerProperty(PropertyDescriptor descriptor)</dfn> method
100-
registers a custom property according the to configuration options provided in
104+
registers a custom property according to the configuration options provided in
101105
<code>descriptor</code>.
106+
When it is called,
107+
it executes the <a>register a custom property</a> algorithm,
108+
passing the options in its <code>descriptor</code> argument
109+
as arguments of the same names.
110+
111+
<div algorithm>
112+
To <dfn>register a custom property</dfn>
113+
with |name| being a string,
114+
and optionally
115+
|syntax| being a string,
116+
|inherits| being a boolean,
117+
and |initialValue| being a string,
118+
execute these steps:
119+
120+
1. Attempt to parse |name|
121+
as a <<custom-property-name>>.
122+
If this fails,
123+
<a>throw</a> a {{SyntaxError}}
124+
and exit this algorithm.
125+
126+
Otherwise,
127+
let |parsed name| be the parsed value.
128+
129+
If the window's {{[[registeredPropertySet]]}} slot
130+
already contains an entry with |parsed name| as its property name
131+
(compared codepoint-wise),
132+
<a>throw</a> an {{InvalidModificationError}}
133+
and exit this algorithm.
134+
135+
2. If |syntax| is not present,
136+
or is equal to <code>"*"</code> (U+002A ASTERISK),
137+
let |parsed syntax| be undefined,
138+
and skip to the next step of this algorithm.
139+
140+
Otherwise, attempt to parse |syntax|
141+
according to the rules in [[#supported-syntax-strings]].
142+
If it does not parse successfully,
143+
<a>throw</a> a {{SyntaxError}}.
144+
Otherwise,
145+
let |parsed syntax| be the parsed syntax.
146+
147+
Note: For example, a valid syntax string is something like <code>"&lt;length>"</code>,
148+
or <code>"&lt;number>+"</code>;
149+
the allowed syntax is a subset of [[css-values-3#value-defs]].
150+
Future levels of this specification are expected to expand the complexity of allowed syntax strings,
151+
allowing custom properties that more closely resemble the full breadth of what CSS properties allow.
152+
153+
3. If |parsed syntax| is undefined,
154+
and |initialValue| is not present,
155+
let |parsed initial value| be empty.
156+
This must be treated identically to the "default" initial value of custom properties,
157+
as defined in [[!css-variables]].
158+
Skip to the next step of this algorithm.
159+
160+
Otherwise,
161+
if |parsed syntax| is undefined,
162+
parse |initialValue| as a <<declaration-value>>.
163+
If this fails,
164+
<a>throw</a> a {{SyntaxError}}
165+
and exit this algorithm.
166+
Otherwise,
167+
let |parsed initial value| be the parsed result.
168+
Skip to the next step of this algorithm.
169+
170+
Otherwise, if |initialValue| is not present,
171+
<a>throw</a> a {{SyntaxError}}
172+
and exit this algorithm.
173+
174+
Otherwise,
175+
parse {{PropertyDescriptor/initialValue}}
176+
according to |parsed syntax|.
177+
If this fails,
178+
<a>throw</a> a {{SyntaxError}}
179+
and exit this algorithm.
180+
181+
Otherwise, let |parsed initial value| be the parsed result.
182+
If |parsed initial value| is not <a>computationally idempotent</a>,
183+
<a>throw</a> a {{SyntaxError}}
184+
and exit this algorithm.
185+
186+
4. If |inherits| is present,
187+
set |inherit flag| to its value.
188+
Otherwise, set |inherit flag| to false.
189+
190+
5. Let |registered property| be a record
191+
with a property name of |parsed name|,
192+
a syntax of |parsed syntax|,
193+
an initial value of |parsed initial value|,
194+
and an inherit flag of |inherit flag|.
195+
Add |registered property|
196+
to the window's {{[[registeredPropertySet]]}}.
197+
</div>
102198

103-
Attempting to register properties with a {{PropertyDescriptor/name}} that doesn't
104-
correspond to the <<custom-property-name>> production must cause {{registerProperty()}}
105-
to throw a {{SyntaxError}}.
106-
107-
The list of types supported in the {{PropertyDescriptor/syntax}} member are listed
108-
in <a section href="#supported-syntax-strings"></a>. Currently, only simple
109-
type references are supported. Attempting to register properties with a
110-
{{PropertyDescriptor/syntax}} that is not supported must cause {{registerProperty()}}
111-
to throw a {{SyntaxError}}.
112-
113-
Note: for example, the syntax string could be "&lt;length&gt;" or "&lt;number&gt;".
114-
115-
Note: in future levels we anticipate supporting more sophisticated parse strings, e.g.
116-
"&lt;length&gt; || &lt;number&gt;"
117-
118-
Attempting to call {{registerProperty()}} with an {{PropertyDescriptor/initialValue}} that is
119-
not parseable using the provided {{PropertyDescriptor/syntax}} must cause it to
120-
throw a {{SyntaxError}}. If no {{PropertyDescriptor/initialValue}} is provided and the
121-
{{PropertyDescriptor/syntax}} is '*', then a special initial value is used. This initial
122-
value must be considered parseable by {{registerProperty()}} but invalid at computed
123-
value time. Initial values that are not computationally idempotent must also cause
124-
{{registerProperty()}} to throw a {{SyntaxError}}.
199+
A property value is <dfn export>computationally idempotent</dfn>
200+
if it can be converted into a computed value
201+
using only the value of the property on the element,
202+
and "global" information that cannot be changed by CSS.
125203

126204
<div class='example'>
127-
For example, "3cm" is a computationally idempotent length, and hence valid as an initial value.
128-
However, "3em" is not (depending on the environment, 3em could compute to
129-
multiple different values). Additionally, "var(--foo)" is not computationally idempotent.
205+
For example, ''5px'' is <a>computationally idempotent</a>,
206+
as converting it into a computed value doesn't change it at all.
207+
Similarly, ''1in'' is <a>computationally idempotent</a>,
208+
as converting it into a computed value
209+
relies only on the "global knowledge" that ''1in'' is ''96px'',
210+
which can't be altered or adjusted by anything in CSS.
211+
212+
On the other hand, ''3em'' is not <a>computationally idempotent</a>,
213+
because it relies on the value of 'font-size' on the element
214+
(or the element's parent).
215+
Neither is a value with a ''var()'' function,
216+
because it relies on the value of a <a>custom property</a>.
130217
</div>
131218

132-
Issue(282): define computational idempotency.
133-
134-
Issue(121): Is computational idempotency the right thing to do here? We could also just
135-
resolve any relative values once (against all the other initial values) and use
136-
that. OR! We could allow specified values and just fix our engines...
137-
138-
When a custom property is registered with a given type, the process via which specified
139-
values for that property are turned into computed values is defined
140-
fully by the type selected, as described in
141-
<a section href="#calculation-of-computed-values"></a>.
142-
143-
If {{registerProperty()}} is called with a descriptor name that matches an already registered property,
144-
then an {{InvalidModificationError}} is thrown and the re-registration fails.
219+
When a custom property is registered with a given type,
220+
the process via which specified values for that property are turned into computed values
221+
is defined fully by the type selected,
222+
as described in [[#calculation-of-computed-values]].
145223

146224
Properties can be unregistered using
147225
<dfn method for=CSS>unregisterProperty(DOMString name)</dfn>.
148-
If this function is called with a name that doesn't match an existing property
149-
then a {{NotFoundError}} is thrown.
226+
When it is called,
227+
it executes the <a>unregister a custom property</a> algorithm,
228+
with a <code>name</code> set to its sole argument.
150229

151-
Successful calls to both {{registerProperty()}} and {{unregisterProperty()}}
152-
change the set of registered properties. When the set of registered properties
153-
changes, previously syntactically invalid property values can become valid and vice versa.
154-
This can change the set of <a>declared values</a> which requires the <a>cascade</a> to
155-
be recomputed.
230+
<div algorithm>
231+
To <dfn>unregister a custom property</dfn> with the name |name|:
156232

157-
<div class='example'>
158-
By default, all custom property declarations that can be parsed as a sequence of tokens
159-
are valid. Hence, the result of this stylesheet:
160-
161-
<pre class='lang-css'>
162-
.thing {
163-
--my-color: green;
164-
--my-color: url("not-a-color");
165-
color: var(--my-color);
166-
}
167-
</pre>
168-
169-
is to set the color property of elements of class "thing" to "inherit".
170-
The second --my-color declaration overrides the first at parse time (both are valid),
171-
and the var reference in the color property is found to be invalid at computation time
172-
(because <code>url("not-a-color")</code> is not a color). At computation time the only
173-
available fallback is the default value, which in the case of color is "inherit".
233+
1. If the window's {{[[registeredPropertySet]]}}
234+
contains a record with a property name matching |name|
235+
(compared codepoint-wise),
236+
remove the record from the set.
174237

175-
if we call:
176-
177-
<pre class='lang-javascript'>
178-
registerProperty({
179-
name: "--my-color",
180-
syntax: "&lt;color>"
181-
});
182-
</pre>
238+
Otherwise,
239+
<a>throw</a> a {{NotFoundError}}.
240+
</div>
183241

184-
then the second --my-color declaration becomes syntactically invalid, which means that
185-
the cascade uses the first declaration. The color therefore switches to green.
242+
When the window's {{[[registeredPropertySet]]}} changes,
243+
previously syntactically invalid property values can become valid and vice versa.
244+
This can change the set of <a>declared values</a> which requires the <a>cascade</a> to be recomputed.
186245

246+
<div class='example'>
247+
By default, all custom property declarations that can be parsed as a sequence of tokens
248+
are valid. Hence, the result of this stylesheet:
249+
250+
<pre class='lang-css'>
251+
.thing {
252+
--my-color: green;
253+
--my-color: url("not-a-color");
254+
color: var(--my-color);
255+
}
256+
</pre>
257+
258+
is to set the 'color' property of elements of class "thing" to ''inherit''.
259+
The second '--my-color' declaration overrides the first at parse time (both are valid),
260+
and the ''var()'' reference in the 'color' property is found to be <a spec=css-variables>invalid at computed-value time</a>
261+
(because ''url("not-a-color")'' is not a color).
262+
At computed-value time the only available fallback is the default value,
263+
which in the case of color is ''inherit''.
264+
265+
if we call:
266+
267+
<pre class='lang-javascript'>
268+
CSS.registerProperty({
269+
name: "--my-color",
270+
syntax: "&lt;color>",
271+
initialValue: "black"
272+
});
273+
</pre>
274+
275+
then the second '--my-color' declaration becomes syntactically invalid at parse time,
276+
and is ignored.
277+
The first '--my-color' is the only valid declaration left for the property,
278+
so 'color' is set to the value ''green''.
187279
</div>
188280

189281
Supported syntax strings {#supported-syntax-strings}

0 commit comments

Comments
 (0)