@happyvertical/smrt-ui 0.55.16 → 0.55.18
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/AGENTS.md +14 -0
- package/README.md +75 -0
- package/dist/components/calendar/Calendar.svelte +59 -56
- package/dist/components/calendar/CalendarView.svelte +80 -77
- package/dist/components/calendar/DayView.svelte +39 -36
- package/dist/components/chat/MessageBubble.svelte +26 -23
- package/dist/components/chat/ReactionPicker.svelte +12 -9
- package/dist/components/chat/TypingIndicator.svelte +12 -9
- package/dist/components/data/CollectionList.svelte +11 -8
- package/dist/components/data/CollectionToolbar.svelte +5 -2
- package/dist/components/data/DataTable.svelte +74 -59
- package/dist/components/data/ListSortSelect.svelte +8 -5
- package/dist/components/data/SortableHeader.svelte +10 -7
- package/dist/components/display/ConfidenceBadge.svelte +11 -8
- package/dist/components/display/CurrencyDisplay.svelte +7 -4
- package/dist/components/display/DateDisplay.svelte +6 -3
- package/dist/components/display/Icon.svelte +4 -1
- package/dist/components/display/StatusBadge.svelte +9 -6
- package/dist/components/feedback/Alert.svelte +12 -8
- package/dist/components/feedback/ConfirmDialog.svelte +13 -10
- package/dist/components/feedback/LoadingOverlay.svelte +37 -34
- package/dist/components/feedback/Meter.svelte +4 -1
- package/dist/components/feedback/Modal.svelte +26 -21
- package/dist/components/feedback/PhoneSheet.svelte +6 -3
- package/dist/components/feedback/Progress.svelte +8 -5
- package/dist/components/feedback/ProgressBar.svelte +13 -10
- package/dist/components/feedback/Spinner.svelte +4 -1
- package/dist/components/feedback/ToastViewport.svelte +18 -15
- package/dist/components/feedback/WorkingStrip.svelte +6 -3
- package/dist/components/forms/CameraCapture.svelte +8 -5
- package/dist/components/forms/Checkbox.svelte +11 -8
- package/dist/components/forms/Combobox.svelte +5 -2
- package/dist/components/forms/DatePicker.svelte +7 -2
- package/dist/components/forms/DictationButton.svelte +17 -14
- package/dist/components/forms/DictationStatus.svelte +12 -9
- package/dist/components/forms/ErrorSummary.svelte +4 -1
- package/dist/components/forms/FieldLabel.svelte +9 -6
- package/dist/components/forms/Fieldset.svelte +4 -1
- package/dist/components/forms/FilePicker.svelte +5 -2
- package/dist/components/forms/Form.svelte +1 -1
- package/dist/components/forms/FormActionBar.svelte +4 -1
- package/dist/components/forms/FormGroup.svelte +6 -3
- package/dist/components/forms/Input.svelte +22 -15
- package/dist/components/forms/InputGroup.svelte +6 -3
- package/dist/components/forms/Listbox.svelte +5 -2
- package/dist/components/forms/MultiSelect.svelte +4 -1
- package/dist/components/forms/Radio.svelte +9 -6
- package/dist/components/forms/RadioGroup.svelte +5 -2
- package/dist/components/forms/RangeSlider.svelte +5 -2
- package/dist/components/forms/RelationInput.svelte +7 -4
- package/dist/components/forms/SearchInput.svelte +7 -4
- package/dist/components/forms/SegmentedControl.svelte +6 -3
- package/dist/components/forms/Select.svelte +20 -13
- package/dist/components/forms/SignaturePad.svelte +8 -5
- package/dist/components/forms/Slider.svelte +5 -2
- package/dist/components/forms/StagedControlReview.svelte +15 -12
- package/dist/components/forms/Switch.svelte +8 -5
- package/dist/components/forms/TagsInput.svelte +5 -2
- package/dist/components/forms/Textarea.svelte +20 -13
- package/dist/components/forms/TimePicker.svelte +7 -2
- package/dist/components/forms/Toggle.svelte +14 -11
- package/dist/components/forms/ToggleButton.svelte +5 -2
- package/dist/components/layout/ActionGroup.svelte +4 -1
- package/dist/components/layout/Container.svelte +4 -1
- package/dist/components/layout/EmptyState.svelte +11 -8
- package/dist/components/layout/Footer.svelte +4 -1
- package/dist/components/layout/Grid.svelte +13 -10
- package/dist/components/layout/Header.svelte +4 -1
- package/dist/components/layout/Masthead.svelte +4 -1
- package/dist/components/layout/PageHeader.svelte +12 -9
- package/dist/components/layout/PageLayout.svelte +3 -0
- package/dist/components/layout/SummaryCard.svelte +9 -6
- package/dist/components/memberships/MembershipCard.svelte +5 -2
- package/dist/components/memberships/MembershipList.svelte +5 -2
- package/dist/components/nav/FilterChips.svelte +13 -10
- package/dist/components/nav/Tabs.svelte +75 -41
- package/dist/components/permissions/PermissionPicker.svelte +5 -2
- package/dist/components/roles/RoleBadge.svelte +8 -5
- package/dist/components/roles/RoleSelector.svelte +22 -19
- package/dist/components/theme/ThemeProvider.svelte +7 -4
- package/dist/components/ui/Accordion.svelte +4 -1
- package/dist/components/ui/AccordionItem.svelte +5 -2
- package/dist/components/ui/Avatar.svelte +10 -7
- package/dist/components/ui/Badge.svelte +6 -2
- package/dist/components/ui/Button.svelte +49 -37
- package/dist/components/ui/Card.svelte +18 -14
- package/dist/components/ui/Chip.svelte +41 -14
- package/dist/components/ui/Disclosure.svelte +5 -2
- package/dist/components/ui/Dropdown.svelte +33 -25
- package/dist/components/ui/IconToggle.svelte +12 -9
- package/dist/components/ui/IconToggle.svelte.d.ts +1 -1
- package/dist/components/ui/IconToggle.svelte.d.ts.map +1 -1
- package/dist/components/ui/IconToggleGroup.svelte +8 -5
- package/dist/components/ui/Pagination.svelte +11 -8
- package/dist/components/ui/Popover.svelte +9 -6
- package/dist/components/ui/Skeleton.svelte +10 -7
- package/dist/components/ui/Tooltip.svelte +13 -9
- package/dist/components/ui/Tree.svelte +12 -9
- package/dist/styles/layers.css +8 -0
- package/dist/styles/layers.d.ts +9 -0
- package/dist/styles/layers.d.ts.map +1 -0
- package/dist/styles/layers.js +8 -0
- package/dist/styles/tokens.css +27 -69
- package/dist/styles/unstyled.css +65 -0
- package/dist/svelte/playground/BaseControlsPreview.svelte +3 -0
- package/dist/svelte/playground/CalendarPreview.svelte +5 -2
- package/dist/svelte/playground/CapturePreview.svelte +3 -0
- package/dist/svelte/playground/CodeSelectorsPreview.svelte +3 -0
- package/dist/svelte/playground/CollectionsPreview.svelte +3 -0
- package/dist/svelte/playground/DataTablePreview.svelte +3 -0
- package/dist/svelte/playground/FeedbackPreview.svelte +3 -0
- package/dist/svelte/playground/InteractiveControlsPreview.svelte +3 -0
- package/dist/svelte/playground/StylelessPreview.svelte +110 -0
- package/dist/svelte/playground/StylelessPreview.svelte.d.ts +4 -0
- package/dist/svelte/playground/StylelessPreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground.d.ts.map +1 -1
- package/dist/svelte/playground.js +10 -0
- package/dist/test-support/setup.js +9 -0
- package/dist/theme/ThemeProvider.svelte +3 -0
- package/dist/themes/CUSTOM_THEME_GUIDE.md +40 -0
- package/dist/themes/README.md +151 -0
- package/dist/themes/ThemeProvider.svelte +181 -12
- package/dist/themes/ThemeProvider.svelte.d.ts +7 -2
- package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -1
- package/dist/themes/components/ColorSchemeToggle.svelte +17 -14
- package/dist/themes/components/ThemeSwitcher.svelte +14 -11
- package/dist/themes/create-theme.d.ts +22 -1
- package/dist/themes/create-theme.d.ts.map +1 -1
- package/dist/themes/create-theme.js +100 -9
- package/dist/themes/css-generator.d.ts.map +1 -1
- package/dist/themes/css-generator.js +20 -20
- package/dist/themes/derive.d.ts +31 -0
- package/dist/themes/derive.d.ts.map +1 -0
- package/dist/themes/derive.js +183 -0
- package/dist/themes/glass/index.d.ts.map +1 -1
- package/dist/themes/glass/index.js +127 -14
- package/dist/themes/happyvertical/index.d.ts.map +1 -1
- package/dist/themes/happyvertical/index.js +101 -20
- package/dist/themes/index.d.ts +2 -2
- package/dist/themes/index.d.ts.map +1 -1
- package/dist/themes/index.js +1 -1
- package/dist/themes/material/index.d.ts.map +1 -1
- package/dist/themes/material/index.js +129 -28
- package/dist/themes/required-tokens.generated.json +201 -0
- package/dist/themes/shared.d.ts +35 -0
- package/dist/themes/shared.d.ts.map +1 -1
- package/dist/themes/shared.js +32 -0
- package/dist/themes/smrt/index.d.ts +3 -0
- package/dist/themes/smrt/index.d.ts.map +1 -1
- package/dist/themes/smrt/index.js +108 -26
- package/dist/themes/studio/index.d.ts.map +1 -1
- package/dist/themes/studio/index.js +116 -40
- package/dist/themes/styles/base.css +229 -1
- package/dist/themes/styles/glass.css +107 -20
- package/dist/themes/styles/happyvertical.css +111 -15
- package/dist/themes/styles/material.css +127 -35
- package/dist/themes/styles/smrt.css +126 -31
- package/dist/themes/styles/studio.css +132 -37
- package/dist/themes/theme-script.d.ts +3 -1
- package/dist/themes/theme-script.d.ts.map +1 -1
- package/dist/themes/theme-script.js +7 -2
- package/dist/themes/types.d.ts +118 -6
- package/dist/themes/types.d.ts.map +1 -1
- package/dist/utils/theme/typography.d.ts +21 -21
- package/dist/utils/theme/typography.js +21 -21
- package/package.json +8 -2
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Helper functions for creating custom themes that match the SMRT theme system.
|
|
5
5
|
*/
|
|
6
|
-
import { hexToRgb, rgbToHex } from '../utils/theme/color.js';
|
|
6
|
+
import { generateTheme, getContrastRatio, hexToRgb, rgbToHex, } from '../utils/theme/color.js';
|
|
7
|
+
import { baselineTokens, opaqueGlass } from './derive.js';
|
|
7
8
|
import { hasCustomTheme, registerCustomTheme, themes as registeredThemes, } from './registry.js';
|
|
8
9
|
import { borderRadiusScale, durationScale, materialEasing, spacingScale, } from './shared.js';
|
|
9
10
|
/**
|
|
@@ -22,6 +23,10 @@ const defaultColorStructure = {
|
|
|
22
23
|
onTertiary: '#ffffff',
|
|
23
24
|
tertiaryContainer: '#ede9fe',
|
|
24
25
|
onTertiaryContainer: '#3b0764',
|
|
26
|
+
info: '#8b5cf6',
|
|
27
|
+
onInfo: '#ffffff',
|
|
28
|
+
infoContainer: '#ede9fe',
|
|
29
|
+
onInfoContainer: '#3b0764',
|
|
25
30
|
error: '#dc2626',
|
|
26
31
|
onError: '#ffffff',
|
|
27
32
|
errorContainer: '#fee2e2',
|
|
@@ -86,12 +91,15 @@ function generateDarkColors(light) {
|
|
|
86
91
|
}
|
|
87
92
|
return rgbToHex(r * factor, g * factor, b * factor);
|
|
88
93
|
};
|
|
94
|
+
// Multiplying a very dark brand seed stays dark. Use tonal primary pairs so
|
|
95
|
+
// icons and labels keep contrast against their containers in dark mode.
|
|
96
|
+
const primary = generateTheme(light.primary, 'dark');
|
|
89
97
|
return {
|
|
90
98
|
...light,
|
|
91
|
-
primary:
|
|
92
|
-
onPrimary:
|
|
93
|
-
primaryContainer:
|
|
94
|
-
onPrimaryContainer:
|
|
99
|
+
primary: primary.primary,
|
|
100
|
+
onPrimary: primary.onPrimary,
|
|
101
|
+
primaryContainer: primary.primaryContainer,
|
|
102
|
+
onPrimaryContainer: primary.onPrimaryContainer,
|
|
95
103
|
secondary: adjustBrightness(light.secondary, 1.3),
|
|
96
104
|
onSecondary: adjustBrightness(light.onSecondary, 0.8),
|
|
97
105
|
secondaryContainer: adjustBrightness(light.secondaryContainer, 0.3),
|
|
@@ -234,6 +242,27 @@ function mergeTypography(custom) {
|
|
|
234
242
|
labelSmall: { ...defaults.labelSmall, ...custom.labelSmall },
|
|
235
243
|
};
|
|
236
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* The info family follows an explicitly supplied tertiary unless the caller
|
|
247
|
+
* also supplied a distinct info hue; otherwise it keeps the extended preset's
|
|
248
|
+
* (or the default) info. Presets without a distinct info hue define it as their
|
|
249
|
+
* tertiary, so a custom tertiary carries the Information status with it.
|
|
250
|
+
*/
|
|
251
|
+
function withInfoFromTertiary(palette, partial) {
|
|
252
|
+
if (partial?.tertiary === undefined)
|
|
253
|
+
return palette;
|
|
254
|
+
return {
|
|
255
|
+
...palette,
|
|
256
|
+
info: partial.info ?? palette.tertiary,
|
|
257
|
+
onInfo: partial.onInfo ?? palette.onTertiary,
|
|
258
|
+
infoContainer: partial.infoContainer ?? palette.tertiaryContainer,
|
|
259
|
+
onInfoContainer: partial.onInfoContainer ?? palette.onTertiaryContainer,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/** Drop undefined entries so they cannot clobber derived defaults. */
|
|
263
|
+
function definedOnly(value) {
|
|
264
|
+
return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined));
|
|
265
|
+
}
|
|
237
266
|
/**
|
|
238
267
|
* Create a custom theme
|
|
239
268
|
*
|
|
@@ -265,7 +294,7 @@ export function createTheme(options) {
|
|
|
265
294
|
// Get base theme if extending (lazy import to avoid circular deps)
|
|
266
295
|
const baseTheme = extend ? getBaseThemeSync(extend) : null;
|
|
267
296
|
// Build light colors
|
|
268
|
-
const lightColors = {
|
|
297
|
+
const lightColors = withInfoFromTertiary({
|
|
269
298
|
...defaultColorStructure,
|
|
270
299
|
...baseTheme?.light,
|
|
271
300
|
...lightPartial,
|
|
@@ -277,11 +306,12 @@ export function createTheme(options) {
|
|
|
277
306
|
`${normalizeHex(lightPartial.primary)}20`,
|
|
278
307
|
onPrimaryContainer: lightPartial.onPrimaryContainer || lightPartial.primary,
|
|
279
308
|
inversePrimary: lightPartial.inversePrimary || lightPartial.primary,
|
|
280
|
-
};
|
|
309
|
+
}, lightPartial);
|
|
281
310
|
// Build dark colors
|
|
282
311
|
const darkColors = darkPartial
|
|
283
|
-
? { ...lightColors, ...darkPartial }
|
|
312
|
+
? withInfoFromTertiary({ ...lightColors, ...darkPartial }, darkPartial)
|
|
284
313
|
: generateDarkColors(lightColors);
|
|
314
|
+
const baseline = baselineTokens(lightColors, darkColors);
|
|
285
315
|
return {
|
|
286
316
|
id: id,
|
|
287
317
|
name,
|
|
@@ -299,7 +329,22 @@ export function createTheme(options) {
|
|
|
299
329
|
...(baseTheme?.easing || materialEasing),
|
|
300
330
|
...options.easing,
|
|
301
331
|
},
|
|
302
|
-
glass: options.glass,
|
|
332
|
+
glass: options.glass ?? baseTheme?.glass ?? { ...opaqueGlass },
|
|
333
|
+
...baseline,
|
|
334
|
+
...definedOnly({
|
|
335
|
+
surfaces: options.surfaces,
|
|
336
|
+
hairlines: options.hairlines,
|
|
337
|
+
states: options.states && { ...baseline.states, ...options.states },
|
|
338
|
+
shadowColor: options.shadowColor,
|
|
339
|
+
controls: options.controls && {
|
|
340
|
+
...baseline.controls,
|
|
341
|
+
...options.controls,
|
|
342
|
+
},
|
|
343
|
+
focus: options.focus && { ...baseline.focus, ...options.focus },
|
|
344
|
+
native: options.native,
|
|
345
|
+
schemeDuration: options.schemeDuration,
|
|
346
|
+
fontFeatureSettings: options.fontFeatureSettings,
|
|
347
|
+
}),
|
|
303
348
|
fontFamily: options.fontFamily || baseTheme?.fontFamily || 'system-ui, sans-serif',
|
|
304
349
|
};
|
|
305
350
|
}
|
|
@@ -394,3 +439,49 @@ export function createThemeFromColor(primaryColor, id, name, options) {
|
|
|
394
439
|
});
|
|
395
440
|
}
|
|
396
441
|
// Types are exported from index.ts
|
|
442
|
+
/**
|
|
443
|
+
* Derive the primary-dependent token overrides for a user-chosen primary colour
|
|
444
|
+
* in one resolved scheme, using the same derivation as `createThemeFromColor`
|
|
445
|
+
* (light: the colour itself with a ~12.5% container; dark: the tonal primary
|
|
446
|
+
* pair from `generateTheme`). `on-primary` is the higher-contrast of white and
|
|
447
|
+
* black on the final primary so an override never leaves it mismatched. Focus,
|
|
448
|
+
* accent, caret and selection tokens follow the primary via `var()`.
|
|
449
|
+
*
|
|
450
|
+
* Returns `--smrt-*` declarations; throws on an unparseable colour.
|
|
451
|
+
*/
|
|
452
|
+
export function derivePrimaryOverrides(color, scheme) {
|
|
453
|
+
const seed = normalizeHex(color);
|
|
454
|
+
let primary = seed;
|
|
455
|
+
let onPrimary;
|
|
456
|
+
let container = `${seed}20`;
|
|
457
|
+
let onContainer = seed;
|
|
458
|
+
if (scheme === 'dark') {
|
|
459
|
+
const tonal = generateTheme(seed, 'dark');
|
|
460
|
+
primary = tonal.primary;
|
|
461
|
+
onPrimary = tonal.onPrimary;
|
|
462
|
+
container = tonal.primaryContainer;
|
|
463
|
+
onContainer = tonal.onPrimaryContainer;
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
onPrimary = '#ffffff';
|
|
467
|
+
}
|
|
468
|
+
const bg = hexToRgb(primary);
|
|
469
|
+
const white = getContrastRatio(hexToRgb('#ffffff'), bg);
|
|
470
|
+
const black = getContrastRatio(hexToRgb('#000000'), bg);
|
|
471
|
+
const tonalOn = hexToRgb(onPrimary);
|
|
472
|
+
if (getContrastRatio(tonalOn, bg) < 4.5) {
|
|
473
|
+
onPrimary = white >= black ? '#ffffff' : '#000000';
|
|
474
|
+
}
|
|
475
|
+
return {
|
|
476
|
+
'--smrt-color-primary': primary,
|
|
477
|
+
'--smrt-color-on-primary': onPrimary,
|
|
478
|
+
'--smrt-color-primary-container': container,
|
|
479
|
+
'--smrt-color-on-primary-container': onContainer,
|
|
480
|
+
'--smrt-color-inverse-primary': seed,
|
|
481
|
+
'--smrt-focus-ring-color': 'var(--smrt-color-primary)',
|
|
482
|
+
'--smrt-accent-color': 'var(--smrt-color-primary)',
|
|
483
|
+
'--smrt-caret-color': 'var(--smrt-color-primary)',
|
|
484
|
+
'--smrt-selection-background': 'var(--smrt-color-primary-container)',
|
|
485
|
+
'--smrt-selection-color': 'var(--smrt-color-on-primary-container)',
|
|
486
|
+
};
|
|
487
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"css-generator.d.ts","sourceRoot":"","sources":["../../src/themes/css-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"css-generator.d.ts","sourceRoot":"","sources":["../../src/themes/css-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,KAAK,EAOV,KAAK,EAEN,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAgMD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,OAAO,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA+CxB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CAIR;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,OAAO,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAaR;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CAS5D"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Converts theme definitions into CSS custom properties for runtime theming.
|
|
5
5
|
* Generates CSS variables for colors, typography, spacing, elevation, etc.
|
|
6
6
|
*/
|
|
7
|
+
import { generateBaselineVariables } from './derive.js';
|
|
7
8
|
import { themes } from './registry.js';
|
|
8
9
|
import { borderRadiusAliases, durationAliases, fontFamilyAliases, fontWeightTokens, spacingAliases, zIndexTokens, } from './shared.js';
|
|
9
10
|
/**
|
|
@@ -11,7 +12,16 @@ import { borderRadiusAliases, durationAliases, fontFamilyAliases, fontWeightToke
|
|
|
11
12
|
*/
|
|
12
13
|
function generateColorVariables(colors, prefix) {
|
|
13
14
|
const vars = {};
|
|
14
|
-
|
|
15
|
+
const withInfo = {
|
|
16
|
+
...colors,
|
|
17
|
+
info: colors.info ?? colors.tertiary,
|
|
18
|
+
onInfo: colors.onInfo ?? colors.onTertiary,
|
|
19
|
+
infoContainer: colors.infoContainer ?? colors.tertiaryContainer,
|
|
20
|
+
onInfoContainer: colors.onInfoContainer ?? colors.onTertiaryContainer,
|
|
21
|
+
};
|
|
22
|
+
for (const [key, value] of Object.entries(withInfo)) {
|
|
23
|
+
if (value === undefined)
|
|
24
|
+
continue;
|
|
15
25
|
// Convert camelCase to kebab-case: primaryContainer -> primary-container
|
|
16
26
|
const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
17
27
|
vars[`${prefix}-color-${cssKey}`] = value;
|
|
@@ -29,14 +39,15 @@ function generateTypographyVariables(typography, prefix) {
|
|
|
29
39
|
vars[`${prefix}-typography-${cssKey}-line-height`] = token.lineHeight;
|
|
30
40
|
vars[`${prefix}-typography-${cssKey}-weight`] = String(token.weight);
|
|
31
41
|
vars[`${prefix}-typography-${cssKey}-tracking`] = token.tracking;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
// Always emit the longhand (issue #3826): a token without its own family
|
|
43
|
+
// inherits the theme body font, so the longhand is defined for every theme
|
|
44
|
+
// and components never depend on an unset custom property.
|
|
45
|
+
const family = token.fontFamily ?? `var(${prefix}-font-family)`;
|
|
46
|
+
vars[`${prefix}-typography-${cssKey}-font-family`] = family;
|
|
35
47
|
// Additive `font` shorthand alias (issue #1431): components use
|
|
36
48
|
// `font: var(--smrt-typography-body-medium-font)`, expecting the CSS
|
|
37
49
|
// `font` shorthand order (style variant size/line-height family). Built
|
|
38
50
|
// from the emitted longhands so it stays in sync.
|
|
39
|
-
const family = token.fontFamily ?? `var(${prefix}-font-family)`;
|
|
40
51
|
vars[`${prefix}-typography-${cssKey}-font`] =
|
|
41
52
|
`${token.weight} ${token.size}/${token.lineHeight} ${family}`;
|
|
42
53
|
}
|
|
@@ -113,19 +124,6 @@ function generateEasingVariables(easing, prefix) {
|
|
|
113
124
|
}
|
|
114
125
|
return vars;
|
|
115
126
|
}
|
|
116
|
-
/**
|
|
117
|
-
* Generate CSS custom properties for glass effects
|
|
118
|
-
*/
|
|
119
|
-
function generateGlassVariables(glass, prefix) {
|
|
120
|
-
if (!glass)
|
|
121
|
-
return {};
|
|
122
|
-
return {
|
|
123
|
-
[`${prefix}-glass-blur`]: glass.blur,
|
|
124
|
-
[`${prefix}-glass-saturation`]: glass.saturation,
|
|
125
|
-
[`${prefix}-glass-border-opacity`]: glass.borderOpacity,
|
|
126
|
-
[`${prefix}-glass-background-opacity`]: glass.backgroundOpacity,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
127
|
/**
|
|
130
128
|
* Generate helper tokens that do not vary by color scheme (issue #1431).
|
|
131
129
|
*
|
|
@@ -197,8 +195,10 @@ export function generateThemeVariables(theme, isDark, options = {}) {
|
|
|
197
195
|
...generateEasingVariables(theme.easing, prefix),
|
|
198
196
|
// Theme-independent helper tokens (mono font, named weights, z-index)
|
|
199
197
|
...generateStaticTokens(prefix, theme.fontFamilyMono),
|
|
200
|
-
//
|
|
201
|
-
|
|
198
|
+
// Premium baseline: surface ladder, hairlines, state layers, shadow colour,
|
|
199
|
+
// control geometry, focus ring, native chrome, glass, scheme motion, font
|
|
200
|
+
// features (#3865)
|
|
201
|
+
...generateBaselineVariables(theme, isDark, prefix),
|
|
202
202
|
};
|
|
203
203
|
}
|
|
204
204
|
/**
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Premium-baseline token derivation (epic #3864, issue #3865).
|
|
3
|
+
*
|
|
4
|
+
* Resolves the surface ladder, hairlines, state layers, shadow colour, control
|
|
5
|
+
* geometry, focus ring, native chrome, glass and motion/typography tokens for
|
|
6
|
+
* one theme and scheme. Presets set explicit values on `Theme`; anything a theme
|
|
7
|
+
* omits (custom themes, `createTheme()`) is derived here from its palette so
|
|
8
|
+
* every theme always defines every token.
|
|
9
|
+
*/
|
|
10
|
+
import type { ColorPalette, ControlTokens, FocusRingTokens, GlassEffects, GlassSurfaces, HairlineTokens, NativeChromeTokens, StateLayers, SurfaceLadder, Theme } from './types.js';
|
|
11
|
+
export declare const defaultStateLayers: StateLayers;
|
|
12
|
+
export declare const defaultSchemeDuration = "var(--smrt-duration-medium1)";
|
|
13
|
+
export declare const defaultFontFeatureSettings = "normal";
|
|
14
|
+
/** `rgb(r g b)` from any palette colour; black when it cannot be parsed. */
|
|
15
|
+
export declare function toRgbTriplet(color: string): string;
|
|
16
|
+
export declare function deriveSurfaces(colors: ColorPalette, isDark: boolean): SurfaceLadder;
|
|
17
|
+
export declare function deriveHairlines(isDark: boolean, prefix?: string): HairlineTokens;
|
|
18
|
+
export declare function deriveControls(prefix?: string): ControlTokens;
|
|
19
|
+
export declare function deriveFocus(prefix?: string): FocusRingTokens;
|
|
20
|
+
export declare function deriveNative(prefix?: string): NativeChromeTokens;
|
|
21
|
+
export declare function deriveGlassSurfaces(prefix?: string): GlassSurfaces;
|
|
22
|
+
/** Opaque glass default for themes that are not glass. */
|
|
23
|
+
export declare const opaqueGlass: GlassEffects;
|
|
24
|
+
/**
|
|
25
|
+
* Complete set of baseline sections derived from a palette pair. Presets spread
|
|
26
|
+
* this and override what they tune; `createTheme()` uses it directly.
|
|
27
|
+
*/
|
|
28
|
+
export declare function baselineTokens(light: ColorPalette, dark: ColorPalette): Pick<Theme, 'surfaces' | 'hairlines' | 'states' | 'shadowColor' | 'controls' | 'focus' | 'native' | 'schemeDuration' | 'fontFeatureSettings'>;
|
|
29
|
+
/** Flat `--prefix-*` map for the premium-baseline families. */
|
|
30
|
+
export declare function generateBaselineVariables(theme: Theme, isDark: boolean, prefix: string): Record<string, string>;
|
|
31
|
+
//# sourceMappingURL=derive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../src/themes/derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,eAAe,EACf,YAAY,EACZ,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,KAAK,EACN,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,kBAAkB,EAAE,WAOhC,CAAC;AAEF,eAAO,MAAM,qBAAqB,iCAAiC,CAAC;AACpE,eAAO,MAAM,0BAA0B,WAAW,CAAC;AAEnD,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,OAAO,GACd,aAAa,CAaf;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,OAAO,EACf,MAAM,SAAW,GAChB,cAAc,CAQhB;AAED,wBAAgB,cAAc,CAAC,MAAM,SAAW,GAAG,aAAa,CAS/D;AAED,wBAAgB,WAAW,CAAC,MAAM,SAAW,GAAG,eAAe,CAM9D;AAED,wBAAgB,YAAY,CAAC,MAAM,SAAW,GAAG,kBAAkB,CASlE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,SAAW,GAAG,aAAa,CAMpE;AAED,0DAA0D;AAC1D,eAAO,MAAM,WAAW,EAAE,YAAkD,CAAC;AAE7E;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,YAAY,GACjB,IAAI,CACL,KAAK,EACH,UAAU,GACV,WAAW,GACX,QAAQ,GACR,aAAa,GACb,UAAU,GACV,OAAO,GACP,QAAQ,GACR,gBAAgB,GAChB,qBAAqB,CACxB,CAkBA;AAED,+DAA+D;AAC/D,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAuExB"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Premium-baseline token derivation (epic #3864, issue #3865).
|
|
3
|
+
*
|
|
4
|
+
* Resolves the surface ladder, hairlines, state layers, shadow colour, control
|
|
5
|
+
* geometry, focus ring, native chrome, glass and motion/typography tokens for
|
|
6
|
+
* one theme and scheme. Presets set explicit values on `Theme`; anything a theme
|
|
7
|
+
* omits (custom themes, `createTheme()`) is derived here from its palette so
|
|
8
|
+
* every theme always defines every token.
|
|
9
|
+
*/
|
|
10
|
+
import { hexToRgb } from '../utils/theme/color.js';
|
|
11
|
+
import { noInsetHighlight } from './shared.js';
|
|
12
|
+
export const defaultStateLayers = {
|
|
13
|
+
hover: '0.08',
|
|
14
|
+
pressed: '0.12',
|
|
15
|
+
selected: '0.12',
|
|
16
|
+
focus: '0.12',
|
|
17
|
+
dragged: '0.16',
|
|
18
|
+
disabled: '0.38',
|
|
19
|
+
};
|
|
20
|
+
export const defaultSchemeDuration = 'var(--smrt-duration-medium1)';
|
|
21
|
+
export const defaultFontFeatureSettings = 'normal';
|
|
22
|
+
/** `rgb(r g b)` from any palette colour; black when it cannot be parsed. */
|
|
23
|
+
export function toRgbTriplet(color) {
|
|
24
|
+
try {
|
|
25
|
+
const { r, g, b } = hexToRgb(color);
|
|
26
|
+
if ([r, g, b].some((n) => Number.isNaN(n)))
|
|
27
|
+
return 'rgb(0 0 0)';
|
|
28
|
+
return `rgb(${Math.round(r)} ${Math.round(g)} ${Math.round(b)})`;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return 'rgb(0 0 0)';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function deriveSurfaces(colors, isDark) {
|
|
35
|
+
return {
|
|
36
|
+
ground: colors.background,
|
|
37
|
+
panel: colors.surface,
|
|
38
|
+
control: isDark
|
|
39
|
+
? colors.surfaceContainerHigh
|
|
40
|
+
: colors.surfaceContainerLowest,
|
|
41
|
+
raised: isDark
|
|
42
|
+
? colors.surfaceContainerHigh
|
|
43
|
+
: colors.surfaceContainerLowest,
|
|
44
|
+
sunken: isDark ? colors.surfaceContainerLowest : colors.surfaceContainer,
|
|
45
|
+
overlay: colors.scrim,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function deriveHairlines(isDark, prefix = '--smrt') {
|
|
49
|
+
return {
|
|
50
|
+
color: `color-mix(in srgb, var(${prefix}-color-on-surface) 12%, transparent)`,
|
|
51
|
+
strongColor: `color-mix(in srgb, var(${prefix}-color-on-surface) 20%, transparent)`,
|
|
52
|
+
insetHighlight: isDark
|
|
53
|
+
? 'inset 0 1px 0 rgb(255 255 255 / 0.06)'
|
|
54
|
+
: noInsetHighlight,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function deriveControls(prefix = '--smrt') {
|
|
58
|
+
return {
|
|
59
|
+
radius: `var(${prefix}-radius-md)`,
|
|
60
|
+
radiusSmall: `var(${prefix}-radius-sm)`,
|
|
61
|
+
height: '2.75rem',
|
|
62
|
+
heightSmall: '2.25rem',
|
|
63
|
+
weight: '500',
|
|
64
|
+
border: `var(${prefix}-hairline-strong)`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function deriveFocus(prefix = '--smrt') {
|
|
68
|
+
return {
|
|
69
|
+
color: `var(${prefix}-color-primary)`,
|
|
70
|
+
width: '2px',
|
|
71
|
+
offset: '2px',
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function deriveNative(prefix = '--smrt') {
|
|
75
|
+
return {
|
|
76
|
+
accent: `var(${prefix}-color-primary)`,
|
|
77
|
+
selectionBackground: `var(${prefix}-color-primary-container)`,
|
|
78
|
+
selectionColor: `var(${prefix}-color-on-primary-container)`,
|
|
79
|
+
caret: `var(${prefix}-color-primary)`,
|
|
80
|
+
scrollbarThumb: `var(${prefix}-hairline-strong-color)`,
|
|
81
|
+
scrollbarTrack: 'transparent',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function deriveGlassSurfaces(prefix = '--smrt') {
|
|
85
|
+
return {
|
|
86
|
+
surface: `var(${prefix}-surface-panel)`,
|
|
87
|
+
surfaceStrong: `var(${prefix}-surface-raised)`,
|
|
88
|
+
border: `var(${prefix}-hairline-color)`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Opaque glass default for themes that are not glass. */
|
|
92
|
+
export const opaqueGlass = { blur: '0px', saturation: '100%' };
|
|
93
|
+
/**
|
|
94
|
+
* Complete set of baseline sections derived from a palette pair. Presets spread
|
|
95
|
+
* this and override what they tune; `createTheme()` uses it directly.
|
|
96
|
+
*/
|
|
97
|
+
export function baselineTokens(light, dark) {
|
|
98
|
+
return {
|
|
99
|
+
surfaces: {
|
|
100
|
+
light: deriveSurfaces(light, false),
|
|
101
|
+
dark: deriveSurfaces(dark, true),
|
|
102
|
+
},
|
|
103
|
+
hairlines: { light: deriveHairlines(false), dark: deriveHairlines(true) },
|
|
104
|
+
states: { ...defaultStateLayers },
|
|
105
|
+
shadowColor: {
|
|
106
|
+
light: toRgbTriplet(light.shadow),
|
|
107
|
+
dark: toRgbTriplet(dark.shadow),
|
|
108
|
+
},
|
|
109
|
+
controls: deriveControls(),
|
|
110
|
+
focus: deriveFocus(),
|
|
111
|
+
native: { light: deriveNative(), dark: deriveNative() },
|
|
112
|
+
schemeDuration: defaultSchemeDuration,
|
|
113
|
+
fontFeatureSettings: defaultFontFeatureSettings,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/** Flat `--prefix-*` map for the premium-baseline families. */
|
|
117
|
+
export function generateBaselineVariables(theme, isDark, prefix) {
|
|
118
|
+
const scheme = isDark ? 'dark' : 'light';
|
|
119
|
+
const colors = isDark ? theme.dark : theme.light;
|
|
120
|
+
const surfaces = theme.surfaces?.[scheme] ?? deriveSurfaces(colors, isDark);
|
|
121
|
+
const hairlines = theme.hairlines?.[scheme] ?? deriveHairlines(isDark, prefix);
|
|
122
|
+
const states = { ...defaultStateLayers, ...theme.states };
|
|
123
|
+
const controls = { ...deriveControls(prefix), ...theme.controls };
|
|
124
|
+
const focus = { ...deriveFocus(prefix), ...theme.focus };
|
|
125
|
+
const native = theme.native?.[scheme] ?? deriveNative(prefix);
|
|
126
|
+
const glass = theme.glass ?? opaqueGlass;
|
|
127
|
+
const glassSurfaces = glass.surfaces?.[scheme] ?? deriveGlassSurfaces(prefix);
|
|
128
|
+
const shadowColor = theme.shadowColor?.[scheme] ?? toRgbTriplet(colors.shadow);
|
|
129
|
+
return {
|
|
130
|
+
// Surface ladder
|
|
131
|
+
[`${prefix}-surface-ground`]: surfaces.ground,
|
|
132
|
+
[`${prefix}-surface-panel`]: surfaces.panel,
|
|
133
|
+
[`${prefix}-surface-control`]: surfaces.control,
|
|
134
|
+
[`${prefix}-surface-raised`]: surfaces.raised,
|
|
135
|
+
[`${prefix}-surface-sunken`]: surfaces.sunken,
|
|
136
|
+
[`${prefix}-surface-overlay`]: surfaces.overlay,
|
|
137
|
+
// Hairlines
|
|
138
|
+
[`${prefix}-hairline-color`]: hairlines.color,
|
|
139
|
+
[`${prefix}-hairline-strong-color`]: hairlines.strongColor,
|
|
140
|
+
[`${prefix}-hairline`]: `1px solid var(${prefix}-hairline-color)`,
|
|
141
|
+
[`${prefix}-hairline-strong`]: `1px solid var(${prefix}-hairline-strong-color)`,
|
|
142
|
+
[`${prefix}-inset-highlight`]: hairlines.insetHighlight,
|
|
143
|
+
// State layers
|
|
144
|
+
[`${prefix}-state-hover`]: states.hover,
|
|
145
|
+
[`${prefix}-state-pressed`]: states.pressed,
|
|
146
|
+
[`${prefix}-state-selected`]: states.selected,
|
|
147
|
+
[`${prefix}-state-focus`]: states.focus,
|
|
148
|
+
[`${prefix}-state-dragged`]: states.dragged,
|
|
149
|
+
[`${prefix}-state-disabled`]: states.disabled,
|
|
150
|
+
// Depth
|
|
151
|
+
[`${prefix}-shadow-color`]: shadowColor,
|
|
152
|
+
// Controls
|
|
153
|
+
[`${prefix}-control-radius`]: controls.radius,
|
|
154
|
+
[`${prefix}-control-radius-small`]: controls.radiusSmall,
|
|
155
|
+
[`${prefix}-control-height`]: controls.height,
|
|
156
|
+
[`${prefix}-control-height-small`]: controls.heightSmall,
|
|
157
|
+
[`${prefix}-control-weight`]: controls.weight,
|
|
158
|
+
[`${prefix}-control-border`]: controls.border,
|
|
159
|
+
// Focus ring
|
|
160
|
+
[`${prefix}-focus-ring-color`]: focus.color,
|
|
161
|
+
[`${prefix}-focus-ring-width`]: focus.width,
|
|
162
|
+
[`${prefix}-focus-ring-offset`]: focus.offset,
|
|
163
|
+
// Native chrome
|
|
164
|
+
[`${prefix}-accent-color`]: native.accent,
|
|
165
|
+
[`${prefix}-selection-background`]: native.selectionBackground,
|
|
166
|
+
[`${prefix}-selection-color`]: native.selectionColor,
|
|
167
|
+
[`${prefix}-caret-color`]: native.caret,
|
|
168
|
+
[`${prefix}-scrollbar-thumb`]: native.scrollbarThumb,
|
|
169
|
+
[`${prefix}-scrollbar-track`]: native.scrollbarTrack,
|
|
170
|
+
// Glass
|
|
171
|
+
[`${prefix}-glass-blur`]: glass.blur,
|
|
172
|
+
[`${prefix}-glass-saturation`]: glass.saturation,
|
|
173
|
+
[`${prefix}-glass-surface`]: glassSurfaces.surface,
|
|
174
|
+
[`${prefix}-glass-surface-strong`]: glassSurfaces.surfaceStrong,
|
|
175
|
+
[`${prefix}-glass-border`]: glassSurfaces.border,
|
|
176
|
+
// Deprecated aliases kept for one release (see GlassEffects).
|
|
177
|
+
[`${prefix}-glass-border-opacity`]: glass.borderOpacity ?? '1',
|
|
178
|
+
[`${prefix}-glass-background-opacity`]: glass.backgroundOpacity ?? '1',
|
|
179
|
+
// Motion and typography
|
|
180
|
+
[`${prefix}-duration-scheme`]: theme.schemeDuration ?? defaultSchemeDuration,
|
|
181
|
+
[`${prefix}-font-feature-settings`]: theme.fontFeatureSettings ?? defaultFontFeatureSettings,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/glass/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/glass/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,OAAO,KAAK,EAIV,KAAK,EAEN,MAAM,aAAa,CAAC;AA2XrB;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,KA2DxB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|