@happyvertical/smrt-ui 0.55.17 → 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.
Files changed (90) hide show
  1. package/README.md +7 -0
  2. package/dist/components/calendar/CalendarView.svelte +2 -2
  3. package/dist/components/chat/ReactionPicker.svelte +2 -2
  4. package/dist/components/data/CollectionList.svelte +1 -1
  5. package/dist/components/data/CollectionToolbar.svelte +1 -1
  6. package/dist/components/data/DataTable.svelte +44 -32
  7. package/dist/components/data/SortableHeader.svelte +2 -2
  8. package/dist/components/feedback/Alert.svelte +4 -3
  9. package/dist/components/feedback/LoadingOverlay.svelte +2 -2
  10. package/dist/components/feedback/Modal.svelte +11 -9
  11. package/dist/components/feedback/PhoneSheet.svelte +2 -2
  12. package/dist/components/feedback/ToastViewport.svelte +1 -1
  13. package/dist/components/forms/CameraCapture.svelte +2 -2
  14. package/dist/components/forms/Checkbox.svelte +1 -1
  15. package/dist/components/forms/Combobox.svelte +1 -1
  16. package/dist/components/forms/FilePicker.svelte +1 -1
  17. package/dist/components/forms/Input.svelte +11 -7
  18. package/dist/components/forms/InputGroup.svelte +1 -1
  19. package/dist/components/forms/Listbox.svelte +1 -1
  20. package/dist/components/forms/Radio.svelte +1 -1
  21. package/dist/components/forms/RangeSlider.svelte +1 -1
  22. package/dist/components/forms/SearchInput.svelte +2 -2
  23. package/dist/components/forms/SegmentedControl.svelte +1 -1
  24. package/dist/components/forms/Select.svelte +11 -7
  25. package/dist/components/forms/SignaturePad.svelte +2 -2
  26. package/dist/components/forms/Slider.svelte +1 -1
  27. package/dist/components/forms/StagedControlReview.svelte +1 -1
  28. package/dist/components/forms/Switch.svelte +1 -1
  29. package/dist/components/forms/TagsInput.svelte +1 -1
  30. package/dist/components/forms/Textarea.svelte +10 -6
  31. package/dist/components/forms/Toggle.svelte +2 -2
  32. package/dist/components/forms/ToggleButton.svelte +1 -1
  33. package/dist/components/layout/PageHeader.svelte +2 -2
  34. package/dist/components/nav/Tabs.svelte +47 -17
  35. package/dist/components/permissions/PermissionPicker.svelte +1 -1
  36. package/dist/components/roles/RoleSelector.svelte +2 -2
  37. package/dist/components/ui/AccordionItem.svelte +1 -1
  38. package/dist/components/ui/Badge.svelte +2 -1
  39. package/dist/components/ui/Button.svelte +38 -29
  40. package/dist/components/ui/Card.svelte +11 -10
  41. package/dist/components/ui/Chip.svelte +31 -7
  42. package/dist/components/ui/Disclosure.svelte +1 -1
  43. package/dist/components/ui/Dropdown.svelte +20 -15
  44. package/dist/components/ui/IconToggle.svelte +2 -2
  45. package/dist/components/ui/Popover.svelte +4 -4
  46. package/dist/components/ui/Tooltip.svelte +1 -0
  47. package/dist/components/ui/Tree.svelte +2 -2
  48. package/dist/themes/CUSTOM_THEME_GUIDE.md +15 -0
  49. package/dist/themes/README.md +126 -0
  50. package/dist/themes/ThemeProvider.svelte +173 -13
  51. package/dist/themes/ThemeProvider.svelte.d.ts +7 -2
  52. package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -1
  53. package/dist/themes/create-theme.d.ts +22 -1
  54. package/dist/themes/create-theme.d.ts.map +1 -1
  55. package/dist/themes/create-theme.js +93 -5
  56. package/dist/themes/css-generator.d.ts.map +1 -1
  57. package/dist/themes/css-generator.js +15 -16
  58. package/dist/themes/derive.d.ts +31 -0
  59. package/dist/themes/derive.d.ts.map +1 -0
  60. package/dist/themes/derive.js +183 -0
  61. package/dist/themes/glass/index.d.ts.map +1 -1
  62. package/dist/themes/glass/index.js +127 -14
  63. package/dist/themes/happyvertical/index.d.ts.map +1 -1
  64. package/dist/themes/happyvertical/index.js +101 -20
  65. package/dist/themes/index.d.ts +2 -2
  66. package/dist/themes/index.d.ts.map +1 -1
  67. package/dist/themes/index.js +1 -1
  68. package/dist/themes/material/index.d.ts.map +1 -1
  69. package/dist/themes/material/index.js +129 -28
  70. package/dist/themes/required-tokens.generated.json +29 -0
  71. package/dist/themes/shared.d.ts +35 -0
  72. package/dist/themes/shared.d.ts.map +1 -1
  73. package/dist/themes/shared.js +32 -0
  74. package/dist/themes/smrt/index.d.ts +3 -0
  75. package/dist/themes/smrt/index.d.ts.map +1 -1
  76. package/dist/themes/smrt/index.js +108 -26
  77. package/dist/themes/studio/index.d.ts.map +1 -1
  78. package/dist/themes/studio/index.js +116 -40
  79. package/dist/themes/styles/base.css +225 -0
  80. package/dist/themes/styles/glass.css +103 -19
  81. package/dist/themes/styles/happyvertical.css +104 -12
  82. package/dist/themes/styles/material.css +127 -35
  83. package/dist/themes/styles/smrt.css +122 -30
  84. package/dist/themes/styles/studio.css +128 -36
  85. package/dist/themes/theme-script.d.ts +3 -1
  86. package/dist/themes/theme-script.d.ts.map +1 -1
  87. package/dist/themes/theme-script.js +7 -2
  88. package/dist/themes/types.d.ts +118 -6
  89. package/dist/themes/types.d.ts.map +1 -1
  90. package/package.json +2 -2
