@ax-design/typed-om 0.2.0 → 0.2.1
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/detector.d.ts +7 -0
- package/dist/detector.js +41 -4
- package/dist/register.js +15 -0
- package/package.json +1 -1
- package/src/detector.ts +50 -4
- package/src/register.ts +13 -0
package/dist/detector.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { PropertySpec } from './schema.js';
|
|
2
|
+
export interface KeywordMirror {
|
|
3
|
+
name: string;
|
|
4
|
+
property: string;
|
|
5
|
+
syntax: string;
|
|
6
|
+
initial: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function keywordMirrors(schema: PropertySpec[]): KeywordMirror[];
|
|
2
9
|
export interface DetectorTemplate {
|
|
3
10
|
css: string;
|
|
4
11
|
elementCount: number;
|
package/dist/detector.js
CHANGED
|
@@ -30,13 +30,45 @@ function chunk(items, size) {
|
|
|
30
30
|
function weight(i) {
|
|
31
31
|
return (1 + i * 0.0173).toFixed(4);
|
|
32
32
|
}
|
|
33
|
+
// Numeric specs that may hold a keyword (e.g. "<length> | auto") would poison the numeric
|
|
34
|
+
// calc() hash when the computed value is that keyword: calc(auto * 1.0000) is invalid and
|
|
35
|
+
// invalidates the whole transform-origin / perspective-origin declaration. Give each such spec
|
|
36
|
+
// a registered mirror with a pure numeric syntax: "auto" is rejected at computed-value time,
|
|
37
|
+
// so the mirror falls back to its zero initial and the hash stays legal. Value<->keyword jumps
|
|
38
|
+
// still move the hash (number -> 0), so changes keep firing.
|
|
39
|
+
export function keywordMirrors(schema) {
|
|
40
|
+
const out = [];
|
|
41
|
+
let i = 0;
|
|
42
|
+
for (const spec of schema) {
|
|
43
|
+
const t = spec.syntax.type;
|
|
44
|
+
if (t !== 'length' && t !== 'length-percentage' && t !== 'number')
|
|
45
|
+
continue;
|
|
46
|
+
if (!spec.syntax.keywords || !spec.syntax.keywords.length)
|
|
47
|
+
continue;
|
|
48
|
+
out.push({
|
|
49
|
+
name: `--${PREFIX}-kw-m${i++}`,
|
|
50
|
+
property: spec.name,
|
|
51
|
+
syntax: t === 'number' ? '<number>' : t === 'length' ? '<length>' : '<length-percentage>',
|
|
52
|
+
initial: t === 'number' ? '0' : '0px',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
33
57
|
// `registered` lists the properties registered by name. A registered non-inherited property
|
|
34
58
|
// does not reach the detector element inside the shadow root, so the host mirrors it into an
|
|
35
59
|
// unregistered (inherited) property. The slot resets the mirrors so author content does not
|
|
36
60
|
// inherit them.
|
|
37
61
|
export function buildDetector(schema, registered = new Set()) {
|
|
38
62
|
const mirrors = [];
|
|
63
|
+
const kwMirrors = [];
|
|
64
|
+
const kwName = {};
|
|
65
|
+
for (const m of keywordMirrors(schema)) {
|
|
66
|
+
kwName[m.property] = m.name;
|
|
67
|
+
kwMirrors.push(`${m.name}: var(${m.property});`);
|
|
68
|
+
}
|
|
39
69
|
const source = (spec) => {
|
|
70
|
+
if (kwName[spec.name])
|
|
71
|
+
return kwName[spec.name];
|
|
40
72
|
if (!registered.has(spec.name) || spec.inherits)
|
|
41
73
|
return spec.name;
|
|
42
74
|
const mirror = `--${PREFIX}-m${mirrors.length}`;
|
|
@@ -52,7 +84,11 @@ export function buildDetector(schema, registered = new Set()) {
|
|
|
52
84
|
const groups = chunk(numeric, Math.ceil(numeric.length / HASH_SLOTS));
|
|
53
85
|
const hashes = groups.map((group) => `calc(${group
|
|
54
86
|
.map((spec, i) => {
|
|
55
|
-
const
|
|
87
|
+
const src = source(spec);
|
|
88
|
+
// The registered mirror always resolves to a number (keyword -> zero), so a
|
|
89
|
+
// keyword-capable spec's fallback is zero rather than its (keyword) initial.
|
|
90
|
+
const fallback = kwName[spec.name] ? (spec.syntax.type === 'number' ? '0' : '0px') : spec.initial;
|
|
91
|
+
const v = `var(${src}, ${fallback})`;
|
|
56
92
|
return spec.syntax.type === 'number' ? `${v} * ${weight(i)}px` : `${v} * ${weight(i)}`;
|
|
57
93
|
})
|
|
58
94
|
.join(' + ')})`);
|
|
@@ -94,9 +130,10 @@ export function buildDetector(schema, registered = new Set()) {
|
|
|
94
130
|
const transition = e.transitions.length ? ` transition: ${e.transitions.join(', ')};` : '';
|
|
95
131
|
rules.push(`.${PREFIX}-d${i} { ${e.decls.join(' ')}${transition} }`);
|
|
96
132
|
});
|
|
97
|
-
if (mirrors.length) {
|
|
98
|
-
|
|
99
|
-
rules.push(
|
|
133
|
+
if (mirrors.length || kwMirrors.length) {
|
|
134
|
+
const all = [...mirrors, ...kwMirrors];
|
|
135
|
+
rules.push(`:host { ${all.join(' ')} }`);
|
|
136
|
+
rules.push(`slot { ${all.map((m) => `${m.slice(0, m.indexOf(':'))}: initial;`).join(' ')} }`);
|
|
100
137
|
}
|
|
101
138
|
rules.push(`.${PREFIX}-c { position: absolute; left: 0; top: 0; width: 1px; height: 1px; overflow: hidden; visibility: hidden; pointer-events: none; contain: strict; }`, `.${PREFIX}-c > div { position: absolute; left: 0; top: 0; width: 1px; height: 1px; }`);
|
|
102
139
|
return { css: rules.join('\n'), elementCount: elements.length };
|
package/dist/register.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { keywordMirrors } from './detector.js';
|
|
1
2
|
import { cssSyntax } from './schema.js';
|
|
2
3
|
export function canRegister() {
|
|
3
4
|
return typeof CSS !== 'undefined' && typeof CSS.registerProperty === 'function';
|
|
@@ -25,5 +26,19 @@ export function registerProperties(schema) {
|
|
|
25
26
|
throw error;
|
|
26
27
|
}
|
|
27
28
|
}
|
|
29
|
+
// Numeric specs that may hold a keyword get a registered mirror with a pure numeric syntax,
|
|
30
|
+
// so the keyword is rejected at computed-value time and the numeric hash stays legal. The
|
|
31
|
+
// mirror is internal (never read by the reader) and its definition is derived from the
|
|
32
|
+
// permanent schema contract, so a re-registration by another copy is the same definition.
|
|
33
|
+
for (const m of keywordMirrors(schema)) {
|
|
34
|
+
try {
|
|
35
|
+
css.registerProperty({ name: m.name, syntax: m.syntax, inherits: true, initialValue: m.initial });
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
// Already registered by an earlier copy with the identical definition.
|
|
39
|
+
if (!error || error.name !== 'InvalidModificationError')
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
28
43
|
return registered;
|
|
29
44
|
}
|
package/package.json
CHANGED
package/src/detector.ts
CHANGED
|
@@ -35,6 +35,40 @@ function weight(i: number): string {
|
|
|
35
35
|
return (1 + i * 0.0173).toFixed(4);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export interface KeywordMirror {
|
|
39
|
+
// Name of the registered mirror property, e.g. "--ax-typed-om-kw-m0".
|
|
40
|
+
name: string;
|
|
41
|
+
// The source custom property the mirror reflects.
|
|
42
|
+
property: string;
|
|
43
|
+
// Pure numeric syntax (no keywords) the mirror is registered with.
|
|
44
|
+
syntax: string;
|
|
45
|
+
// Zero initial value for that syntax.
|
|
46
|
+
initial: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Numeric specs that may hold a keyword (e.g. "<length> | auto") would poison the numeric
|
|
50
|
+
// calc() hash when the computed value is that keyword: calc(auto * 1.0000) is invalid and
|
|
51
|
+
// invalidates the whole transform-origin / perspective-origin declaration. Give each such spec
|
|
52
|
+
// a registered mirror with a pure numeric syntax: "auto" is rejected at computed-value time,
|
|
53
|
+
// so the mirror falls back to its zero initial and the hash stays legal. Value<->keyword jumps
|
|
54
|
+
// still move the hash (number -> 0), so changes keep firing.
|
|
55
|
+
export function keywordMirrors(schema: PropertySpec[]): KeywordMirror[] {
|
|
56
|
+
const out: KeywordMirror[] = [];
|
|
57
|
+
let i = 0;
|
|
58
|
+
for (const spec of schema) {
|
|
59
|
+
const t = spec.syntax.type;
|
|
60
|
+
if (t !== 'length' && t !== 'length-percentage' && t !== 'number') continue;
|
|
61
|
+
if (!spec.syntax.keywords || !spec.syntax.keywords.length) continue;
|
|
62
|
+
out.push({
|
|
63
|
+
name: `--${PREFIX}-kw-m${i++}`,
|
|
64
|
+
property: spec.name,
|
|
65
|
+
syntax: t === 'number' ? '<number>' : t === 'length' ? '<length>' : '<length-percentage>',
|
|
66
|
+
initial: t === 'number' ? '0' : '0px',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
|
|
38
72
|
export interface DetectorTemplate {
|
|
39
73
|
css: string;
|
|
40
74
|
elementCount: number;
|
|
@@ -46,7 +80,14 @@ export interface DetectorTemplate {
|
|
|
46
80
|
// inherit them.
|
|
47
81
|
export function buildDetector(schema: PropertySpec[], registered: Set<string> = new Set()): DetectorTemplate {
|
|
48
82
|
const mirrors: string[] = [];
|
|
83
|
+
const kwMirrors: string[] = [];
|
|
84
|
+
const kwName: { [name: string]: string } = {};
|
|
85
|
+
for (const m of keywordMirrors(schema)) {
|
|
86
|
+
kwName[m.property] = m.name;
|
|
87
|
+
kwMirrors.push(`${m.name}: var(${m.property});`);
|
|
88
|
+
}
|
|
49
89
|
const source = (spec: PropertySpec) => {
|
|
90
|
+
if (kwName[spec.name]) return kwName[spec.name];
|
|
50
91
|
if (!registered.has(spec.name) || spec.inherits) return spec.name;
|
|
51
92
|
const mirror = `--${PREFIX}-m${mirrors.length}`;
|
|
52
93
|
mirrors.push(`${mirror}: var(${spec.name});`);
|
|
@@ -64,7 +105,11 @@ export function buildDetector(schema: PropertySpec[], registered: Set<string> =
|
|
|
64
105
|
const hashes = groups.map((group) =>
|
|
65
106
|
`calc(${group
|
|
66
107
|
.map((spec, i) => {
|
|
67
|
-
const
|
|
108
|
+
const src = source(spec);
|
|
109
|
+
// The registered mirror always resolves to a number (keyword -> zero), so a
|
|
110
|
+
// keyword-capable spec's fallback is zero rather than its (keyword) initial.
|
|
111
|
+
const fallback = kwName[spec.name] ? (spec.syntax.type === 'number' ? '0' : '0px') : spec.initial;
|
|
112
|
+
const v = `var(${src}, ${fallback})`;
|
|
68
113
|
return spec.syntax.type === 'number' ? `${v} * ${weight(i)}px` : `${v} * ${weight(i)}`;
|
|
69
114
|
})
|
|
70
115
|
.join(' + ')})`
|
|
@@ -106,9 +151,10 @@ export function buildDetector(schema: PropertySpec[], registered: Set<string> =
|
|
|
106
151
|
const transition = e.transitions.length ? ` transition: ${e.transitions.join(', ')};` : '';
|
|
107
152
|
rules.push(`.${PREFIX}-d${i} { ${e.decls.join(' ')}${transition} }`);
|
|
108
153
|
});
|
|
109
|
-
if (mirrors.length) {
|
|
110
|
-
|
|
111
|
-
rules.push(
|
|
154
|
+
if (mirrors.length || kwMirrors.length) {
|
|
155
|
+
const all = [...mirrors, ...kwMirrors];
|
|
156
|
+
rules.push(`:host { ${all.join(' ')} }`);
|
|
157
|
+
rules.push(`slot { ${all.map((m) => `${m.slice(0, m.indexOf(':'))}: initial;`).join(' ')} }`);
|
|
112
158
|
}
|
|
113
159
|
rules.push(
|
|
114
160
|
`.${PREFIX}-c { position: absolute; left: 0; top: 0; width: 1px; height: 1px; overflow: hidden; visibility: hidden; pointer-events: none; contain: strict; }`,
|
package/src/register.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { keywordMirrors } from './detector.js';
|
|
1
2
|
import { cssSyntax } from './schema.js';
|
|
2
3
|
import type { PropertySpec } from './schema.js';
|
|
3
4
|
|
|
@@ -32,5 +33,17 @@ export function registerProperties(schema: PropertySpec[]): Set<string> {
|
|
|
32
33
|
else throw error;
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
// Numeric specs that may hold a keyword get a registered mirror with a pure numeric syntax,
|
|
37
|
+
// so the keyword is rejected at computed-value time and the numeric hash stays legal. The
|
|
38
|
+
// mirror is internal (never read by the reader) and its definition is derived from the
|
|
39
|
+
// permanent schema contract, so a re-registration by another copy is the same definition.
|
|
40
|
+
for (const m of keywordMirrors(schema)) {
|
|
41
|
+
try {
|
|
42
|
+
css.registerProperty!({ name: m.name, syntax: m.syntax, inherits: true, initialValue: m.initial });
|
|
43
|
+
} catch (error) {
|
|
44
|
+
// Already registered by an earlier copy with the identical definition.
|
|
45
|
+
if (!error || (error as Error).name !== 'InvalidModificationError') throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
35
48
|
return registered;
|
|
36
49
|
}
|