@astryxdesign/core 0.4.2 → 0.4.3-canary.551a8de
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/CHANGELOG.md +45 -0
- package/README.md +79 -45
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +3 -19
- package/dist/Banner/Banner.d.ts +9 -2
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +84 -33
- package/dist/Banner/index.d.ts +14 -12
- package/dist/Banner/index.d.ts.map +1 -1
- package/dist/Banner/index.js +10 -8
- package/dist/Chat/ChatTokenizedText.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts +38 -4
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +98 -31
- package/dist/ComplexSelector/index.d.ts +2 -2
- package/dist/ComplexSelector/index.d.ts.map +1 -1
- package/dist/ComplexSelector/index.js +1 -1
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +55 -12
- package/dist/MobileNav/MobileNav.d.ts +12 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +102 -30
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +4 -1
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +2 -4
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +5 -1
- package/dist/Table/columnUtils.d.ts.map +1 -1
- package/dist/Table/columnUtils.js +4 -1
- package/dist/TextArea/TextArea.d.ts +6 -3
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +17 -6
- package/dist/TreeList/TreeList.js +2 -1
- package/dist/astryx.css +8 -4
- package/dist/theme/defineTheme.d.ts +30 -7
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +36 -47
- package/dist/theme/expandColorScale.d.ts +17 -2
- package/dist/theme/expandColorScale.d.ts.map +1 -1
- package/dist/theme/expandColorScale.js +63 -33
- package/dist/theme/mergeComponents.d.ts +20 -0
- package/dist/theme/mergeComponents.d.ts.map +1 -0
- package/dist/theme/mergeComponents.js +56 -0
- package/dist/theme/onMediaTokens.d.ts +6 -1
- package/dist/theme/onMediaTokens.d.ts.map +1 -1
- package/dist/theme/onMediaTokens.js +11 -3
- package/dist/utils/characters.d.ts +27 -0
- package/dist/utils/characters.d.ts.map +1 -0
- package/dist/utils/characters.js +83 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/package.json +4 -8
- package/src/Avatar/Avatar.test.tsx +6 -1
- package/src/Avatar/Avatar.tsx +3 -21
- package/src/Banner/Banner.doc.mjs +12 -10
- package/src/Banner/Banner.test.tsx +108 -0
- package/src/Banner/Banner.tsx +124 -38
- package/src/Banner/index.ts +15 -13
- package/src/Chat/ChatTokenizedText.tsx +1 -1
- package/src/ComplexSelector/ComplexSelector.doc.mjs +55 -6
- package/src/ComplexSelector/ComplexSelector.test.tsx +197 -6
- package/src/ComplexSelector/ComplexSelector.tsx +156 -28
- package/src/ComplexSelector/index.ts +3 -1
- package/src/Markdown/parser.test.ts +53 -0
- package/src/Markdown/parser.ts +53 -12
- package/src/MobileNav/MobileNav.tsx +128 -37
- package/src/MobileNav/MobileNavCloseEdgeCases.test.tsx +426 -0
- package/src/MobileNav/MobileNavCloseTiming.test.ts +58 -0
- package/src/MobileNav/MobileNavCloseVisibility.test.tsx +172 -0
- package/src/PowerSearch/PowerSearch.test.tsx +48 -3
- package/src/PowerSearch/PowerSearch.tsx +4 -1
- package/src/PowerSearch/formatFilterValue.test.ts +22 -0
- package/src/PowerSearch/formatFilterValue.ts +2 -4
- package/src/Switch/Switch.test.tsx +16 -0
- package/src/Switch/Switch.tsx +7 -0
- package/src/Table/Table.test.tsx +6 -0
- package/src/Table/columnUtils.ts +3 -1
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextArea/TextArea.test.tsx +72 -0
- package/src/TextArea/TextArea.tsx +26 -8
- package/src/TreeList/TreeList.doc.mjs +2 -2
- package/src/TreeList/TreeList.tsx +1 -1
- package/src/__tests__/stubMatchMedia.test.ts +79 -0
- package/src/__tests__/stubMatchMedia.ts +95 -0
- package/src/theme/defineTheme.test.ts +127 -0
- package/src/theme/defineTheme.ts +70 -55
- package/src/theme/expandColorScale.test.ts +138 -0
- package/src/theme/expandColorScale.ts +89 -44
- package/src/theme/extensibleAxes.test.ts +365 -0
- package/src/theme/mergeComponents.ts +59 -0
- package/src/theme/onMediaTokens.ts +9 -2
- package/src/utils/characters.test.ts +141 -0
- package/src/utils/characters.ts +88 -0
- package/src/utils/index.ts +2 -0
- package/dist/astryx.umd.js +0 -147
- package/dist/astryx.umd.js.map +0 -7
|
@@ -44,6 +44,7 @@ import { expandRadiusScale } from "./expandRadiusScale.js";
|
|
|
44
44
|
import { expandColorScale } from "./expandColorScale.js";
|
|
45
45
|
import { domainTokenDefaults } from "./domainTokens/index.js";
|
|
46
46
|
import { registerTheme } from "./themeRegistry.js";
|
|
47
|
+
import { deepMergeComponents } from "./mergeComponents.js";
|
|
47
48
|
|
|
48
49
|
// =============================================================================
|
|
49
50
|
// Types
|
|
@@ -155,48 +156,6 @@ function resolveTokenValue(value) {
|
|
|
155
156
|
return value;
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
/**
|
|
159
|
-
* Deep-merge two component style maps.
|
|
160
|
-
* Properties in `overrides` take precedence over `base`.
|
|
161
|
-
* This allows typeScale-generated rules to be overridden by explicit components.
|
|
162
|
-
*/
|
|
163
|
-
function deepMergeComponents(base, overrides) {
|
|
164
|
-
if (!base && !overrides) {
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
167
|
-
if (!base) {
|
|
168
|
-
return overrides;
|
|
169
|
-
}
|
|
170
|
-
if (!overrides) {
|
|
171
|
-
return base;
|
|
172
|
-
}
|
|
173
|
-
const result = {};
|
|
174
|
-
|
|
175
|
-
// Start with all base entries
|
|
176
|
-
for (const [component, rules] of Object.entries(base)) {
|
|
177
|
-
result[component] = {
|
|
178
|
-
...rules
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Merge overrides on top
|
|
183
|
-
for (const [component, rules] of Object.entries(overrides)) {
|
|
184
|
-
if (!result[component]) {
|
|
185
|
-
result[component] = {
|
|
186
|
-
...rules
|
|
187
|
-
};
|
|
188
|
-
} else {
|
|
189
|
-
for (const [key, styles] of Object.entries(rules)) {
|
|
190
|
-
result[component][key] = {
|
|
191
|
-
...result[component][key],
|
|
192
|
-
...styles
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return result;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
159
|
/**
|
|
201
160
|
* Resolve a FontWeight name to a var() reference.
|
|
202
161
|
* Named weights map to var(--font-weight-*); raw values pass through.
|
|
@@ -226,6 +185,24 @@ function buildFontFamily(family, fallbacks) {
|
|
|
226
185
|
return quoted;
|
|
227
186
|
}
|
|
228
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Describe a rejected `extends` value for the error message — enough to tell a
|
|
190
|
+
* missed import (`undefined`) from a module namespace or a plain object.
|
|
191
|
+
*/
|
|
192
|
+
function describeBadBase(value) {
|
|
193
|
+
if (value === undefined) {
|
|
194
|
+
return 'undefined';
|
|
195
|
+
}
|
|
196
|
+
if (value === null) {
|
|
197
|
+
return 'null';
|
|
198
|
+
}
|
|
199
|
+
if (typeof value !== 'object') {
|
|
200
|
+
return typeof value;
|
|
201
|
+
}
|
|
202
|
+
const keys = Object.keys(value);
|
|
203
|
+
return `an object with keys [${keys.slice(0, 4).join(', ')}${keys.length > 4 ? ', …' : ''}]`;
|
|
204
|
+
}
|
|
205
|
+
|
|
229
206
|
/**
|
|
230
207
|
* Create an Astryx theme.
|
|
231
208
|
*
|
|
@@ -239,7 +216,15 @@ function buildFontFamily(family, fallbacks) {
|
|
|
239
216
|
export function defineTheme(input) {
|
|
240
217
|
const tokens = {};
|
|
241
218
|
|
|
242
|
-
// 0. Pre-seed from base theme when `extends` is provided (lowest precedence)
|
|
219
|
+
// 0. Pre-seed from base theme when `extends` is provided (lowest precedence).
|
|
220
|
+
// A base that is not a theme is refused rather than ignored: `extends` used
|
|
221
|
+
// to inherit nothing when its value was undefined, which is what a named
|
|
222
|
+
// import silently resolving to the wrong module hands over, and the theme
|
|
223
|
+
// then built into a plausible-looking stylesheet missing everything it was
|
|
224
|
+
// supposed to inherit.
|
|
225
|
+
if ('extends' in input && !isDefinedTheme(input.extends)) {
|
|
226
|
+
throw new Error(`defineTheme("${input.name}"): \`extends\` must be a theme from defineTheme(), got ${describeBadBase(input.extends)}. ` + `Check that the import naming your base theme resolves to its source and exports that name — ` + `a generated \`<theme>.js\` artifact sitting next to the source exports \`<name>Theme\`, not the source's own export.`);
|
|
227
|
+
}
|
|
243
228
|
const base = input.extends;
|
|
244
229
|
if (base) {
|
|
245
230
|
for (const [key, value] of Object.entries(base.tokens)) {
|
|
@@ -370,9 +355,10 @@ export function defineTheme(input) {
|
|
|
370
355
|
components = deepMergeComponents(base.components, components);
|
|
371
356
|
}
|
|
372
357
|
|
|
373
|
-
// 4. Resolve on-media token overrides (
|
|
374
|
-
|
|
375
|
-
const
|
|
358
|
+
// 4. Resolve on-media token overrides (base's resolved surface, then
|
|
359
|
+
// defaults, then this theme's own overrides)
|
|
360
|
+
const __onDark = resolveOnMedia('dark', input.onDark, base?.__onDark);
|
|
361
|
+
const __onLight = resolveOnMedia('light', input.onLight, base?.__onLight);
|
|
376
362
|
|
|
377
363
|
// 5. Merge icons — input icons override base icons
|
|
378
364
|
const icons = input.icons && base?.icons ? {
|
|
@@ -392,7 +378,10 @@ export function defineTheme(input) {
|
|
|
392
378
|
components,
|
|
393
379
|
icons,
|
|
394
380
|
indicators,
|
|
395
|
-
__inputTokens: input.tokens
|
|
381
|
+
__inputTokens: base?.__inputTokens || input.tokens ? {
|
|
382
|
+
...base?.__inputTokens,
|
|
383
|
+
...input.tokens
|
|
384
|
+
} : undefined,
|
|
396
385
|
__onDark,
|
|
397
386
|
__onLight
|
|
398
387
|
};
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* // Minimal — just a seed color
|
|
7
7
|
* { accent: '#0064E0' }
|
|
8
8
|
*
|
|
9
|
+
* // Per-scheme seeds: light palettes from '#0064E0', dark from '#48CAE4'
|
|
10
|
+
* { accent: ['#0064E0', '#48CAE4'] }
|
|
11
|
+
*
|
|
9
12
|
* // With customization
|
|
10
13
|
* { accent: '#B7410E', neutralStyle: 'warm', contrast: 'high' }
|
|
11
14
|
*
|
|
@@ -15,14 +18,18 @@
|
|
|
15
18
|
*/
|
|
16
19
|
export interface ColorScaleConfig {
|
|
17
20
|
/**
|
|
18
|
-
* Seed accent color
|
|
21
|
+
* Seed accent color. Everything derives from this.
|
|
22
|
+
*
|
|
23
|
+
* Either a single hex (#RRGGBB) used for both color schemes, or a
|
|
24
|
+
* `[light, dark]` hex tuple: the light scheme's palettes derive from
|
|
25
|
+
* the light seed and the dark scheme's palettes from the dark seed.
|
|
19
26
|
*
|
|
20
27
|
* Optional. When omitted, the neutral palettes are seeded from the
|
|
21
28
|
* default accent's hue and the accent tokens (--color-accent,
|
|
22
29
|
* --color-accent-muted, --color-on-accent) are not generated — they
|
|
23
30
|
* fall through to colorDefaults.
|
|
24
31
|
*/
|
|
25
|
-
accent?: string;
|
|
32
|
+
accent?: string | [light: string, dark: string];
|
|
26
33
|
/**
|
|
27
34
|
* Neutral tone warmth. Controls how much of the seed's hue bleeds
|
|
28
35
|
* into neutral/background colors.
|
|
@@ -56,6 +63,11 @@ export declare function ensureContrastTone(hue: number, chroma: number, startTon
|
|
|
56
63
|
* --color-on-dark/on-light) are NOT generated — they fall through
|
|
57
64
|
* to colorDefaults.
|
|
58
65
|
*
|
|
66
|
+
* A `[light, dark]` tuple accent seeds each scheme separately: the light
|
|
67
|
+
* half of every generated `light-dark()` pair comes from the light seed's
|
|
68
|
+
* palettes, the dark half from the dark seed's. A string accent seeds both
|
|
69
|
+
* halves from the same palettes, exactly as before tuples were supported.
|
|
70
|
+
*
|
|
59
71
|
* Without an `accent`, the accent tokens join that fall-through set: the
|
|
60
72
|
* neutrals are seeded from the default accent's hue, and --color-accent,
|
|
61
73
|
* --color-accent-muted and --color-on-accent keep their colorDefaults values.
|
|
@@ -65,6 +77,9 @@ export declare function ensureContrastTone(hue: number, chroma: number, startTon
|
|
|
65
77
|
* const tokens = expandColorScale({ accent: '#0064E0' });
|
|
66
78
|
* // tokens['--color-accent'] === 'light-dark(#..., #...)'
|
|
67
79
|
*
|
|
80
|
+
* const perScheme = expandColorScale({ accent: ['#0064E0', '#48CAE4'] });
|
|
81
|
+
* // light half derives from #0064E0, dark half from #48CAE4
|
|
82
|
+
*
|
|
68
83
|
* const neutralOnly = expandColorScale({ neutralStyle: 'warm' });
|
|
69
84
|
* // neutralOnly['--color-accent'] === undefined
|
|
70
85
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expandColorScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandColorScale.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"expandColorScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandColorScale.ts"],"names":[],"mappings":"AAgDA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAEhD;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAE3C;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAyCtD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,EACZ,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAYR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CA0J3E"}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* @output Token overrides for derivable color tokens
|
|
7
7
|
* @position Theme utility; consumed by defineTheme.ts
|
|
8
8
|
*
|
|
9
|
-
* Generates color token overrides from
|
|
10
|
-
*
|
|
9
|
+
* Generates color token overrides from an accent seed using the HCT
|
|
10
|
+
* perceptual color model. Only produces tokens that meaningfully
|
|
11
11
|
* derive from the accent — status colors, categorical hues, and fixed
|
|
12
12
|
* tokens (on-dark/on-light) fall through to colorDefaults.
|
|
13
13
|
*
|
|
@@ -15,11 +15,19 @@
|
|
|
15
15
|
* ramp (seeded from the default accent's hue) while the accent tokens
|
|
16
16
|
* themselves fall through to colorDefaults, same as the tokens above.
|
|
17
17
|
*
|
|
18
|
+
* `accent` also accepts a `[light, dark]` tuple (matching `TokenValue` in
|
|
19
|
+
* defineTheme). A tuple seeds each color scheme from its own half: the
|
|
20
|
+
* light side of every generated `light-dark()` pair derives from the light
|
|
21
|
+
* accent's palettes, the dark side from the dark accent's. A plain string
|
|
22
|
+
* seeds both sides identically, token for token the same output as before
|
|
23
|
+
* tuples existed.
|
|
24
|
+
*
|
|
18
25
|
* WCAG contrast guarantees (asserted in expandColorScale.test.ts):
|
|
19
26
|
* - Text tones are guaranteed >= 4.5:1 against their surfaces by tone
|
|
20
27
|
* spacing alone — HCT tone is CIE L*, which fixes relative luminance
|
|
21
28
|
* regardless of hue/chroma, so the fixed tone assignments hold for any
|
|
22
|
-
* accent/neutralStyle (WCAG 1.4.3)
|
|
29
|
+
* accent/neutralStyle (WCAG 1.4.3), and each half of a tuple pairs with
|
|
30
|
+
* surfaces derived from that same seed.
|
|
23
31
|
* - --color-border-emphasized (form-control boundaries) is tone-bumped
|
|
24
32
|
* until it reaches >= 3:1 against the generated surface (WCAG 1.4.11).
|
|
25
33
|
* - --color-border, --color-skeleton, and --color-track are intentionally
|
|
@@ -46,6 +54,9 @@ import { hexToHct, hctToHex, tonalPalette, hexWithAlpha } from "./hct.js";
|
|
|
46
54
|
* // Minimal — just a seed color
|
|
47
55
|
* { accent: '#0064E0' }
|
|
48
56
|
*
|
|
57
|
+
* // Per-scheme seeds: light palettes from '#0064E0', dark from '#48CAE4'
|
|
58
|
+
* { accent: ['#0064E0', '#48CAE4'] }
|
|
59
|
+
*
|
|
49
60
|
* // With customization
|
|
50
61
|
* { accent: '#B7410E', neutralStyle: 'warm', contrast: 'high' }
|
|
51
62
|
*
|
|
@@ -126,6 +137,11 @@ export function ensureContrastTone(hue, chroma, startTone, step, background, min
|
|
|
126
137
|
* --color-on-dark/on-light) are NOT generated — they fall through
|
|
127
138
|
* to colorDefaults.
|
|
128
139
|
*
|
|
140
|
+
* A `[light, dark]` tuple accent seeds each scheme separately: the light
|
|
141
|
+
* half of every generated `light-dark()` pair comes from the light seed's
|
|
142
|
+
* palettes, the dark half from the dark seed's. A string accent seeds both
|
|
143
|
+
* halves from the same palettes, exactly as before tuples were supported.
|
|
144
|
+
*
|
|
129
145
|
* Without an `accent`, the accent tokens join that fall-through set: the
|
|
130
146
|
* neutrals are seeded from the default accent's hue, and --color-accent,
|
|
131
147
|
* --color-accent-muted and --color-on-accent keep their colorDefaults values.
|
|
@@ -135,6 +151,9 @@ export function ensureContrastTone(hue, chroma, startTone, step, background, min
|
|
|
135
151
|
* const tokens = expandColorScale({ accent: '#0064E0' });
|
|
136
152
|
* // tokens['--color-accent'] === 'light-dark(#..., #...)'
|
|
137
153
|
*
|
|
154
|
+
* const perScheme = expandColorScale({ accent: ['#0064E0', '#48CAE4'] });
|
|
155
|
+
* // light half derives from #0064E0, dark half from #48CAE4
|
|
156
|
+
*
|
|
138
157
|
* const neutralOnly = expandColorScale({ neutralStyle: 'warm' });
|
|
139
158
|
* // neutralOnly['--color-accent'] === undefined
|
|
140
159
|
* ```
|
|
@@ -145,14 +164,26 @@ export function expandColorScale(config) {
|
|
|
145
164
|
neutralStyle = 'cool',
|
|
146
165
|
contrast = 'standard'
|
|
147
166
|
} = config;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
167
|
+
|
|
168
|
+
// Normalize to per-scheme seeds. A string accent (or an absent one) uses
|
|
169
|
+
// the same seed for both halves, which keeps single-seed output identical
|
|
170
|
+
// to the pre-tuple implementation.
|
|
171
|
+
const [lightAccent, darkAccent] = Array.isArray(accent) ? accent : [accent, accent];
|
|
172
|
+
const lightSeed = hexToHct(lightAccent ?? DEFAULT_ACCENT_SEED);
|
|
173
|
+
const sameSeed = darkAccent === lightAccent;
|
|
174
|
+
const darkSeed = sameSeed ? lightSeed : hexToHct(darkAccent ?? DEFAULT_ACCENT_SEED);
|
|
151
175
|
const neutralChroma = NEUTRAL_CHROMA[neutralStyle] ?? 5;
|
|
152
176
|
const neutralVariantChroma = NEUTRAL_VARIANT_CHROMA[neutralStyle] ?? 8;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
177
|
+
|
|
178
|
+
// Palette naming: *L palettes feed the light (first) half of each ld()
|
|
179
|
+
// pair below, *D palettes the dark (second) half. With a single seed the
|
|
180
|
+
// D palettes alias the L ones.
|
|
181
|
+
const PL = tonalPalette(lightSeed.hue, Math.max(lightSeed.chroma, 48));
|
|
182
|
+
const NL = tonalPalette(lightSeed.hue, neutralChroma);
|
|
183
|
+
const NVL = tonalPalette(lightSeed.hue, neutralVariantChroma);
|
|
184
|
+
const PD = sameSeed ? PL : tonalPalette(darkSeed.hue, Math.max(darkSeed.chroma, 48));
|
|
185
|
+
const ND = sameSeed ? NL : tonalPalette(darkSeed.hue, neutralChroma);
|
|
186
|
+
const NVD = sameSeed ? NVL : tonalPalette(darkSeed.hue, neutralVariantChroma);
|
|
156
187
|
const isHigh = contrast === 'high';
|
|
157
188
|
const textPrimaryLightTone = isHigh ? 0 : 10;
|
|
158
189
|
const textPrimaryDarkTone = isHigh ? 99 : 90;
|
|
@@ -173,7 +204,7 @@ export function expandColorScale(config) {
|
|
|
173
204
|
// contrast starts at 70/30 and walks toward mid-scale only as far as needed.
|
|
174
205
|
const borderEmphasizedStartLight = isHigh ? 50 : 70;
|
|
175
206
|
const borderEmphasizedStartDark = isHigh ? 50 : 30;
|
|
176
|
-
const borderEmphasized = ld(ensureContrastTone(
|
|
207
|
+
const borderEmphasized = ld(ensureContrastTone(lightSeed.hue, neutralVariantChroma, borderEmphasizedStartLight, -1, NL[99], NON_TEXT_MIN_CONTRAST), ensureContrastTone(darkSeed.hue, neutralVariantChroma, borderEmphasizedStartDark, 1, ND[10], NON_TEXT_MIN_CONTRAST));
|
|
177
208
|
return {
|
|
178
209
|
// Core semantic — only with a seed accent. Without one these fall through
|
|
179
210
|
// to colorDefaults, whose --color-accent is NOT what the default seed
|
|
@@ -181,47 +212,46 @@ export function expandColorScale(config) {
|
|
|
181
212
|
// recolor every neutral-only theme. Nullish and not truthy, matching the
|
|
182
213
|
// seed above, so a supplied-but-malformed accent keeps its old behavior.
|
|
183
214
|
...(accent != null ? {
|
|
184
|
-
'--color-accent': ld(
|
|
215
|
+
'--color-accent': ld(PL[40], PD[80]),
|
|
185
216
|
// Derived accent tokens reference --color-accent instead of baking its
|
|
186
217
|
// resolved hex, so a scoped override of the base token re-accents the
|
|
187
218
|
// whole subtree at runtime. --color-on-accent stays baked: it is a
|
|
188
219
|
// contrast computation against the accent, which CSS cannot express.
|
|
189
220
|
'--color-accent-muted': ld(accentWithAlpha(0.2), accentWithAlpha(0.25)),
|
|
190
|
-
'--color-on-accent': ld(
|
|
221
|
+
'--color-on-accent': ld(PL[100], PD[20])
|
|
191
222
|
} : null),
|
|
192
|
-
'--color-neutral': ld(hexWithAlpha(
|
|
193
|
-
'--color-background-surface': ld(
|
|
194
|
-
'--color-background-body': ld(
|
|
195
|
-
'--color-overlay': ld(hexWithAlpha(
|
|
196
|
-
'--color-overlay-hover': ld(hexWithAlpha(
|
|
197
|
-
'--color-overlay-pressed': ld(hexWithAlpha(
|
|
198
|
-
'--color-background-muted': ld(hexWithAlpha(
|
|
223
|
+
'--color-neutral': ld(hexWithAlpha(NL[10], 0.1), hexWithAlpha(ND[90], 0.2)),
|
|
224
|
+
'--color-background-surface': ld(NL[99], ND[10]),
|
|
225
|
+
'--color-background-body': ld(NL[95], ND[5]),
|
|
226
|
+
'--color-overlay': ld(hexWithAlpha(NL[10], 0.4), hexWithAlpha(ND[10], 0.6)),
|
|
227
|
+
'--color-overlay-hover': ld(hexWithAlpha(NL[10], 0.05), hexWithAlpha(ND[100], 0.05)),
|
|
228
|
+
'--color-overlay-pressed': ld(hexWithAlpha(NL[10], 0.1), hexWithAlpha(ND[100], 0.1)),
|
|
229
|
+
'--color-background-muted': ld(hexWithAlpha(NL[10], 0.05), hexWithAlpha(ND[10], 0.5)),
|
|
199
230
|
// Text
|
|
200
|
-
'--color-text-primary': ld(
|
|
201
|
-
'--color-text-secondary': ld(
|
|
202
|
-
'--color-text-disabled': ld(
|
|
231
|
+
'--color-text-primary': ld(NL[textPrimaryLightTone], ND[textPrimaryDarkTone]),
|
|
232
|
+
'--color-text-secondary': ld(NVL[textSecondaryLightTone], NVD[textSecondaryDarkTone]),
|
|
233
|
+
'--color-text-disabled': ld(NVL[60], NVD[40]),
|
|
203
234
|
'--color-text-accent': 'var(--color-accent)',
|
|
204
235
|
// Icon
|
|
205
236
|
'--color-icon-accent': 'var(--color-accent)',
|
|
206
|
-
'--color-icon-primary': ld(
|
|
207
|
-
'--color-icon-secondary': ld(
|
|
208
|
-
'--color-icon-disabled': ld(
|
|
237
|
+
'--color-icon-primary': ld(NL[textPrimaryLightTone], ND[textPrimaryDarkTone]),
|
|
238
|
+
'--color-icon-secondary': ld(NVL[textSecondaryLightTone], NVD[textSecondaryDarkTone]),
|
|
239
|
+
'--color-icon-disabled': ld(NVL[60], NVD[40]),
|
|
209
240
|
// Surface variants
|
|
210
|
-
'--color-background-card': ld(
|
|
211
|
-
'--color-background-popover': ld(
|
|
212
|
-
'--color-background-inverted': ld(
|
|
213
|
-
// Border
|
|
241
|
+
'--color-background-card': ld(NL[99], ND[10]),
|
|
242
|
+
'--color-background-popover': ld(NL[99], ND[20]),
|
|
243
|
+
'--color-background-inverted': ld(NL[10], ND[99]),
|
|
214
244
|
// Border
|
|
215
245
|
// Decorative hairline — not a WCAG 1.4.11 boundary. High contrast
|
|
216
246
|
// doubles the alpha so structural boundaries stay perceivable.
|
|
217
|
-
'--color-border': ld(hexWithAlpha(
|
|
247
|
+
'--color-border': ld(hexWithAlpha(NL[10], borderSubtleAlpha), hexWithAlpha(ND[95], borderSubtleAlpha)),
|
|
218
248
|
'--color-border-emphasized': borderEmphasized,
|
|
219
249
|
// Effects
|
|
220
|
-
'--color-skeleton': ld(
|
|
250
|
+
'--color-skeleton': ld(NVL[70], NVD[30]),
|
|
221
251
|
// Channel-on-body surface (ProgressBar/Slider tracks, Switch off-state).
|
|
222
252
|
// Defaults to the same NV[70]/NV[30] ramp stop as --color-skeleton.
|
|
223
|
-
'--color-track': ld(
|
|
224
|
-
'--color-shadow': ld(hexWithAlpha(
|
|
253
|
+
'--color-track': ld(NVL[70], NVD[30]),
|
|
254
|
+
'--color-shadow': ld(hexWithAlpha(NL[0], 0.1), hexWithAlpha(ND[0], 0.3)),
|
|
225
255
|
'--color-tint-hover': ld('black', 'white')
|
|
226
256
|
};
|
|
227
257
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Component style-map merging
|
|
3
|
+
*
|
|
4
|
+
* One merge rule for component overrides, shared by every layer that composes
|
|
5
|
+
* them: `extends` inheritance, generated type-scale rules, and the on-media
|
|
6
|
+
* (`onDark`/`onLight`) surfaces. Merging is per style key, so a child that
|
|
7
|
+
* restates one property of `button.base` keeps the rest of the base's.
|
|
8
|
+
*
|
|
9
|
+
* @input two ComponentStyleMaps — the base and the overrides that win
|
|
10
|
+
* @output a merged ComponentStyleMap
|
|
11
|
+
* @position packages/core/src/theme/mergeComponents.ts
|
|
12
|
+
*/
|
|
13
|
+
import type { ComponentStyleMap } from './defineTheme';
|
|
14
|
+
/**
|
|
15
|
+
* Deep-merge component style maps: `overrides` wins per style key, and every
|
|
16
|
+
* component and key the base declared that the overrides do not mention is
|
|
17
|
+
* carried through untouched.
|
|
18
|
+
*/
|
|
19
|
+
export declare function deepMergeComponents(base?: ComponentStyleMap, overrides?: ComponentStyleMap): ComponentStyleMap | undefined;
|
|
20
|
+
//# sourceMappingURL=mergeComponents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeComponents.d.ts","sourceRoot":"","sources":["../../src/theme/mergeComponents.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,CAAC,EAAE,iBAAiB,EACxB,SAAS,CAAC,EAAE,iBAAiB,GAC5B,iBAAiB,GAAG,SAAS,CAiC/B"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Component style-map merging
|
|
5
|
+
*
|
|
6
|
+
* One merge rule for component overrides, shared by every layer that composes
|
|
7
|
+
* them: `extends` inheritance, generated type-scale rules, and the on-media
|
|
8
|
+
* (`onDark`/`onLight`) surfaces. Merging is per style key, so a child that
|
|
9
|
+
* restates one property of `button.base` keeps the rest of the base's.
|
|
10
|
+
*
|
|
11
|
+
* @input two ComponentStyleMaps — the base and the overrides that win
|
|
12
|
+
* @output a merged ComponentStyleMap
|
|
13
|
+
* @position packages/core/src/theme/mergeComponents.ts
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Deep-merge component style maps: `overrides` wins per style key, and every
|
|
18
|
+
* component and key the base declared that the overrides do not mention is
|
|
19
|
+
* carried through untouched.
|
|
20
|
+
*/
|
|
21
|
+
export function deepMergeComponents(base, overrides) {
|
|
22
|
+
if (!base && !overrides) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
if (!base) {
|
|
26
|
+
return overrides;
|
|
27
|
+
}
|
|
28
|
+
if (!overrides) {
|
|
29
|
+
return base;
|
|
30
|
+
}
|
|
31
|
+
const result = {};
|
|
32
|
+
|
|
33
|
+
// Start with all base entries
|
|
34
|
+
for (const [component, rules] of Object.entries(base)) {
|
|
35
|
+
result[component] = {
|
|
36
|
+
...rules
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Merge overrides on top
|
|
41
|
+
for (const [component, rules] of Object.entries(overrides)) {
|
|
42
|
+
if (!result[component]) {
|
|
43
|
+
result[component] = {
|
|
44
|
+
...rules
|
|
45
|
+
};
|
|
46
|
+
} else {
|
|
47
|
+
for (const [key, styles] of Object.entries(rules)) {
|
|
48
|
+
result[component][key] = {
|
|
49
|
+
...result[component][key],
|
|
50
|
+
...styles
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
@@ -53,6 +53,11 @@ export declare const defaultOnLightTokens: Record<string, string>;
|
|
|
53
53
|
/**
|
|
54
54
|
* Resolve on-media overrides: merge user tokens with defaults,
|
|
55
55
|
* pass through component overrides.
|
|
56
|
+
*
|
|
57
|
+
* `base` is the already-resolved surface of a theme being extended. It sits
|
|
58
|
+
* between the defaults and this theme's own input, so a child theme inherits
|
|
59
|
+
* the surface customizations of the theme it extends instead of silently
|
|
60
|
+
* reverting them to the defaults.
|
|
56
61
|
*/
|
|
57
|
-
export declare function resolveOnMedia(surface: 'dark' | 'light', input?: OnMediaOverrides): ResolvedOnMedia;
|
|
62
|
+
export declare function resolveOnMedia(surface: 'dark' | 'light', input?: OnMediaOverrides, base?: ResolvedOnMedia): ResolvedOnMedia;
|
|
58
63
|
//# sourceMappingURL=onMediaTokens.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onMediaTokens.d.ts","sourceRoot":"","sources":["../../src/theme/onMediaTokens.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAC,UAAU,EAAE,iBAAiB,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"onMediaTokens.d.ts","sourceRoot":"","sources":["../../src/theme/onMediaTokens.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAC,UAAU,EAAE,iBAAiB,EAAC,MAAM,eAAe,CAAC;AAGjE;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAC7C,yDAAyD;IACzD,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,yDAAyD;IACzD,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAStD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CASvD,CAAC;AAYF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,GAAG,OAAO,EACzB,KAAK,CAAC,EAAE,gBAAgB,EACxB,IAAI,CAAC,EAAE,eAAe,GACrB,eAAe,CAkBjB"}
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
* `onDark`/`onLight` fields in `defineTheme()`.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
import { deepMergeComponents } from "./mergeComponents.js";
|
|
24
|
+
|
|
23
25
|
/**
|
|
24
26
|
* On-media theme overrides — same shape as the main theme but scoped
|
|
25
27
|
* to a surface luminance context.
|
|
@@ -71,11 +73,17 @@ function resolveValue(value) {
|
|
|
71
73
|
/**
|
|
72
74
|
* Resolve on-media overrides: merge user tokens with defaults,
|
|
73
75
|
* pass through component overrides.
|
|
76
|
+
*
|
|
77
|
+
* `base` is the already-resolved surface of a theme being extended. It sits
|
|
78
|
+
* between the defaults and this theme's own input, so a child theme inherits
|
|
79
|
+
* the surface customizations of the theme it extends instead of silently
|
|
80
|
+
* reverting them to the defaults.
|
|
74
81
|
*/
|
|
75
|
-
export function resolveOnMedia(surface, input) {
|
|
82
|
+
export function resolveOnMedia(surface, input, base) {
|
|
76
83
|
const defaults = surface === 'dark' ? defaultOnDarkTokens : defaultOnLightTokens;
|
|
77
84
|
const tokens = {
|
|
78
|
-
...defaults
|
|
85
|
+
...defaults,
|
|
86
|
+
...base?.tokens
|
|
79
87
|
};
|
|
80
88
|
if (input?.tokens) {
|
|
81
89
|
for (const [key, value] of Object.entries(input.tokens)) {
|
|
@@ -86,6 +94,6 @@ export function resolveOnMedia(surface, input) {
|
|
|
86
94
|
}
|
|
87
95
|
return {
|
|
88
96
|
tokens,
|
|
89
|
-
components: input?.components
|
|
97
|
+
components: deepMergeComponents(base?.components, input?.components)
|
|
90
98
|
};
|
|
91
99
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Number of characters in a string — the count a person would give, where one
|
|
3
|
+
* emoji, flag, or accented letter is one character. Replacement for `.length`
|
|
4
|
+
* on user-visible strings, which counts internal storage units instead.
|
|
5
|
+
*/
|
|
6
|
+
export declare function characterCount(str: string): number;
|
|
7
|
+
/**
|
|
8
|
+
* The first character of a string, or '' when empty. Replacement for
|
|
9
|
+
* `.charAt(0)`, which can return half of an emoji. Reads only the first
|
|
10
|
+
* character, so cost does not scale with the length of the string.
|
|
11
|
+
*/
|
|
12
|
+
export declare function firstCharacter(str: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Truncate to at most `max` characters, ellipsis included: strings within
|
|
15
|
+
* `max` characters pass through unchanged; longer strings are cut so the
|
|
16
|
+
* result — content plus `ellipsis` — is exactly `max` characters (or just the
|
|
17
|
+
* ellipsis, when `max` is smaller than the ellipsis itself). Replacement for
|
|
18
|
+
* `str.slice(0, n) + '…'`, which can cut an emoji in half.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```
|
|
22
|
+
* truncateCharacters('abcdefghij', 5) // 'abcd…'
|
|
23
|
+
* truncateCharacters('abcdefghij', 8, '...') // 'abcde...'
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function truncateCharacters(str: string, max: number, ellipsis?: string): string;
|
|
27
|
+
//# sourceMappingURL=characters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"characters.d.ts","sourceRoot":"","sources":["../../src/utils/characters.ts"],"names":[],"mappings":"AAqCA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,QAAQ,SAAM,GACb,MAAM,CAOR"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file characters.ts
|
|
5
|
+
* @input Strings that may contain characters made of several code units
|
|
6
|
+
* (emoji, flags, joined emoji sequences, accented letters)
|
|
7
|
+
* @output Exports characterCount, firstCharacter, truncateCharacters —
|
|
8
|
+
* replacements for .length / .charAt(0) / .slice(0, n) that measure
|
|
9
|
+
* and cut user-visible strings the way a person reads them
|
|
10
|
+
* @position Shared utility; consumed by Avatar, TextArea, PowerSearch, Table
|
|
11
|
+
*
|
|
12
|
+
* SYNC: When modified, update:
|
|
13
|
+
* - /packages/core/src/utils/characters.test.ts
|
|
14
|
+
* - /packages/core/src/utils/index.ts
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Reuse a single segmenter when the runtime supports Intl.Segmenter.
|
|
19
|
+
* `grapheme` is the Intl granularity name for a user-perceived character.
|
|
20
|
+
*/
|
|
21
|
+
const characterSegmenter = typeof Intl.Segmenter === 'function' ? new Intl.Segmenter(undefined, {
|
|
22
|
+
granularity: 'grapheme'
|
|
23
|
+
}) : null;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Split a string into user-perceived characters. The code-point fallback
|
|
27
|
+
* keeps surrogate pairs intact but may split joined emoji sequences and flag
|
|
28
|
+
* pairs on runtimes without Intl.Segmenter.
|
|
29
|
+
*/
|
|
30
|
+
function splitCharacters(str) {
|
|
31
|
+
if (characterSegmenter) {
|
|
32
|
+
return [...characterSegmenter.segment(str)].map(s => s.segment);
|
|
33
|
+
}
|
|
34
|
+
return [...str];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Number of characters in a string — the count a person would give, where one
|
|
39
|
+
* emoji, flag, or accented letter is one character. Replacement for `.length`
|
|
40
|
+
* on user-visible strings, which counts internal storage units instead.
|
|
41
|
+
*/
|
|
42
|
+
export function characterCount(str) {
|
|
43
|
+
if (str === '') {
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
return splitCharacters(str).length;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The first character of a string, or '' when empty. Replacement for
|
|
51
|
+
* `.charAt(0)`, which can return half of an emoji. Reads only the first
|
|
52
|
+
* character, so cost does not scale with the length of the string.
|
|
53
|
+
*/
|
|
54
|
+
export function firstCharacter(str) {
|
|
55
|
+
if (characterSegmenter) {
|
|
56
|
+
const first = characterSegmenter.segment(str)[Symbol.iterator]().next();
|
|
57
|
+
return first.done ? '' : first.value.segment;
|
|
58
|
+
}
|
|
59
|
+
const codePoint = str.codePointAt(0);
|
|
60
|
+
return codePoint == null ? '' : String.fromCodePoint(codePoint);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Truncate to at most `max` characters, ellipsis included: strings within
|
|
65
|
+
* `max` characters pass through unchanged; longer strings are cut so the
|
|
66
|
+
* result — content plus `ellipsis` — is exactly `max` characters (or just the
|
|
67
|
+
* ellipsis, when `max` is smaller than the ellipsis itself). Replacement for
|
|
68
|
+
* `str.slice(0, n) + '…'`, which can cut an emoji in half.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```
|
|
72
|
+
* truncateCharacters('abcdefghij', 5) // 'abcd…'
|
|
73
|
+
* truncateCharacters('abcdefghij', 8, '...') // 'abcde...'
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function truncateCharacters(str, max, ellipsis = '…') {
|
|
77
|
+
const characters = splitCharacters(str);
|
|
78
|
+
if (characters.length <= max) {
|
|
79
|
+
return str;
|
|
80
|
+
}
|
|
81
|
+
const keep = Math.max(max - characterCount(ellipsis), 0);
|
|
82
|
+
return characters.slice(0, keep).join('') + ellipsis;
|
|
83
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { parseISOTime, formatISOTime, formatDisplayTime12h, formatDisplayTime24h
|
|
|
13
13
|
export type { ISOTimeString, ParsedTime } from './timeParser';
|
|
14
14
|
export { parseStyleKey } from './parseStyleKey';
|
|
15
15
|
export { getKey, type Key, type KeyFallback } from './getKey';
|
|
16
|
+
export { characterCount, firstCharacter, truncateCharacters } from './characters';
|
|
16
17
|
export { mergeProps } from './mergeProps';
|
|
17
18
|
export { mergeRefs } from './mergeRefs';
|
|
18
19
|
export { isFocusDetached } from './focusReturn';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,YAAY,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAEvC,YAAY,EAAC,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAC,MAAM,aAAa,CAAC;AAEhF,OAAO,EACL,cAAc,EACd,SAAS,EACT,QAAQ,EACR,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,8BAA8B,EAC9B,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,8BAA8B,EAC9B,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAC,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAElD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,aAAa,EACb,SAAS,EACT,UAAU,EACV,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAC,aAAa,EAAE,UAAU,EAAC,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,MAAM,EAAE,KAAK,GAAG,EAAE,KAAK,WAAW,EAAC,MAAM,UAAU,CAAC;AAE5D,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AACxC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAC,UAAU,EAAE,mBAAmB,EAAC,MAAM,cAAc,CAAC;AAC7D,YAAY,EACV,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,UAAU,EAAE,YAAY,EAAC,MAAM,cAAc,CAAC;AACtD,YAAY,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAC,aAAa,EAAE,eAAe,EAAC,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AACzC,YAAY,EAAC,SAAS,EAAE,mBAAmB,EAAC,MAAM,aAAa,CAAC;AAEhE,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,YAAY,EAAC,IAAI,EAAC,MAAM,SAAS,CAAC;AAElC,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAItC,OAAO,EAAC,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,YAAY,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAEvC,YAAY,EAAC,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAC,MAAM,aAAa,CAAC;AAEhF,OAAO,EACL,cAAc,EACd,SAAS,EACT,QAAQ,EACR,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,8BAA8B,EAC9B,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,8BAA8B,EAC9B,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAC,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAElD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,aAAa,EACb,SAAS,EACT,UAAU,EACV,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAC,aAAa,EAAE,UAAU,EAAC,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,MAAM,EAAE,KAAK,GAAG,EAAE,KAAK,WAAW,EAAC,MAAM,UAAU,CAAC;AAE5D,OAAO,EAAC,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAC,MAAM,cAAc,CAAC;AAEhF,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AACxC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAC,UAAU,EAAE,mBAAmB,EAAC,MAAM,cAAc,CAAC;AAC7D,YAAY,EACV,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,UAAU,EAAE,YAAY,EAAC,MAAM,cAAc,CAAC;AACtD,YAAY,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAC,aAAa,EAAE,eAAe,EAAC,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AACzC,YAAY,EAAC,SAAS,EAAE,mBAAmB,EAAC,MAAM,aAAa,CAAC;AAEhE,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,YAAY,EAAC,IAAI,EAAC,MAAM,SAAS,CAAC;AAElC,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAItC,OAAO,EAAC,kBAAkB,EAAE,iBAAiB,EAAC,MAAM,uBAAuB,CAAC"}
|
package/dist/utils/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export { plainDateCreate, plainDateFromISO, plainDateToISO, plainDateToDate, pla
|
|
|
12
12
|
export { parseISOTime, formatISOTime, formatDisplayTime12h, formatDisplayTime24h, parseTimeInput, compareTime, isTimeInRange, clampTime, adjustTime, createISOTimeString } from "./timeParser.js";
|
|
13
13
|
export { parseStyleKey } from "./parseStyleKey.js";
|
|
14
14
|
export { getKey } from "./getKey.js";
|
|
15
|
+
export { characterCount, firstCharacter, truncateCharacters } from "./characters.js";
|
|
15
16
|
export { mergeProps } from "./mergeProps.js";
|
|
16
17
|
export { mergeRefs } from "./mergeRefs.js";
|
|
17
18
|
export { isFocusDetached } from "./focusReturn.js";
|