@@ -59,7 +59,8 @@
59
59
  * lifting the top of the ramp past the bezel, which drops `on-surface-variant`
60
60
  * below AA on those surfaces — the wrong trade.
61
61
  */
62
- import { spacingScale } from '../shared.js';
62
+ import { baselineTokens, opaqueGlass } from '../derive.js';
63
+ import { hairlineInset, noInsetHighlight, noShadow, shadow, spacingScale, } from '../shared.js';
63
64
  /** Display family (headings, titles) — falls back when the fonts are absent. */
64
65
  const DISPLAY_FONT = '"Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif';
65
66
  /** Body/UI family. */
@@ -89,6 +90,11 @@ const lightColors = {
89
90
  onTertiary: '#ffffff',
90
91
  tertiaryContainer: '#d7e4ea',
91
92
  onTertiaryContainer: '#1b333e',
93
+ // Info - Shares the tertiary hue (no distinct info hue in this preset)
94
+ info: '#3c5a68',
95
+ onInfo: '#ffffff',
96
+ infoContainer: '#d7e4ea',
97
+ onInfoContainer: '#1b333e',
92
98
  // Error - Muted enamel-compatible red
93
99
  error: '#9b3b32',
94
100
  onError: '#ffffff',
@@ -154,6 +160,11 @@ const darkColors = {
154
160
  onTertiary: '#10262e',
155
161
  tertiaryContainer: '#1e313a',
156
162
  onTertiaryContainer: '#c6dee8',
163
+ // Info - Shares the tertiary hue (no distinct info hue in this preset)
164
+ info: '#9cbecc',
165
+ onInfo: '#10262e',
166
+ infoContainer: '#1e313a',
167
+ onInfoContainer: '#c6dee8',
157
168
  // Error
158
169
  error: '#e89b92',
159
170
  onError: '#3b120d',
@@ -313,31 +324,49 @@ const typography = {
313
324
  /**
314
325
  * Day Shift elevation (light) — flat with hairline bezels.
315
326
  *
316
- * Level 1 is the hairline itself; levels 2+ add the minimum soft shadow that
317
- * still separates an overlay from the panel underneath. Closer to studio than
318
- * to material — a raised faceplate, not a floating card.
327
+ * Level 1 is the bezel hairline itself; levels 2+ add the minimum two-layer
328
+ * shadow that still separates an overlay from the panel underneath. Closer to
329
+ * studio than to material — a raised faceplate, not a floating card.
319
330
  */
320
331
  const elevation = {
321
- 0: 'none',
322
- 1: 'inset 0 0 0 1px rgba(32, 39, 43, 0.1)',
323
- 2: '0 1px 2px 0 rgba(32, 39, 43, 0.06)',
324
- 3: '0 2px 6px -2px rgba(32, 39, 43, 0.1)',
325
- 4: '0 6px 16px -6px rgba(32, 39, 43, 0.14)',
326
- 5: '0 12px 28px -12px rgba(32, 39, 43, 0.18)',
332
+ 0: noShadow,
333
+ 1: hairlineInset,
334
+ 2: shadow([[1, 2, 0, 8]]),
335
+ 3: shadow([
336
+ [1, 2, 0, 8],
337
+ [2, 6, -2, 8],
338
+ ]),
339
+ 4: shadow([
340
+ [1, 3, 0, 10],
341
+ [6, 16, -6, 12],
342
+ ]),
343
+ 5: shadow([
344
+ [2, 4, 0, 10],
345
+ [12, 28, -12, 16],
346
+ ]),
327
347
  };
328
348
  /**
329
- * Day Shift elevation (dark) — a white inset hairline over black drop shadows.
330
- *
331
- * Defined here (not only in `styles/happyvertical.css`) so the JS ThemeProvider
332
- * output and the static dark CSS stay in lockstep (#1586).
349
+ * Day Shift elevation (dark) — the bezel hairline at level 1; above it the
350
+ * inset top highlight over black two-layer shadows. Defined here (not only in
351
+ * `styles/happyvertical.css`) so the JS ThemeProvider output and the static dark
352
+ * CSS stay in lockstep (#1586).
333
353
  */
334
354
  const darkElevation = {
335
- 0: 'none',
336
- 1: 'inset 0 0 0 1px rgba(228, 233, 231, 0.08)',
337
- 2: '0 1px 2px 0 rgba(0, 0, 0, 0.4)',
338
- 3: '0 2px 6px -2px rgba(0, 0, 0, 0.5)',
339
- 4: '0 6px 16px -6px rgba(0, 0, 0, 0.6)',
340
- 5: '0 12px 28px -12px rgba(0, 0, 0, 0.7)',
355
+ 0: noShadow,
356
+ 1: hairlineInset,
357
+ 2: shadow([[1, 2, 0, 40]], 'var(--smrt-inset-highlight)'),
358
+ 3: shadow([
359
+ [1, 2, 0, 40],
360
+ [2, 6, -2, 36],
361
+ ], 'var(--smrt-inset-highlight)'),
362
+ 4: shadow([
363
+ [1, 3, 0, 44],
364
+ [6, 16, -6, 44],
365
+ ], 'var(--smrt-inset-highlight)'),
366
+ 5: shadow([
367
+ [2, 4, 0, 46],
368
+ [12, 28, -12, 52],
369
+ ], 'var(--smrt-inset-highlight)'),
341
370
  };
342
371
  /**
343
372
  * Day Shift radii — the mock's restrained geometry: 6px controls, 8px panels.
@@ -396,6 +425,58 @@ export const happyverticalTheme = {
396
425
  borderRadius,
397
426
  duration,
398
427
  easing: calmEasing,
428
+ glass: { ...opaqueGlass },
429
+ ...baselineTokens(lightColors, darkColors),
430
+ // Day Shift roles: enamel ground, faceplate panels, bezel hairlines. The
431
+ // strong edge is the a11y `outline` (3:1), never the decorative bezel.
432
+ surfaces: {
433
+ light: {
434
+ ground: lightColors.background, // enamel
435
+ panel: lightColors.surface, // faceplate
436
+ control: lightColors.surfaceContainerLowest,
437
+ raised: lightColors.surface, // faceplate; the bezel hairline lifts it
438
+ sunken: lightColors.surfaceDim,
439
+ overlay: lightColors.scrim,
440
+ },
441
+ dark: {
442
+ ground: darkColors.background,
443
+ panel: darkColors.surface,
444
+ control: darkColors.surfaceContainerHigh,
445
+ raised: darkColors.surface,
446
+ sunken: darkColors.surfaceContainerLowest,
447
+ overlay: darkColors.scrim,
448
+ },
449
+ },
450
+ hairlines: {
451
+ light: {
452
+ color: 'var(--smrt-color-outline-variant)', // bezel
453
+ strongColor: 'var(--smrt-color-outline)',
454
+ insetHighlight: noInsetHighlight,
455
+ },
456
+ dark: {
457
+ color: 'var(--smrt-color-outline-variant)',
458
+ strongColor: 'var(--smrt-color-outline)',
459
+ insetHighlight: 'inset 0 1px 0 rgb(255 255 255 / 0.04)',
460
+ },
461
+ },
462
+ shadowColor: { light: 'rgb(32 39 43)', dark: 'rgb(0 0 0)' },
463
+ // Minimal state layers: calm is less to process.
464
+ states: {
465
+ hover: '0.06',
466
+ pressed: '0.10',
467
+ selected: '0.10',
468
+ focus: '0.10',
469
+ dragged: '0.12',
470
+ disabled: '0.38',
471
+ },
472
+ // The mock's 6px controls (radius md); small controls take the 4px step.
473
+ controls: {
474
+ radius: 'var(--smrt-radius-md)',
475
+ radiusSmall: 'var(--smrt-radius-sm)',
476
+ height: '2.5rem',
477
+ heightSmall: '2rem',
478
+ weight: '500',
479
+ },
399
480
  fontFamily: BODY_FONT,
400
481
  fontFamilyMono: MONO_FONT,
401
482
  };
@@ -19,12 +19,12 @@
19
19
  export { ColorSchemeToggle, ThemeSwitcher } from './components/index.js';
20
20
  export { getThemeContext, hasThemeContext, setThemeContext, tryGetThemeContext, } from './context.svelte.js';
21
21
  export type { CreateThemeOptions } from './create-theme.js';
22
- export { createTheme, createThemeFromColor, getRegisteredTheme, isThemeRegistered, preloadThemeRegistry, registerTheme, } from './create-theme.js';
22
+ export { createTheme, createThemeFromColor, derivePrimaryOverrides, getRegisteredTheme, isThemeRegistered, preloadThemeRegistry, registerTheme, } from './create-theme.js';
23
23
  export { generateAllThemesCSS, generateThemeCSS, generateThemeVariables, variablesToStyleString, } from './css-generator.js';
24
24
  export { availablePresets, getAllThemes, getTheme, getThemeName, getThemeOptions, glassTheme, happyverticalTheme, isValidPreset, materialTheme, smrtTheme, studioTheme, type ThemePresetSummary, themePresets, themes, } from './presets.js';
25
25
  export { appleEasing, borderRadiusScale, durationScale, materialEasing, spacingScale, studioEasing, } from './shared.js';
26
26
  export { default as ThemeProvider } from './ThemeProvider.svelte';
27
27
  export { type ThemeScriptOptions, themeScript } from './theme-script.js';
28
- export type { BorderRadius, BorderRadiusScale, ColorPalette, ColorScheme, CSSVariableOptions, DurationScale, EasingScale, ElevationScale, GlassEffects, ResolvedScheme, SpacingScale, Theme, ThemeConfig, ThemeContext, ThemePreset, ThemeState, TypographyScale, TypographyToken, } from './types.js';
28
+ export type { BorderRadius, BorderRadiusScale, ColorPalette, ColorScheme, ContrastPreference, CSSVariableOptions, DurationScale, EasingScale, ElevationScale, GlassEffects, ResolvedContrast, ResolvedScheme, SpacingScale, Theme, ThemeConfig, ThemeContext, ThemeDensity, ThemePreset, ThemeState, TypographyScale, TypographyToken, } from './types.js';
29
29
  export { defaultThemeConfig } from './types.js';
30
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/themes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEzE,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,SAAS,EACT,WAAW,EACX,KAAK,kBAAkB,EACvB,YAAY,EACZ,MAAM,GACP,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAAE,KAAK,kBAAkB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEzE,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,cAAc,EACd,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,KAAK,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,UAAU,EACV,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/themes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEzE,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,SAAS,EACT,WAAW,EACX,KAAK,kBAAkB,EACvB,YAAY,EACZ,MAAM,GACP,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,GACb,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAAE,KAAK,kBAAkB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEzE,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,KAAK,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,UAAU,EACV,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
@@ -21,7 +21,7 @@ export { ColorSchemeToggle, ThemeSwitcher } from './components/index.js';
21
21
  // Context
22
22
  export { getThemeContext, hasThemeContext, setThemeContext, tryGetThemeContext, } from './context.svelte.js';
23
23
  // Custom theme creation
24
- export { createTheme, createThemeFromColor, getRegisteredTheme, isThemeRegistered, preloadThemeRegistry, registerTheme, } from './create-theme.js';
24
+ export { createTheme, createThemeFromColor, derivePrimaryOverrides, getRegisteredTheme, isThemeRegistered, preloadThemeRegistry, registerTheme, } from './create-theme.js';
25
25
  // CSS generation
26
26
  export { generateAllThemesCSS, generateThemeCSS, generateThemeVariables, variablesToStyleString, } from './css-generator.js';
27
27
  // Preset data and registry (single source: ./presets.ts, Node-safe)
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/material/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAGV,KAAK,EAEN,MAAM,aAAa,CAAC;AA+QrB;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,KAY3B,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/material/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,OAAO,KAAK,EAGV,KAAK,EAEN,MAAM,aAAa,CAAC;AAoVrB;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,KA0D3B,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -4,7 +4,8 @@
4
4
  * Improved Material Design 3 theme with modern Google product aesthetics.
5
5
  * Features refined colors, updated typography, and polished elevation.
6
6
  */
7
- import { borderRadiusScale, durationScale, materialEasing, spacingScale, } from '../shared.js';
7
+ import { baselineTokens, opaqueGlass } from '../derive.js';
8
+ import { borderRadiusScale, darkInsetHighlight, durationScale, hairlineMix, materialEasing, noInsetHighlight, noShadow, shadow, spacingScale, } from '../shared.js';
8
9
  /**
9
10
  * Material light color palette
10
11
  * Refined M3 colors with slightly more vibrant accents
@@ -25,6 +26,11 @@ const lightColors = {
25
26
  onTertiary: '#ffffff',
26
27
  tertiaryContainer: '#e8ddff',
27
28
  onTertiaryContainer: '#1e005f',
29
+ // Info - Shares the tertiary hue (no distinct info hue in this preset)
30
+ info: '#7c4dff',
31
+ onInfo: '#ffffff',
32
+ infoContainer: '#e8ddff',
33
+ onInfoContainer: '#1e005f',
28
34
  // Error - Google red
29
35
  error: '#b3261e',
30
36
  onError: '#ffffff',
@@ -53,7 +59,7 @@ const lightColors = {
53
59
  surfaceDim: '#dadce0',
54
60
  surfaceBright: '#f8f9fa',
55
61
  // Background
56
- background: '#ffffff',
62
+ background: '#f6f8fc',
57
63
  onBackground: '#1f1f1f',
58
64
  // Outline
59
65
  outline: '#747775',
@@ -68,7 +74,7 @@ const lightColors = {
68
74
  };
69
75
  /**
70
76
  * Material dark color palette
71
- * True dark mode with OLED-friendly blacks
77
+ * M3 tonal dark mode: a #121316 ground with stepped container tiers
72
78
  */
73
79
  const darkColors = {
74
80
  // Primary - Lighter blue for dark mode
@@ -86,6 +92,11 @@ const darkColors = {
86
92
  onTertiary: '#3e1e96',
87
93
  tertiaryContainer: '#5e3fc0',
88
94
  onTertiaryContainer: '#e8ddff',
95
+ // Info - Shares the tertiary hue (no distinct info hue in this preset)
96
+ info: '#cbb7ff',
97
+ onInfo: '#3e1e96',
98
+ infoContainer: '#5e3fc0',
99
+ onInfoContainer: '#e8ddff',
89
100
  // Error
90
101
  error: '#f2b8b5',
91
102
  onError: '#601410',
@@ -101,20 +112,21 @@ const darkColors = {
101
112
  onSuccess: '#0d522d',
102
113
  successContainer: '#1e4620',
103
114
  onSuccessContainer: '#e6f4ea',
104
- // Surface - True dark OLED black base
105
- surface: '#0e0e0e',
115
+ // Surface - M3 tonal ladder (ground < panel < control < raised), each tier a
116
+ // visible step so depth reads from lightness and needs no borders
117
+ surface: '#1b1c20',
106
118
  onSurface: '#e3e3e3',
107
- surfaceVariant: '#1f1f1f',
119
+ surfaceVariant: '#26282c',
108
120
  onSurfaceVariant: '#c4c7c5',
109
- surfaceContainer: '#1f1f1f',
110
- surfaceContainerLow: '#141414',
111
- surfaceContainerHigh: '#2d2d2d',
112
- surfaceContainerHighest: '#363636',
113
- surfaceContainerLowest: '#0a0a0a',
114
- surfaceDim: '#141414',
115
- surfaceBright: '#2d2d2d',
121
+ surfaceContainer: '#1f2024',
122
+ surfaceContainerLow: '#17181c',
123
+ surfaceContainerHigh: '#26282c',
124
+ surfaceContainerHighest: '#34363a',
125
+ surfaceContainerLowest: '#0d0e11',
126
+ surfaceDim: '#121316',
127
+ surfaceBright: '#393b3f',
116
128
  // Background
117
- background: '#0e0e0e',
129
+ background: '#121316',
118
130
  onBackground: '#e3e3e3',
119
131
  // Outline
120
132
  outline: '#8e918f',
@@ -143,28 +155,28 @@ const typography = {
143
155
  size: '2.75rem',
144
156
  lineHeight: '1.15',
145
157
  weight: '400',
146
- tracking: '-0.01em',
158
+ tracking: '-0.015em',
147
159
  fontFamily: 'var(--smrt-font-family)',
148
160
  },
149
161
  displaySmall: {
150
162
  size: '2.25rem',
151
163
  lineHeight: '1.2',
152
164
  weight: '400',
153
- tracking: '0',
165
+ tracking: '-0.01em',
154
166
  fontFamily: 'var(--smrt-font-family)',
155
167
  },
156
168
  headlineLarge: {
157
169
  size: '2rem',
158
170
  lineHeight: '1.25',
159
171
  weight: '400',
160
- tracking: '0',
172
+ tracking: '-0.01em',
161
173
  fontFamily: 'var(--smrt-font-family)',
162
174
  },
163
175
  headlineMedium: {
164
176
  size: '1.75rem',
165
177
  lineHeight: '1.3',
166
178
  weight: '400',
167
- tracking: '0',
179
+ tracking: '-0.005em',
168
180
  fontFamily: 'var(--smrt-font-family)',
169
181
  },
170
182
  headlineSmall: {
@@ -227,28 +239,71 @@ const typography = {
227
239
  size: '0.75rem',
228
240
  lineHeight: '1.4',
229
241
  weight: '500',
230
- tracking: '0.05em',
242
+ tracking: '0.02em',
231
243
  fontFamily: 'var(--smrt-font-family)',
232
244
  },
233
245
  labelSmall: {
234
246
  size: '0.6875rem',
235
247
  lineHeight: '1.4',
236
248
  weight: '500',
237
- tracking: '0.05em',
249
+ tracking: '0.03em',
238
250
  fontFamily: 'var(--smrt-font-family)',
239
251
  },
240
252
  };
241
253
  /**
242
- * Material elevation shadows
243
- * More refined shadows with better diffusion
254
+ * Material elevation (light) — two layers per level: a contact shadow plus an
255
+ * ambient shadow with negative spread, tinted by `--smrt-shadow-color`.
244
256
  */
245
257
  const elevation = {
246
- 0: 'none',
247
- 1: '0 1px 2px 0 rgb(0 0 0 / 0.05), 0 1px 3px 0 rgb(0 0 0 / 0.02)',
248
- 2: '0 1px 2px 0 rgb(0 0 0 / 0.06), 0 2px 4px 0 rgb(0 0 0 / 0.04)',
249
- 3: '0 2px 4px 0 rgb(0 0 0 / 0.06), 0 4px 8px 0 rgb(0 0 0 / 0.04)',
250
- 4: '0 4px 8px 0 rgb(0 0 0 / 0.08), 0 8px 16px 0 rgb(0 0 0 / 0.04)',
251
- 5: '0 8px 16px 0 rgb(0 0 0 / 0.1), 0 16px 32px 0 rgb(0 0 0 / 0.04)',
258
+ 0: noShadow,
259
+ 1: shadow([
260
+ [1, 2, 0, 8],
261
+ [2, 4, -1, 6],
262
+ ]),
263
+ 2: shadow([
264
+ [1, 2, 0, 10],
265
+ [4, 8, -2, 10],
266
+ ]),
267
+ 3: shadow([
268
+ [1, 3, 0, 12],
269
+ [8, 16, -4, 12],
270
+ ]),
271
+ 4: shadow([
272
+ [2, 4, 0, 12],
273
+ [12, 24, -6, 14],
274
+ ]),
275
+ 5: shadow([
276
+ [2, 6, 0, 14],
277
+ [20, 40, -10, 18],
278
+ ]),
279
+ };
280
+ /**
281
+ * Material elevation (dark) — altitude is carried by the tonal ladder, so the
282
+ * shadows are tighter and lower in reach and every level adds the inset top
283
+ * highlight.
284
+ */
285
+ const darkElevation = {
286
+ 0: noShadow,
287
+ 1: shadow([
288
+ [1, 2, 0, 24],
289
+ [1, 3, -1, 16],
290
+ ]),
291
+ 2: shadow([
292
+ [1, 2, 0, 28],
293
+ [3, 6, -2, 20],
294
+ ], 'var(--smrt-inset-highlight)'),
295
+ 3: shadow([
296
+ [1, 3, 0, 30],
297
+ [6, 12, -3, 24],
298
+ ], 'var(--smrt-inset-highlight)'),
299
+ 4: shadow([
300
+ [2, 4, 0, 32],
301
+ [10, 20, -5, 28],
302
+ ], 'var(--smrt-inset-highlight)'),
303
+ 5: shadow([
304
+ [2, 6, 0, 34],
305
+ [16, 32, -8, 32],
306
+ ], 'var(--smrt-inset-highlight)'),
252
307
  };
253
308
  /**
254
309
  * Material theme definition
@@ -260,10 +315,56 @@ export const materialTheme = {
260
315
  dark: darkColors,
261
316
  typography,
262
317
  elevation,
318
+ darkElevation,
263
319
  spacing: spacingScale,
264
320
  borderRadius: borderRadiusScale,
265
321
  duration: durationScale,
266
322
  easing: materialEasing,
323
+ glass: { ...opaqueGlass },
324
+ ...baselineTokens(lightColors, darkColors),
325
+ shadowColor: { light: 'rgb(0 0 0)', dark: 'rgb(0 0 0)' },
326
+ // Tonal ladder: ground < panel < control < raised in dark. Light recesses the
327
+ // filled control into the white panel (M3 filled field) and lifts overlays.
328
+ surfaces: {
329
+ light: {
330
+ ground: lightColors.background,
331
+ panel: lightColors.surface,
332
+ control: lightColors.surfaceContainerHigh,
333
+ raised: lightColors.surfaceContainerLowest,
334
+ sunken: '#eef1f6',
335
+ overlay: lightColors.scrim,
336
+ },
337
+ dark: {
338
+ ground: darkColors.background,
339
+ panel: darkColors.surface,
340
+ control: darkColors.surfaceContainerHigh,
341
+ raised: darkColors.surfaceContainerHighest,
342
+ sunken: darkColors.surfaceContainerLowest,
343
+ overlay: darkColors.scrim,
344
+ },
345
+ },
346
+ hairlines: {
347
+ light: hairlineMix(10, 30, noInsetHighlight),
348
+ dark: hairlineMix(10, 30, darkInsetHighlight(0.05)),
349
+ },
350
+ // M3 state layers.
351
+ states: {
352
+ hover: '0.08',
353
+ pressed: '0.12',
354
+ selected: '0.12',
355
+ focus: '0.12',
356
+ dragged: '0.16',
357
+ disabled: '0.38',
358
+ },
359
+ // Filled controls separate by tier, not by an edge.
360
+ controls: {
361
+ radius: 'var(--smrt-radius-md)',
362
+ radiusSmall: 'var(--smrt-radius-sm)',
363
+ height: '2.75rem',
364
+ heightSmall: '2.25rem',
365
+ weight: '500',
366
+ border: '1px solid transparent',
367
+ },
267
368
  fontFamily: '"Google Sans", "Roboto", system-ui, -apple-system, sans-serif',
268
369
  };
269
370
  export default materialTheme;
@@ -41,6 +41,10 @@
41
41
  "--smrt-color-tertiary-container",
42
42
  "--smrt-color-warning",
43
43
  "--smrt-color-warning-container",
44
+ "--smrt-control-height",
45
+ "--smrt-control-height-small",
46
+ "--smrt-control-radius",
47
+ "--smrt-control-radius-small",
44
48
  "--smrt-duration-fast",
45
49
  "--smrt-duration-medium1",
46
50
  "--smrt-duration-normal",
@@ -55,8 +59,20 @@
55
59
  "--smrt-elevation-3",
56
60
  "--smrt-elevation-4",
57
61
  "--smrt-elevation-5",
62
+ "--smrt-focus-ring-color",
63
+ "--smrt-focus-ring-offset",
64
+ "--smrt-focus-ring-width",
58
65
  "--smrt-font-family",
59
66
  "--smrt-font-family-mono",
67
+ "--smrt-glass-blur",
68
+ "--smrt-glass-saturation",
69
+ "--smrt-glass-surface",
70
+ "--smrt-glass-surface-strong",
71
+ "--smrt-hairline",
72
+ "--smrt-hairline-color",
73
+ "--smrt-hairline-strong",
74
+ "--smrt-hairline-strong-color",
75
+ "--smrt-inset-highlight",
60
76
  "--smrt-radius-2xl",
61
77
  "--smrt-radius-extra-large",
62
78
  "--smrt-radius-extra-small",
@@ -68,6 +84,8 @@
68
84
  "--smrt-radius-sm",
69
85
  "--smrt-radius-small",
70
86
  "--smrt-radius-xl",
87
+ "--smrt-scrollbar-thumb",
88
+ "--smrt-scrollbar-track",
71
89
  "--smrt-spacing-0_5",
72
90
  "--smrt-spacing-1",
73
91
  "--smrt-spacing-10",
@@ -87,6 +105,17 @@
87
105
  "--smrt-spacing-sm",
88
106
  "--smrt-spacing-xl",
89
107
  "--smrt-spacing-xs",
108
+ "--smrt-state-disabled",
109
+ "--smrt-state-dragged",
110
+ "--smrt-state-hover",
111
+ "--smrt-state-pressed",
112
+ "--smrt-state-selected",
113
+ "--smrt-surface-control",
114
+ "--smrt-surface-ground",
115
+ "--smrt-surface-overlay",
116
+ "--smrt-surface-panel",
117
+ "--smrt-surface-raised",
118
+ "--smrt-surface-sunken",
90
119
  "--smrt-touch-target-min",
91
120
  "--smrt-typography-body-large-font",
92
121
  "--smrt-typography-body-large-line-height",
@@ -75,4 +75,39 @@ export declare const appleEasing: EasingScale;
75
75
  * Studio-style easings (for Studio theme - snappier)
76
76
  */
77
77
  export declare const studioEasing: EasingScale;
78
+ /**
79
+ * One shadow layer: `[offset-y, blur, spread, alpha%]`, tinted by the scheme's
80
+ * `--smrt-shadow-color` (the theme's own token, so the tint follows the preset).
81
+ */
82
+ export type ShadowLayer = readonly [
83
+ y: number,
84
+ blur: number,
85
+ spread: number,
86
+ alphaPercent: number
87
+ ];
88
+ /**
89
+ * Compose a box-shadow from layers. Elevation levels are two-layer: a contact
90
+ * shadow (`0 1px 2px`) that anchors the edge, and an ambient shadow (`0 Npx Mpx`
91
+ * with negative spread) that lifts it. `prefix` lists extra leading layers, e.g.
92
+ * `var(--smrt-inset-highlight)` on dark schemes.
93
+ */
94
+ export declare function shadow(layers: readonly ShadowLayer[], prefix?: string): string;
95
+ /** Quiet hairline inset used as elevation 1 by the flat presets. */
96
+ export declare const hairlineInset = "inset 0 0 0 1px var(--smrt-hairline-color)";
97
+ /** Text-colour mixes used for hairlines: quiet edge and strong control edge. */
98
+ export declare function hairlineMix(quietPercent: number, strongPercent: number, insetHighlight: string): {
99
+ color: string;
100
+ strongColor: string;
101
+ insetHighlight: string;
102
+ };
103
+ /**
104
+ * Neutral values that are still valid box-shadow layers. Components combine
105
+ * `var(--smrt-inset-highlight)` with an elevation (`box-shadow: a, b`); the
106
+ * keyword `none` is invalid inside a list and drops the whole declaration, so
107
+ * the "no highlight" and "no elevation" values are transparent shadows.
108
+ */
109
+ export declare const noInsetHighlight = "inset 0 1px 0 transparent";
110
+ export declare const noShadow = "0 0 0 0 transparent";
111
+ /** Top inner light line for dark surfaces (`--smrt-inset-highlight`). */
112
+ export declare const darkInsetHighlight: (alpha: number) => string;
78
113
  //# sourceMappingURL=shared.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/themes/shared.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,YAsB1B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,YAAY,CAQ7D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,iBAS/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,iBAAiB,CAMvE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,aAM3B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAalD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEpD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKnD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAW/C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,WAO5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,WAOzB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,WAO1B,CAAC"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/themes/shared.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,YAsB1B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,YAAY,CAQ7D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,iBAS/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,iBAAiB,CAMvE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,aAM3B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAalD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEpD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKnD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAW/C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,WAO5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,WAOzB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,WAO1B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS;IACjC,CAAC,EAAE,MAAM;IACT,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,MAAM;IACd,YAAY,EAAE,MAAM;CACrB,CAAC;AAKF;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAMR;AAED,oEAAoE;AACpE,eAAO,MAAM,aAAa,+CAA+C,CAAC;AAE1E,gFAAgF;AAChF,wBAAgB,WAAW,CACzB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GACrB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAMhE;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,8BAA8B,CAAC;AAC5D,eAAO,MAAM,QAAQ,wBAAwB,CAAC;AAE9C,yEAAyE;AACzE,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,KAAG,MACN,CAAC"}
@@ -177,3 +177,35 @@ export const studioEasing = {
177
177
  emphasizedDecelerate: 'cubic-bezier(0.0, 0, 0.2, 1)',
178
178
  emphasizedAccelerate: 'cubic-bezier(0.4, 0, 1, 1)',
179
179
  };
180
+ /** `px` length, `0` without a unit so the value stays valid and short. */
181
+ const px = (n) => (n === 0 ? '0' : `${n}px`);
182
+ /**
183
+ * Compose a box-shadow from layers. Elevation levels are two-layer: a contact
184
+ * shadow (`0 1px 2px`) that anchors the edge, and an ambient shadow (`0 Npx Mpx`
185
+ * with negative spread) that lifts it. `prefix` lists extra leading layers, e.g.
186
+ * `var(--smrt-inset-highlight)` on dark schemes.
187
+ */
188
+ export function shadow(layers, prefix) {
189
+ const parts = layers.map(([y, blur, spread, alpha]) => `0 ${px(y)} ${px(blur)} ${px(spread)} color-mix(in srgb, var(--smrt-shadow-color) ${alpha}%, transparent)`);
190
+ return prefix ? [prefix, ...parts].join(', ') : parts.join(', ');
191
+ }
192
+ /** Quiet hairline inset used as elevation 1 by the flat presets. */
193
+ export const hairlineInset = 'inset 0 0 0 1px var(--smrt-hairline-color)';
194
+ /** Text-colour mixes used for hairlines: quiet edge and strong control edge. */
195
+ export function hairlineMix(quietPercent, strongPercent, insetHighlight) {
196
+ return {
197
+ color: `color-mix(in srgb, var(--smrt-color-on-surface) ${quietPercent}%, transparent)`,
198
+ strongColor: `color-mix(in srgb, var(--smrt-color-on-surface) ${strongPercent}%, transparent)`,
199
+ insetHighlight,
200
+ };
201
+ }
202
+ /**
203
+ * Neutral values that are still valid box-shadow layers. Components combine
204
+ * `var(--smrt-inset-highlight)` with an elevation (`box-shadow: a, b`); the
205
+ * keyword `none` is invalid inside a list and drops the whole declaration, so
206
+ * the "no highlight" and "no elevation" values are transparent shadows.
207
+ */
208
+ export const noInsetHighlight = 'inset 0 1px 0 transparent';
209
+ export const noShadow = '0 0 0 0 transparent';
210
+ /** Top inner light line for dark surfaces (`--smrt-inset-highlight`). */
211
+ export const darkInsetHighlight = (alpha) => `inset 0 1px 0 rgb(255 255 255 / ${alpha})`;
@@ -6,6 +6,9 @@
6
6
  * accent (`#ff7a1a`), hairline outlines, deep low shadows, and a
7
7
  * Space Grotesk / Inter / JetBrains Mono type stack.
8
8
  *
9
+ * Depth is calm: two-layer shadows (contact + short ambient) and graphite surface
10
+ * lightness, never far-spread or glowing shadows.
11
+ *
9
12
  * The token palette restyles every existing smrt-ui component; the signature
10
13
  * motifs (engineering-grid background, glow, oscilloscope hairline, instrument
11
14
  * readouts, monospace technical labels) ship as opt-in utility classes in
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/smrt/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAIV,KAAK,EAEN,MAAM,aAAa,CAAC;AA4TrB;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,KAavB,CAAC;AAEF,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/smrt/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAcH,OAAO,KAAK,EAIV,KAAK,EAEN,MAAM,aAAa,CAAC;AA4WrB;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,KAyDvB,CAAC;AAEF,eAAe,SAAS,CAAC"}