@ng-native/fabric 0.1.2 → 0.2.0
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 +1 -1
- package/dist/css.d.ts +69 -13
- package/dist/css.js +291 -59
- package/dist/css.js.map +1 -1
- package/dist/engine.d.ts +56 -3
- package/dist/engine.js +144 -9
- package/dist/engine.js.map +1 -1
- package/dist/font-faces.d.ts +42 -0
- package/dist/font-faces.js +112 -0
- package/dist/font-faces.js.map +1 -0
- package/dist/forms-inputs.js +1 -1
- package/dist/forms-inputs.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/inline-derived-token.d.ts +15 -0
- package/dist/inline-derived-token.js +252 -0
- package/dist/inline-derived-token.js.map +1 -0
- package/dist/inline-token.d.ts +4 -2
- package/dist/inline-token.js +90 -2
- package/dist/inline-token.js.map +1 -1
- package/package.json +1 -1
package/dist/inline-token.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { derivedToken } from "./inline-derived-token.js";
|
|
1
2
|
import { isNamedColor } from "./transition.js";
|
|
2
3
|
const PX = /^(-?\d*\.?\d+)px$/;
|
|
3
4
|
const PERCENT = /^-?\d*\.?\d+%$/;
|
|
4
5
|
const NUMBER = /^-?\d*\.?\d+$/;
|
|
6
|
+
const ANGLE = /^(-?\d*\.?\d+)(deg|grad|rad|turn)$/i;
|
|
5
7
|
/** `#fff`, `rgb()`, `rgba()`, `hsl()`, `hsla()` and `hwb()`: what React Native's `processColor` reads. */
|
|
6
8
|
const COLOR_FUNCTION = /^(#[\da-f]{3,8}|(rgba?|hsla?|hwb)\(.*\))$/i;
|
|
7
9
|
const WORD = /^-?[a-z][\w-]*$/i;
|
|
10
|
+
/** One colour channel: a number, a percentage, or a hue with its unit. */
|
|
11
|
+
const CHANNEL = /^(-?(?:\d+\.?\d*|\.\d+))(%|deg|grad|rad|turn)?$/;
|
|
12
|
+
const HUE_UNITS = { deg: 1, grad: 0.9, rad: 180 / Math.PI, turn: 360 };
|
|
13
|
+
/** `var(--name)` or `var(--name, <fallback>)`, the whole value. */
|
|
14
|
+
const VAR = /^var\(\s*(--[\w-]+)\s*(?:,([\s\S]*))?\)$/i;
|
|
8
15
|
const WEIGHTS = { normal: '400', bold: '700' };
|
|
9
16
|
/**
|
|
10
17
|
* CSS takes a bare 0 wherever it takes a length, and no other bare number. A number from 1 to 1000
|
|
@@ -30,6 +37,78 @@ function fromWord(text) {
|
|
|
30
37
|
...(weight ? { weight } : {}),
|
|
31
38
|
};
|
|
32
39
|
}
|
|
40
|
+
const clamp = (value, low, high) => Math.min(high, Math.max(low, value));
|
|
41
|
+
/**
|
|
42
|
+
* `13 110 253`, `13, 110, 253`, `100% 0% 0%` or `0 100% 50%`, in the forms `rgb()` and `hsl()` read
|
|
43
|
+
* channels in, by the same rules the build-time conversion uses (`channelForms` in values.cjs).
|
|
44
|
+
*/
|
|
45
|
+
function fromChannels(text) {
|
|
46
|
+
const commas = text.split(',');
|
|
47
|
+
const spaced = commas.length === 1;
|
|
48
|
+
const words = spaced ? text.split(/\s+/) : commas.map((word) => word.trim());
|
|
49
|
+
const parsed = words.map((word) => CHANNEL.exec(word));
|
|
50
|
+
if (parsed.length !== 3 || parsed.some((match) => !match))
|
|
51
|
+
return undefined;
|
|
52
|
+
const values = parsed.map((match) => ({ n: Number(match[1]), unit: match[2] ?? '' }));
|
|
53
|
+
const channels = rgbChannels(values);
|
|
54
|
+
const hslChannels = hslOf(values, spaced);
|
|
55
|
+
if (!channels && !hslChannels)
|
|
56
|
+
return undefined;
|
|
57
|
+
return { ...(channels ? { channels } : {}), ...(hslChannels ? { hslChannels } : {}) };
|
|
58
|
+
}
|
|
59
|
+
/** As `rgb()` reads them: three numbers, or three percentages of 255. */
|
|
60
|
+
function rgbChannels(values) {
|
|
61
|
+
const scale = values.every((v) => v.unit === '')
|
|
62
|
+
? 1
|
|
63
|
+
: values.every((v) => v.unit === '%')
|
|
64
|
+
? 255 / 100
|
|
65
|
+
: 0;
|
|
66
|
+
if (!scale)
|
|
67
|
+
return undefined;
|
|
68
|
+
return values.map((v) => Math.round(clamp(v.n * scale, 0, 255) * 1000) / 1000);
|
|
69
|
+
}
|
|
70
|
+
/** As `hsl()` reads them: a hue, then two percentages, which the space syntax may write bare. */
|
|
71
|
+
function hslOf([hue, ...rest], spaced) {
|
|
72
|
+
const degrees = hue.n * (hue.unit === '' ? 1 : (HUE_UNITS[hue.unit] ?? NaN));
|
|
73
|
+
const fractions = rest.map((v) => v.unit === '%' || (spaced && v.unit === '') ? clamp(v.n / 100, 0, 1) : NaN);
|
|
74
|
+
const hsl = [degrees, ...fractions];
|
|
75
|
+
return hsl.every(Number.isFinite) ? hsl : undefined;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Another token, kept as an alias and resolved where it is set, as a stylesheet's `--x: var(--y)`
|
|
79
|
+
* is. Undefined when the parentheses do not close where the value ends: `var(--a, 1px) var(--b)`.
|
|
80
|
+
*/
|
|
81
|
+
function fromVar(text) {
|
|
82
|
+
const match = VAR.exec(text);
|
|
83
|
+
if (!match)
|
|
84
|
+
return undefined;
|
|
85
|
+
const alias = match[1];
|
|
86
|
+
const rest = match[2];
|
|
87
|
+
if (rest === undefined)
|
|
88
|
+
return { alias };
|
|
89
|
+
if (!balanced(rest))
|
|
90
|
+
return undefined;
|
|
91
|
+
const fallback = tokenFromValue(rest);
|
|
92
|
+
return fallback ? { alias, fallback } : { alias };
|
|
93
|
+
}
|
|
94
|
+
function balanced(text) {
|
|
95
|
+
let depth = 0;
|
|
96
|
+
for (const char of text) {
|
|
97
|
+
if (char === '(')
|
|
98
|
+
depth++;
|
|
99
|
+
else if (char === ')' && --depth < 0)
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
return depth === 0;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* A value with a token in it: another token, or one made of others, worked out where it is set.
|
|
106
|
+
* Any other shape is a word no use site reads, as a colour function with a `var()` left in it is
|
|
107
|
+
* not a colour native can draw.
|
|
108
|
+
*/
|
|
109
|
+
function withTokens(text) {
|
|
110
|
+
return fromVar(text) ?? derivedToken(text) ?? { keyword: text };
|
|
111
|
+
}
|
|
33
112
|
export function tokenFromValue(value) {
|
|
34
113
|
if (typeof value === 'number')
|
|
35
114
|
return fromNumber(value);
|
|
@@ -41,12 +120,21 @@ export function tokenFromValue(value) {
|
|
|
41
120
|
const px = PX.exec(text);
|
|
42
121
|
if (px)
|
|
43
122
|
return { length: Number(px[1]) };
|
|
123
|
+
// A percentage is a fraction as well, and an angle its degrees, as the build-time conversion
|
|
124
|
+
// reads them: an hsl() of tokens takes its saturation and its hue so.
|
|
44
125
|
if (PERCENT.test(text))
|
|
45
|
-
return { length: text };
|
|
126
|
+
return { length: text, number: Number(text.slice(0, -1)) / 100 };
|
|
127
|
+
const angle = ANGLE.exec(text);
|
|
128
|
+
if (angle) {
|
|
129
|
+
const [, value, unit] = angle;
|
|
130
|
+
return { angle: Number(value) * HUE_UNITS[unit.toLowerCase()], number: Number(value) };
|
|
131
|
+
}
|
|
46
132
|
if (NUMBER.test(text))
|
|
47
133
|
return fromNumber(Number(text));
|
|
134
|
+
if (text.includes('var('))
|
|
135
|
+
return withTokens(text);
|
|
48
136
|
if (COLOR_FUNCTION.test(text))
|
|
49
137
|
return { color: text };
|
|
50
|
-
return WORD.test(text) ? fromWord(text) : { keyword: text };
|
|
138
|
+
return fromChannels(text) ?? (WORD.test(text) ? fromWord(text) : { keyword: text });
|
|
51
139
|
}
|
|
52
140
|
//# sourceMappingURL=inline-token.js.map
|
package/dist/inline-token.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inline-token.js","sourceRoot":"","sources":["../src/inline-token.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,EAAE,GAAG,mBAAmB,CAAC;AAC/B,MAAM,OAAO,GAAG,gBAAgB,CAAC;AACjC,MAAM,MAAM,GAAG,eAAe,CAAC;AAC/B,0GAA0G;AAC1G,MAAM,cAAc,GAAG,4CAA4C,CAAC;AACpE,MAAM,IAAI,GAAG,kBAAkB,CAAC;AAChC,MAAM,OAAO,GAA2B,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAEvE;;;GAGG;AACH,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,MAAM,GACV,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI;QACzB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE;QACjF,CAAC,CAAC,EAAE,CAAC;IACT,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAAC;AAC/E,CAAC;AAED;;;GAGG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3C,OAAO;QACL,OAAO,EAAE,IAAI;QACb,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;IACxD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAChD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACtD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC","sourcesContent":["/**\n * A custom property's value set on an element at run time, `[style.--tint]=\"tint()\"` or\n * `style=\"--gap: 4px\"`, as a token the cascade can read.\n *\n * A stylesheet's custom properties are converted when the app is built, where there is a CSS\n * parser (`@ng-native/metro/css/values.cjs`). A bound one only exists here, where there is not,\n * so this takes the shapes a binding actually holds and nothing more: a length in `px` or `%`, a\n * number, a colour as React Native writes one, and a word. Anything else is kept as a word, which\n * a use site that wants a length or a colour ignores, as it ignores an undefined token.\n */\nimport type { TokenValue } from './css.ts';\nimport { isNamedColor } from './transition.ts';\n\nconst PX = /^(-?\\d*\\.?\\d+)px$/;\nconst PERCENT = /^-?\\d*\\.?\\d+%$/;\nconst NUMBER = /^-?\\d*\\.?\\d+$/;\n/** `#fff`, `rgb()`, `rgba()`, `hsl()`, `hsla()` and `hwb()`: what React Native's `processColor` reads. */\nconst COLOR_FUNCTION = /^(#[\\da-f]{3,8}|(rgba?|hsla?|hwb)\\(.*\\))$/i;\nconst WORD = /^-?[a-z][\\w-]*$/i;\nconst WEIGHTS: Record<string, string> = { normal: '400', bold: '700' };\n\n/**\n * CSS takes a bare 0 wherever it takes a length, and no other bare number. A number from 1 to 1000\n * is a weight as well, at the nearest hundred, which is every weight native draws.\n */\nfunction fromNumber(value: number): TokenValue | undefined {\n if (!Number.isFinite(value)) return undefined;\n const weight =\n value >= 1 && value <= 1000\n ? { weight: String(Math.min(900, Math.max(100, Math.round(value / 100) * 100))) }\n : {};\n return value === 0 ? { number: 0, length: 0 } : { number: value, ...weight };\n}\n\n/**\n * A word is a keyword, `row`, and may be a colour, `red`, or a weight, `bold`, as well: every form\n * it can take, as the build-time conversion gives, and a use site reads the one it needs.\n */\nfunction fromWord(text: string): TokenValue {\n const weight = WEIGHTS[text.toLowerCase()];\n return {\n keyword: text,\n ...(isNamedColor(text) ? { color: text } : {}),\n ...(weight ? { weight } : {}),\n };\n}\n\nexport function tokenFromValue(value: unknown): TokenValue | undefined {\n if (typeof value === 'number') return fromNumber(value);\n if (typeof value !== 'string') return undefined;\n const text = value.trim();\n if (!text) return undefined;\n const px = PX.exec(text);\n if (px) return { length: Number(px[1]) };\n if (PERCENT.test(text)) return { length: text };\n if (NUMBER.test(text)) return fromNumber(Number(text));\n if (COLOR_FUNCTION.test(text)) return { color: text };\n return WORD.test(text) ? fromWord(text) : { keyword: text };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"inline-token.js","sourceRoot":"","sources":["../src/inline-token.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A custom property's value set on an element at run time, `[style.--tint]=\"tint()\"` or\n * `style=\"--gap: 4px\"`, as a token the cascade can read.\n *\n * A stylesheet's custom properties are converted when the app is built, where there is a CSS\n * parser (`@ng-native/metro/css/values.cjs`). A bound one only exists here, where there is not,\n * so this takes the shapes a binding actually holds and nothing more: a length in `px` or `%`, a\n * number, a colour as React Native writes one, a colour's three channels, a word, another token,\n * `var(--brand)`, and one made of others, `calc(var(--gap) * 2)` (see inline-derived-token.ts).\n * Anything else is kept as a word, which a use site that wants a length or a colour ignores, as\n * it ignores an undefined token.\n */\nimport type { TokenValue } from './css.ts';\nimport { derivedToken } from './inline-derived-token.ts';\nimport { isNamedColor } from './transition.ts';\n\nconst PX = /^(-?\\d*\\.?\\d+)px$/;\nconst PERCENT = /^-?\\d*\\.?\\d+%$/;\nconst NUMBER = /^-?\\d*\\.?\\d+$/;\nconst ANGLE = /^(-?\\d*\\.?\\d+)(deg|grad|rad|turn)$/i;\n/** `#fff`, `rgb()`, `rgba()`, `hsl()`, `hsla()` and `hwb()`: what React Native's `processColor` reads. */\nconst COLOR_FUNCTION = /^(#[\\da-f]{3,8}|(rgba?|hsla?|hwb)\\(.*\\))$/i;\nconst WORD = /^-?[a-z][\\w-]*$/i;\n/** One colour channel: a number, a percentage, or a hue with its unit. */\nconst CHANNEL = /^(-?(?:\\d+\\.?\\d*|\\.\\d+))(%|deg|grad|rad|turn)?$/;\nconst HUE_UNITS: Record<string, number> = { deg: 1, grad: 0.9, rad: 180 / Math.PI, turn: 360 };\n/** `var(--name)` or `var(--name, <fallback>)`, the whole value. */\nconst VAR = /^var\\(\\s*(--[\\w-]+)\\s*(?:,([\\s\\S]*))?\\)$/i;\nconst WEIGHTS: Record<string, string> = { normal: '400', bold: '700' };\n\n/**\n * CSS takes a bare 0 wherever it takes a length, and no other bare number. A number from 1 to 1000\n * is a weight as well, at the nearest hundred, which is every weight native draws.\n */\nfunction fromNumber(value: number): TokenValue | undefined {\n if (!Number.isFinite(value)) return undefined;\n const weight =\n value >= 1 && value <= 1000\n ? { weight: String(Math.min(900, Math.max(100, Math.round(value / 100) * 100))) }\n : {};\n return value === 0 ? { number: 0, length: 0 } : { number: value, ...weight };\n}\n\n/**\n * A word is a keyword, `row`, and may be a colour, `red`, or a weight, `bold`, as well: every form\n * it can take, as the build-time conversion gives, and a use site reads the one it needs.\n */\nfunction fromWord(text: string): TokenValue {\n const weight = WEIGHTS[text.toLowerCase()];\n return {\n keyword: text,\n ...(isNamedColor(text) ? { color: text } : {}),\n ...(weight ? { weight } : {}),\n };\n}\n\nconst clamp = (value: number, low: number, high: number) => Math.min(high, Math.max(low, value));\n\n/**\n * `13 110 253`, `13, 110, 253`, `100% 0% 0%` or `0 100% 50%`, in the forms `rgb()` and `hsl()` read\n * channels in, by the same rules the build-time conversion uses (`channelForms` in values.cjs).\n */\nfunction fromChannels(text: string): TokenValue | undefined {\n const commas = text.split(',');\n const spaced = commas.length === 1;\n const words = spaced ? text.split(/\\s+/) : commas.map((word) => word.trim());\n const parsed = words.map((word) => CHANNEL.exec(word));\n if (parsed.length !== 3 || parsed.some((match) => !match)) return undefined;\n const values = parsed.map((match) => ({ n: Number(match![1]), unit: match![2] ?? '' }));\n const channels = rgbChannels(values);\n const hslChannels = hslOf(values, spaced);\n if (!channels && !hslChannels) return undefined;\n return { ...(channels ? { channels } : {}), ...(hslChannels ? { hslChannels } : {}) };\n}\n\ninterface Channel {\n readonly n: number;\n readonly unit: string;\n}\n\n/** As `rgb()` reads them: three numbers, or three percentages of 255. */\nfunction rgbChannels(values: readonly Channel[]): number[] | undefined {\n const scale = values.every((v) => v.unit === '')\n ? 1\n : values.every((v) => v.unit === '%')\n ? 255 / 100\n : 0;\n if (!scale) return undefined;\n return values.map((v) => Math.round(clamp(v.n * scale, 0, 255) * 1000) / 1000);\n}\n\n/** As `hsl()` reads them: a hue, then two percentages, which the space syntax may write bare. */\nfunction hslOf([hue, ...rest]: readonly Channel[], spaced: boolean): number[] | undefined {\n const degrees = hue!.n * (hue!.unit === '' ? 1 : (HUE_UNITS[hue!.unit] ?? NaN));\n const fractions = rest.map((v) =>\n v.unit === '%' || (spaced && v.unit === '') ? clamp(v.n / 100, 0, 1) : NaN,\n );\n const hsl = [degrees, ...fractions];\n return hsl.every(Number.isFinite) ? hsl : undefined;\n}\n\n/**\n * Another token, kept as an alias and resolved where it is set, as a stylesheet's `--x: var(--y)`\n * is. Undefined when the parentheses do not close where the value ends: `var(--a, 1px) var(--b)`.\n */\nfunction fromVar(text: string): TokenValue | undefined {\n const match = VAR.exec(text);\n if (!match) return undefined;\n const alias = match[1]!;\n const rest = match[2];\n if (rest === undefined) return { alias };\n if (!balanced(rest)) return undefined;\n const fallback = tokenFromValue(rest);\n return fallback ? { alias, fallback } : { alias };\n}\n\nfunction balanced(text: string): boolean {\n let depth = 0;\n for (const char of text) {\n if (char === '(') depth++;\n else if (char === ')' && --depth < 0) return false;\n }\n return depth === 0;\n}\n\n/**\n * A value with a token in it: another token, or one made of others, worked out where it is set.\n * Any other shape is a word no use site reads, as a colour function with a `var()` left in it is\n * not a colour native can draw.\n */\nfunction withTokens(text: string): TokenValue {\n return fromVar(text) ?? derivedToken(text) ?? { keyword: text };\n}\n\nexport function tokenFromValue(value: unknown): TokenValue | undefined {\n if (typeof value === 'number') return fromNumber(value);\n if (typeof value !== 'string') return undefined;\n const text = value.trim();\n if (!text) return undefined;\n const px = PX.exec(text);\n if (px) return { length: Number(px[1]) };\n // A percentage is a fraction as well, and an angle its degrees, as the build-time conversion\n // reads them: an hsl() of tokens takes its saturation and its hue so.\n if (PERCENT.test(text)) return { length: text, number: Number(text.slice(0, -1)) / 100 };\n const angle = ANGLE.exec(text);\n if (angle) {\n const [, value, unit] = angle;\n return { angle: Number(value) * HUE_UNITS[unit!.toLowerCase()]!, number: Number(value) };\n }\n if (NUMBER.test(text)) return fromNumber(Number(text));\n if (text.includes('var(')) return withTokens(text);\n if (COLOR_FUNCTION.test(text)) return { color: text };\n return fromChannels(text) ?? (WORD.test(text) ? fromWord(text) : { keyword: text });\n}\n"]}
|
package/package.json
CHANGED