@animus-ui/properties 0.1.19 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +295 -1
- package/dist/registration-values.d.ts +41 -0
- package/dist/registration-values.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { SHORTHAND_PROPERTIES } from './shorthands';
|
|
2
2
|
export { isUnitlessProperty, UNITLESS_PROPERTIES } from './unitless';
|
|
3
|
+
export { dependsOnContext, foldInitialValue, registeredInitialValue, substitutesValue, } from './registration-values.js';
|
|
4
|
+
export type { FoldedInitialValue } from './registration-values.js';
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -83,4 +83,298 @@ function isUnitlessProperty(property) {
|
|
|
83
83
|
return UNITLESS_PROPERTY_SPELLINGS.has(property);
|
|
84
84
|
}
|
|
85
85
|
//#endregion
|
|
86
|
-
|
|
86
|
+
//#region src/registration-values.ts
|
|
87
|
+
const NUMBER = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?/i;
|
|
88
|
+
const IDENT = /^(?:--|-?[a-zA-Z_])[\w-]*/;
|
|
89
|
+
/** The component values of `text`; `undefined` when it does not parse. */
|
|
90
|
+
function parse(text) {
|
|
91
|
+
let at = 0;
|
|
92
|
+
function values(nested) {
|
|
93
|
+
const out = [];
|
|
94
|
+
while (at < text.length) {
|
|
95
|
+
const char = text[at];
|
|
96
|
+
if (/\s/.test(char)) {
|
|
97
|
+
at += 1;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (char === ")") {
|
|
101
|
+
at += 1;
|
|
102
|
+
return nested ? out : void 0;
|
|
103
|
+
}
|
|
104
|
+
if (char === "\"" || char === "'") {
|
|
105
|
+
const end = stringEnd(text, at);
|
|
106
|
+
if (end === void 0) return void 0;
|
|
107
|
+
out.push({
|
|
108
|
+
kind: "token",
|
|
109
|
+
text: text.slice(at, end)
|
|
110
|
+
});
|
|
111
|
+
at = end;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const rest = text.slice(at);
|
|
115
|
+
const ident = IDENT.exec(rest)?.[0];
|
|
116
|
+
if (char === "(" || ident && rest[ident.length] === "(") {
|
|
117
|
+
const name = (ident ?? "").toLowerCase();
|
|
118
|
+
at += (ident?.length ?? 0) + 1;
|
|
119
|
+
if (name === "url") {
|
|
120
|
+
const end = text.indexOf(")", at);
|
|
121
|
+
if (end < 0) return void 0;
|
|
122
|
+
out.push({
|
|
123
|
+
kind: "token",
|
|
124
|
+
text: "url()"
|
|
125
|
+
});
|
|
126
|
+
at = end + 1;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const args = values(true);
|
|
130
|
+
if (args === void 0) return void 0;
|
|
131
|
+
out.push({
|
|
132
|
+
kind: "function",
|
|
133
|
+
name,
|
|
134
|
+
args
|
|
135
|
+
});
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const number = NUMBER.exec(rest)?.[0];
|
|
139
|
+
if (number !== void 0) {
|
|
140
|
+
const unit = /^(?:%|[a-zA-Z]+)/.exec(rest.slice(number.length))?.[0];
|
|
141
|
+
out.push({
|
|
142
|
+
kind: "numeric",
|
|
143
|
+
value: Number(number),
|
|
144
|
+
unit: (unit ?? "").toLowerCase()
|
|
145
|
+
});
|
|
146
|
+
at += number.length + (unit?.length ?? 0);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
out.push({
|
|
150
|
+
kind: "token",
|
|
151
|
+
text: ident ?? char
|
|
152
|
+
});
|
|
153
|
+
at += ident?.length ?? 1;
|
|
154
|
+
}
|
|
155
|
+
return nested ? void 0 : out;
|
|
156
|
+
}
|
|
157
|
+
return values(false);
|
|
158
|
+
}
|
|
159
|
+
function stringEnd(text, start) {
|
|
160
|
+
for (let at = start + 1; at < text.length; at += 1) if (text[at] === "\\") at += 1;
|
|
161
|
+
else if (text[at] === text[start]) return at + 1;
|
|
162
|
+
}
|
|
163
|
+
function some(values, test) {
|
|
164
|
+
return values.some((value) => test(value) || value.kind === "function" && some(value.args, test));
|
|
165
|
+
}
|
|
166
|
+
const SUBSTITUTIONS = /* @__PURE__ */ new Set([
|
|
167
|
+
"var",
|
|
168
|
+
"env",
|
|
169
|
+
"attr"
|
|
170
|
+
]);
|
|
171
|
+
/** Whether `value` substitutes another value (`var()`, `env()`, `attr()`),
|
|
172
|
+
* which no registration's initial value may. Unparseable text is read as
|
|
173
|
+
* substituting when it names one of them. */
|
|
174
|
+
function substitutesValue(value) {
|
|
175
|
+
const values = parse(value);
|
|
176
|
+
if (values === void 0) return /\b(?:var|env|attr)\(/i.test(value);
|
|
177
|
+
return some(values, (component) => component.kind === "function" && SUBSTITUTIONS.has(component.name));
|
|
178
|
+
}
|
|
179
|
+
const CONTEXT_UNITS = /* @__PURE__ */ new Set([
|
|
180
|
+
"em",
|
|
181
|
+
"rem",
|
|
182
|
+
"ex",
|
|
183
|
+
"rex",
|
|
184
|
+
"cap",
|
|
185
|
+
"rcap",
|
|
186
|
+
"ch",
|
|
187
|
+
"rch",
|
|
188
|
+
"ic",
|
|
189
|
+
"ric",
|
|
190
|
+
"lh",
|
|
191
|
+
"rlh",
|
|
192
|
+
"cqw",
|
|
193
|
+
"cqh",
|
|
194
|
+
"cqi",
|
|
195
|
+
"cqb",
|
|
196
|
+
"cqmin",
|
|
197
|
+
"cqmax"
|
|
198
|
+
]);
|
|
199
|
+
/** Whether `value` uses a font- or container-relative unit, inside math
|
|
200
|
+
* functions too, which makes a typed initial value depend on context. */
|
|
201
|
+
function dependsOnContext(value) {
|
|
202
|
+
const values = parse(value);
|
|
203
|
+
if (values === void 0) return false;
|
|
204
|
+
return some(values, (component) => component.kind === "numeric" && CONTEXT_UNITS.has(component.unit));
|
|
205
|
+
}
|
|
206
|
+
/** Absolute units, by the canonical unit each converts to. */
|
|
207
|
+
const ABSOLUTE_UNITS = /* @__PURE__ */ new Map([
|
|
208
|
+
["px", ["length", 1]],
|
|
209
|
+
["cm", ["length", 96 / 2.54]],
|
|
210
|
+
["mm", ["length", 96 / 25.4]],
|
|
211
|
+
["q", ["length", 96 / 101.6]],
|
|
212
|
+
["in", ["length", 96]],
|
|
213
|
+
["pt", ["length", 4 / 3]],
|
|
214
|
+
["pc", ["length", 16]],
|
|
215
|
+
["deg", ["angle", 1]],
|
|
216
|
+
["grad", ["angle", .9]],
|
|
217
|
+
["rad", ["angle", 180 / Math.PI]],
|
|
218
|
+
["turn", ["angle", 360]],
|
|
219
|
+
["s", ["time", 1]],
|
|
220
|
+
["ms", ["time", .001]],
|
|
221
|
+
["dppx", ["resolution", 1]],
|
|
222
|
+
["x", ["resolution", 1]],
|
|
223
|
+
["dpi", ["resolution", 1 / 96]],
|
|
224
|
+
["dpcm", ["resolution", 2.54 / 96]]
|
|
225
|
+
]);
|
|
226
|
+
const CANONICAL_UNITS = {
|
|
227
|
+
number: "",
|
|
228
|
+
length: "px",
|
|
229
|
+
angle: "deg",
|
|
230
|
+
time: "s",
|
|
231
|
+
resolution: "dppx"
|
|
232
|
+
};
|
|
233
|
+
const MATH_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
234
|
+
"calc",
|
|
235
|
+
"min",
|
|
236
|
+
"max",
|
|
237
|
+
"clamp"
|
|
238
|
+
]);
|
|
239
|
+
/** Evaluates a math function's arguments: `+ - * /` over numbers and
|
|
240
|
+
* absolute dimensions, nested `calc()`, `min()`, `max()` and `clamp()`. */
|
|
241
|
+
function evaluate(values) {
|
|
242
|
+
let at = 0;
|
|
243
|
+
const operator = (...ops) => {
|
|
244
|
+
const value = values[at];
|
|
245
|
+
if (value?.kind === "token" && ops.includes(value.text)) {
|
|
246
|
+
at += 1;
|
|
247
|
+
return value.text;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
function factor() {
|
|
251
|
+
const value = values[at];
|
|
252
|
+
at += 1;
|
|
253
|
+
if (value === void 0) return void 0;
|
|
254
|
+
if (value.kind === "numeric") {
|
|
255
|
+
if (value.unit === "") return {
|
|
256
|
+
type: "number",
|
|
257
|
+
value: value.value
|
|
258
|
+
};
|
|
259
|
+
const unit = ABSOLUTE_UNITS.get(value.unit);
|
|
260
|
+
return unit && {
|
|
261
|
+
type: unit[0],
|
|
262
|
+
value: value.value * unit[1]
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (value.kind === "function") return mathFunction(value);
|
|
266
|
+
}
|
|
267
|
+
function product() {
|
|
268
|
+
let left = factor();
|
|
269
|
+
for (let op = operator("*", "/"); op && left; op = operator("*", "/")) {
|
|
270
|
+
const right = factor();
|
|
271
|
+
if (right === void 0) return void 0;
|
|
272
|
+
if (op === "*") {
|
|
273
|
+
if (left.type !== "number" && right.type !== "number") return void 0;
|
|
274
|
+
left = {
|
|
275
|
+
type: left.type === "number" ? right.type : left.type,
|
|
276
|
+
value: left.value * right.value
|
|
277
|
+
};
|
|
278
|
+
} else if (right.type === "number") left = {
|
|
279
|
+
type: left.type,
|
|
280
|
+
value: left.value / right.value
|
|
281
|
+
};
|
|
282
|
+
else if (right.type === left.type) left = {
|
|
283
|
+
type: "number",
|
|
284
|
+
value: left.value / right.value
|
|
285
|
+
};
|
|
286
|
+
else return;
|
|
287
|
+
}
|
|
288
|
+
return left;
|
|
289
|
+
}
|
|
290
|
+
function sum() {
|
|
291
|
+
let left = product();
|
|
292
|
+
for (let op = operator("+", "-"); op && left; op = operator("+", "-")) {
|
|
293
|
+
const right = product();
|
|
294
|
+
if (right === void 0 || right.type !== left.type) return void 0;
|
|
295
|
+
left = {
|
|
296
|
+
type: left.type,
|
|
297
|
+
value: op === "+" ? left.value + right.value : left.value - right.value
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
return left;
|
|
301
|
+
}
|
|
302
|
+
const result = sum();
|
|
303
|
+
return at === values.length ? result : void 0;
|
|
304
|
+
}
|
|
305
|
+
function mathFunction(value) {
|
|
306
|
+
if (value.name === "calc" || value.name === "") return evaluate(value.args);
|
|
307
|
+
if (!MATH_FUNCTIONS.has(value.name)) return void 0;
|
|
308
|
+
const args = [];
|
|
309
|
+
let start = 0;
|
|
310
|
+
for (let at = 0; at <= value.args.length; at += 1) {
|
|
311
|
+
const arg = value.args[at];
|
|
312
|
+
if (at === value.args.length || arg?.kind === "token" && arg.text === ",") {
|
|
313
|
+
const computed = evaluate(value.args.slice(start, at));
|
|
314
|
+
if (computed === void 0) return void 0;
|
|
315
|
+
args.push(computed);
|
|
316
|
+
start = at + 1;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const type = args[0]?.type;
|
|
320
|
+
if (type === void 0 || args.some((arg) => arg.type !== type)) return;
|
|
321
|
+
const values = args.map((arg) => arg.value);
|
|
322
|
+
if (value.name === "min") return {
|
|
323
|
+
type,
|
|
324
|
+
value: Math.min(...values)
|
|
325
|
+
};
|
|
326
|
+
if (value.name === "max") return {
|
|
327
|
+
type,
|
|
328
|
+
value: Math.max(...values)
|
|
329
|
+
};
|
|
330
|
+
if (values.length !== 3) return void 0;
|
|
331
|
+
const [low, middle, high] = values;
|
|
332
|
+
return {
|
|
333
|
+
type,
|
|
334
|
+
value: Math.max(low, Math.min(middle, high))
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
/** The data type each folded value is written as, by syntax type. */
|
|
338
|
+
const ACCEPTING_SYNTAX_TYPES = /* @__PURE__ */ new Map([
|
|
339
|
+
["number", "number"],
|
|
340
|
+
["integer", "number"],
|
|
341
|
+
["length", "length"],
|
|
342
|
+
["length-percentage", "length"],
|
|
343
|
+
["angle", "angle"],
|
|
344
|
+
["time", "time"],
|
|
345
|
+
["resolution", "resolution"]
|
|
346
|
+
]);
|
|
347
|
+
/**
|
|
348
|
+
* The computed value of an initial value that is one math function (`calc()`,
|
|
349
|
+
* `min()`, `max()`, `clamp()`) over numbers and absolute units, such as
|
|
350
|
+
* `calc(1px / 1px)` → `1`. The browser computes the same value, and CSS
|
|
351
|
+
* tooling that cannot parse the function in that position reads the result.
|
|
352
|
+
* `undefined` for anything else, and for the universal syntax, whose initial
|
|
353
|
+
* value is kept as written.
|
|
354
|
+
*/
|
|
355
|
+
function foldInitialValue(syntax, initialValue) {
|
|
356
|
+
if (syntax.trim() === "*") return void 0;
|
|
357
|
+
const values = parse(initialValue);
|
|
358
|
+
const only = values?.length === 1 ? values[0] : void 0;
|
|
359
|
+
if (only?.kind !== "function" || !MATH_FUNCTIONS.has(only.name)) return;
|
|
360
|
+
const computed = mathFunction(only);
|
|
361
|
+
if (computed === void 0) return void 0;
|
|
362
|
+
const accepted = syntax.split("|").some((component) => {
|
|
363
|
+
const type = /<([a-z-]+)>/.exec(component)?.[1];
|
|
364
|
+
if (type === void 0 || ACCEPTING_SYNTAX_TYPES.get(type) !== computed.type) return false;
|
|
365
|
+
return type !== "integer" || Number.isInteger(computed.value);
|
|
366
|
+
});
|
|
367
|
+
return {
|
|
368
|
+
text: `${Number(computed.value.toPrecision(12))}${CANONICAL_UNITS[computed.type]}`,
|
|
369
|
+
accepted,
|
|
370
|
+
type: computed.type
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/** An initial value folded when its syntax accepts the computed value, and
|
|
374
|
+
* unchanged otherwise: what a registration records and emits. */
|
|
375
|
+
function registeredInitialValue(syntax, initialValue) {
|
|
376
|
+
const folded = foldInitialValue(syntax, initialValue);
|
|
377
|
+
return folded?.accepted ? folded.text : initialValue;
|
|
378
|
+
}
|
|
379
|
+
//#endregion
|
|
380
|
+
export { SHORTHAND_PROPERTIES, UNITLESS_PROPERTIES, dependsOnContext, foldInitialValue, isUnitlessProperty, registeredInitialValue, substitutesValue };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a custom-property registration's initial value as CSS component
|
|
3
|
+
* values: what it substitutes, which units make it depend on context, and
|
|
4
|
+
* what an all-absolute math function computes to. Quoted text and `url()`
|
|
5
|
+
* stay text.
|
|
6
|
+
*/
|
|
7
|
+
/** Whether `value` substitutes another value (`var()`, `env()`, `attr()`),
|
|
8
|
+
* which no registration's initial value may. Unparseable text is read as
|
|
9
|
+
* substituting when it names one of them. */
|
|
10
|
+
export declare function substitutesValue(value: string): boolean;
|
|
11
|
+
/** Whether `value` uses a font- or container-relative unit, inside math
|
|
12
|
+
* functions too, which makes a typed initial value depend on context. */
|
|
13
|
+
export declare function dependsOnContext(value: string): boolean;
|
|
14
|
+
/** What an all-absolute math expression computes to. */
|
|
15
|
+
interface Computed {
|
|
16
|
+
type: 'number' | 'length' | 'angle' | 'time' | 'resolution';
|
|
17
|
+
value: number;
|
|
18
|
+
}
|
|
19
|
+
/** A math initial value folded to its computed value. */
|
|
20
|
+
export interface FoldedInitialValue {
|
|
21
|
+
/** The computed value as CSS text, such as `1`, `16px` or `90deg`. */
|
|
22
|
+
text: string;
|
|
23
|
+
/** Whether the registration's syntax accepts it. */
|
|
24
|
+
accepted: boolean;
|
|
25
|
+
/** The computed value's data type, for a diagnostic. */
|
|
26
|
+
type: Computed['type'];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The computed value of an initial value that is one math function (`calc()`,
|
|
30
|
+
* `min()`, `max()`, `clamp()`) over numbers and absolute units, such as
|
|
31
|
+
* `calc(1px / 1px)` → `1`. The browser computes the same value, and CSS
|
|
32
|
+
* tooling that cannot parse the function in that position reads the result.
|
|
33
|
+
* `undefined` for anything else, and for the universal syntax, whose initial
|
|
34
|
+
* value is kept as written.
|
|
35
|
+
*/
|
|
36
|
+
export declare function foldInitialValue(syntax: string, initialValue: string): FoldedInitialValue | undefined;
|
|
37
|
+
/** An initial value folded when its syntax accepts the computed value, and
|
|
38
|
+
* unchanged otherwise: what a registration records and emits. */
|
|
39
|
+
export declare function registeredInitialValue(syntax: string, initialValue: string): string;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=registration-values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration-values.d.ts","sourceRoot":"","sources":["../src/registration-values.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyFH;;8CAE8C;AAC9C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAQvD;AAuBD;0EAC0E;AAC1E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAQvD;AAED,wDAAwD;AACxD,UAAU,QAAQ;IAChB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,CAAC;IAC5D,KAAK,EAAE,MAAM,CAAC;CACf;AAwID,yDAAyD;AACzD,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,QAAQ,EAAE,OAAO,CAAC;IAClB,wDAAwD;IACxD,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,kBAAkB,GAAG,SAAS,CAyBhC;AAED;kEACkE;AAClE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,MAAM,CAGR"}
|