@ax-design/typed-om 0.1.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/README.md +7 -2
- package/dist/detector.d.ts +7 -0
- package/dist/detector.js +41 -4
- package/dist/reader.js +6 -0
- package/dist/register.js +15 -0
- package/dist/schema.d.ts +3 -0
- package/dist/schema.js +19 -10
- package/package.json +1 -1
- package/src/detector.ts +50 -4
- package/src/reader.ts +3 -0
- package/src/register.ts +13 -0
- package/src/schema.ts +20 -10
package/README.md
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
<h1 align="center">
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ax-design/typed-om/master/docs/logo-r.png">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/ax-design/typed-om/master/docs/logo.png" alt="Ax Typed OM">
|
|
5
|
+
</picture>
|
|
6
|
+
</h1>
|
|
2
7
|
|
|
3
8
|
<p align="center">
|
|
4
|
-
Typed reads and
|
|
9
|
+
Typed reads and monitors CSS custom properties for Axiom Design System.
|
|
5
10
|
</p>
|
|
6
11
|
|
|
7
12
|
<p align="center">
|
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/reader.js
CHANGED
|
@@ -41,10 +41,16 @@ export class StyleReader {
|
|
|
41
41
|
function parseFast(spec, text) {
|
|
42
42
|
switch (spec.syntax.type) {
|
|
43
43
|
case 'length':
|
|
44
|
+
if (spec.syntax.keywords && spec.syntax.keywords.indexOf(text) >= 0)
|
|
45
|
+
return text;
|
|
44
46
|
return parseLength(text);
|
|
45
47
|
case 'length-percentage':
|
|
48
|
+
if (spec.syntax.keywords && spec.syntax.keywords.indexOf(text) >= 0)
|
|
49
|
+
return text;
|
|
46
50
|
return parseLengthPercentage(text);
|
|
47
51
|
case 'number':
|
|
52
|
+
if (spec.syntax.keywords && spec.syntax.keywords.indexOf(text) >= 0)
|
|
53
|
+
return text;
|
|
48
54
|
return parseNumber(text);
|
|
49
55
|
case 'color':
|
|
50
56
|
if (spec.syntax.keywords && spec.syntax.keywords.indexOf(text) >= 0)
|
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/dist/schema.d.ts
CHANGED
package/dist/schema.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
const RESERVED = ['initial', 'inherit', 'unset', 'revert', 'revert-layer', 'default'];
|
|
2
|
+
function checkKeywords(name, keywords) {
|
|
3
|
+
for (const value of keywords) {
|
|
4
|
+
if (RESERVED.indexOf(value) >= 0)
|
|
5
|
+
throw new Error(`${name}: keyword "${value}" cannot be observed`);
|
|
6
|
+
if (!/^-?[_a-zA-Z][_a-zA-Z0-9-]*$/.test(value))
|
|
7
|
+
throw new Error(`${name}: "${value}" is not an identifier`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
2
10
|
export function validateSchema(schema) {
|
|
3
11
|
const seen = [];
|
|
4
12
|
for (const spec of schema) {
|
|
@@ -8,24 +16,25 @@ export function validateSchema(schema) {
|
|
|
8
16
|
seen.push(spec.name);
|
|
9
17
|
if (spec.name.indexOf('--') !== 0)
|
|
10
18
|
throw new Error(`${spec.name} is not a custom property name`);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
const syntax = spec.syntax;
|
|
20
|
+
if (syntax.type === 'keyword') {
|
|
21
|
+
checkKeywords(spec.name, syntax.values);
|
|
22
|
+
}
|
|
23
|
+
else if (syntax.type !== 'color' && syntax.keywords) {
|
|
24
|
+
// Numeric types may hold a keyword instead of a value ("<length> | auto");
|
|
25
|
+
// validate them the same way as the keyword type. Color keywords stay unvalidated.
|
|
26
|
+
checkKeywords(spec.name, syntax.keywords);
|
|
18
27
|
}
|
|
19
28
|
}
|
|
20
29
|
}
|
|
21
30
|
export function cssSyntax(syntax) {
|
|
22
31
|
switch (syntax.type) {
|
|
23
32
|
case 'length':
|
|
24
|
-
return '<length>';
|
|
33
|
+
return syntax.keywords && syntax.keywords.length ? `<length> | ${syntax.keywords.join(' | ')}` : '<length>';
|
|
25
34
|
case 'length-percentage':
|
|
26
|
-
return '<length-percentage>';
|
|
35
|
+
return syntax.keywords && syntax.keywords.length ? `<length-percentage> | ${syntax.keywords.join(' | ')}` : '<length-percentage>';
|
|
27
36
|
case 'number':
|
|
28
|
-
return '<number>';
|
|
37
|
+
return syntax.keywords && syntax.keywords.length ? `<number> | ${syntax.keywords.join(' | ')}` : '<number>';
|
|
29
38
|
case 'color':
|
|
30
39
|
return syntax.keywords && syntax.keywords.length ? `<color> | ${syntax.keywords.join(' | ')}` : '<color>';
|
|
31
40
|
case 'keyword':
|
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/reader.ts
CHANGED
|
@@ -54,10 +54,13 @@ export class StyleReader {
|
|
|
54
54
|
function parseFast(spec: PropertySpec, text: string): PropertyValue {
|
|
55
55
|
switch (spec.syntax.type) {
|
|
56
56
|
case 'length':
|
|
57
|
+
if (spec.syntax.keywords && spec.syntax.keywords.indexOf(text) >= 0) return text;
|
|
57
58
|
return parseLength(text);
|
|
58
59
|
case 'length-percentage':
|
|
60
|
+
if (spec.syntax.keywords && spec.syntax.keywords.indexOf(text) >= 0) return text;
|
|
59
61
|
return parseLengthPercentage(text);
|
|
60
62
|
case 'number':
|
|
63
|
+
if (spec.syntax.keywords && spec.syntax.keywords.indexOf(text) >= 0) return text;
|
|
61
64
|
return parseNumber(text);
|
|
62
65
|
case 'color':
|
|
63
66
|
if (spec.syntax.keywords && spec.syntax.keywords.indexOf(text) >= 0) return text;
|
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
|
}
|
package/src/schema.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Description of one custom property the caller wants to read and observe.
|
|
2
2
|
export type PropertySyntax =
|
|
3
|
-
| { type: 'length' }
|
|
4
|
-
| { type: 'length-percentage' }
|
|
5
|
-
| { type: 'number' }
|
|
3
|
+
| { type: 'length'; keywords?: string[] }
|
|
4
|
+
| { type: 'length-percentage'; keywords?: string[] }
|
|
5
|
+
| { type: 'number'; keywords?: string[] }
|
|
6
6
|
// `keywords`: extra identifiers the property may hold instead of a color (returned as strings).
|
|
7
7
|
| { type: 'color'; keywords?: string[] }
|
|
8
8
|
// Allowed values. CSS-wide keywords are rejected. `none` is allowed for existing APIs, but
|
|
@@ -37,6 +37,13 @@ export type PropertyValue = LengthPercentage | number | string | Rgba | null;
|
|
|
37
37
|
|
|
38
38
|
const RESERVED = ['initial', 'inherit', 'unset', 'revert', 'revert-layer', 'default'];
|
|
39
39
|
|
|
40
|
+
function checkKeywords(name: string, keywords: string[]): void {
|
|
41
|
+
for (const value of keywords) {
|
|
42
|
+
if (RESERVED.indexOf(value) >= 0) throw new Error(`${name}: keyword "${value}" cannot be observed`);
|
|
43
|
+
if (!/^-?[_a-zA-Z][_a-zA-Z0-9-]*$/.test(value)) throw new Error(`${name}: "${value}" is not an identifier`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
export function validateSchema(schema: PropertySpec[]): void {
|
|
41
48
|
const seen: string[] = [];
|
|
42
49
|
for (const spec of schema) {
|
|
@@ -45,10 +52,13 @@ export function validateSchema(schema: PropertySpec[]): void {
|
|
|
45
52
|
}
|
|
46
53
|
seen.push(spec.name);
|
|
47
54
|
if (spec.name.indexOf('--') !== 0) throw new Error(`${spec.name} is not a custom property name`);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
const syntax = spec.syntax;
|
|
56
|
+
if (syntax.type === 'keyword') {
|
|
57
|
+
checkKeywords(spec.name, syntax.values);
|
|
58
|
+
} else if (syntax.type !== 'color' && syntax.keywords) {
|
|
59
|
+
// Numeric types may hold a keyword instead of a value ("<length> | auto");
|
|
60
|
+
// validate them the same way as the keyword type. Color keywords stay unvalidated.
|
|
61
|
+
checkKeywords(spec.name, syntax.keywords);
|
|
52
62
|
}
|
|
53
63
|
}
|
|
54
64
|
}
|
|
@@ -56,11 +66,11 @@ export function validateSchema(schema: PropertySpec[]): void {
|
|
|
56
66
|
export function cssSyntax(syntax: PropertySyntax): string {
|
|
57
67
|
switch (syntax.type) {
|
|
58
68
|
case 'length':
|
|
59
|
-
return '<length>';
|
|
69
|
+
return syntax.keywords && syntax.keywords.length ? `<length> | ${syntax.keywords.join(' | ')}` : '<length>';
|
|
60
70
|
case 'length-percentage':
|
|
61
|
-
return '<length-percentage>';
|
|
71
|
+
return syntax.keywords && syntax.keywords.length ? `<length-percentage> | ${syntax.keywords.join(' | ')}` : '<length-percentage>';
|
|
62
72
|
case 'number':
|
|
63
|
-
return '<number>';
|
|
73
|
+
return syntax.keywords && syntax.keywords.length ? `<number> | ${syntax.keywords.join(' | ')}` : '<number>';
|
|
64
74
|
case 'color':
|
|
65
75
|
return syntax.keywords && syntax.keywords.length ? `<color> | ${syntax.keywords.join(' | ')}` : '<color>';
|
|
66
76
|
case 'keyword':
|