@happyvertical/smrt-ui 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +50 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/dist/actions/__tests__/ripple.test.js +28 -0
- package/dist/actions/permission.d.ts +34 -0
- package/dist/actions/permission.d.ts.map +1 -0
- package/dist/actions/permission.js +70 -0
- package/dist/actions/ripple.d.ts +7 -0
- package/dist/actions/ripple.d.ts.map +1 -0
- package/dist/actions/ripple.js +65 -0
- package/dist/components/calendar/Calendar.svelte +520 -0
- package/dist/components/calendar/Calendar.svelte.d.ts +17 -0
- package/dist/components/calendar/Calendar.svelte.d.ts.map +1 -0
- package/dist/components/calendar/DayView.svelte +389 -0
- package/dist/components/calendar/DayView.svelte.d.ts +13 -0
- package/dist/components/calendar/DayView.svelte.d.ts.map +1 -0
- package/dist/components/calendar/index.d.ts +6 -0
- package/dist/components/calendar/index.d.ts.map +1 -0
- package/dist/components/calendar/index.js +5 -0
- package/dist/components/chat/MessageBubble.svelte +126 -0
- package/dist/components/chat/MessageBubble.svelte.d.ts +30 -0
- package/dist/components/chat/MessageBubble.svelte.d.ts.map +1 -0
- package/dist/components/chat/ReactionPicker.svelte +89 -0
- package/dist/components/chat/ReactionPicker.svelte.d.ts +19 -0
- package/dist/components/chat/ReactionPicker.svelte.d.ts.map +1 -0
- package/dist/components/chat/TypingIndicator.svelte +90 -0
- package/dist/components/chat/TypingIndicator.svelte.d.ts +17 -0
- package/dist/components/chat/TypingIndicator.svelte.d.ts.map +1 -0
- package/dist/components/chat/__tests__/chat-primitives.test.js +67 -0
- package/dist/components/chat/index.d.ts +10 -0
- package/dist/components/chat/index.d.ts.map +1 -0
- package/dist/components/chat/index.js +9 -0
- package/dist/components/data/DataTable.svelte +519 -0
- package/dist/components/data/DataTable.svelte.d.ts +49 -0
- package/dist/components/data/DataTable.svelte.d.ts.map +1 -0
- package/dist/components/data/__tests__/DataTable.test.js +48 -0
- package/dist/components/data/__tests__/data-table-helpers.test.js +36 -0
- package/dist/components/data/index.d.ts +6 -0
- package/dist/components/data/index.d.ts.map +1 -0
- package/dist/components/data/index.js +5 -0
- package/dist/components/data/types.d.ts +104 -0
- package/dist/components/data/types.d.ts.map +1 -0
- package/dist/components/data/types.js +45 -0
- package/dist/components/display/ConfidenceBadge.svelte +142 -0
- package/dist/components/display/ConfidenceBadge.svelte.d.ts +25 -0
- package/dist/components/display/ConfidenceBadge.svelte.d.ts.map +1 -0
- package/dist/components/display/CurrencyDisplay.svelte +106 -0
- package/dist/components/display/CurrencyDisplay.svelte.d.ts +30 -0
- package/dist/components/display/CurrencyDisplay.svelte.d.ts.map +1 -0
- package/dist/components/display/DateDisplay.svelte +122 -0
- package/dist/components/display/DateDisplay.svelte.d.ts +24 -0
- package/dist/components/display/DateDisplay.svelte.d.ts.map +1 -0
- package/dist/components/display/Icon.svelte +77 -0
- package/dist/components/display/Icon.svelte.d.ts +28 -0
- package/dist/components/display/Icon.svelte.d.ts.map +1 -0
- package/dist/components/display/StatusBadge.svelte +256 -0
- package/dist/components/display/StatusBadge.svelte.d.ts +24 -0
- package/dist/components/display/StatusBadge.svelte.d.ts.map +1 -0
- package/dist/components/display/__tests__/ConfidenceBadge.test.js +96 -0
- package/dist/components/display/__tests__/CurrencyDisplay.test.js +114 -0
- package/dist/components/display/__tests__/DateDisplay.test.js +114 -0
- package/dist/components/display/__tests__/Icon.test.js +93 -0
- package/dist/components/display/__tests__/StatusBadge.test.js +98 -0
- package/dist/components/display/index.d.ts +10 -0
- package/dist/components/display/index.d.ts.map +1 -0
- package/dist/components/display/index.js +9 -0
- package/dist/components/display/types.d.ts +5 -0
- package/dist/components/display/types.d.ts.map +1 -0
- package/dist/components/display/types.js +4 -0
- package/dist/components/feedback/ConfirmDialog.svelte +226 -0
- package/dist/components/feedback/ConfirmDialog.svelte.d.ts +25 -0
- package/dist/components/feedback/ConfirmDialog.svelte.d.ts.map +1 -0
- package/dist/components/feedback/LoadingOverlay.svelte +281 -0
- package/dist/components/feedback/LoadingOverlay.svelte.d.ts +31 -0
- package/dist/components/feedback/LoadingOverlay.svelte.d.ts.map +1 -0
- package/dist/components/feedback/Modal.svelte +393 -0
- package/dist/components/feedback/Modal.svelte.d.ts +46 -0
- package/dist/components/feedback/Modal.svelte.d.ts.map +1 -0
- package/dist/components/feedback/ProgressBar.svelte +162 -0
- package/dist/components/feedback/ProgressBar.svelte.d.ts +21 -0
- package/dist/components/feedback/ProgressBar.svelte.d.ts.map +1 -0
- package/dist/components/feedback/__tests__/ConfirmDialog.test.js +111 -0
- package/dist/components/feedback/__tests__/LoadingOverlay.test.js +99 -0
- package/dist/components/feedback/__tests__/Modal.test.js +72 -0
- package/dist/components/feedback/__tests__/ProgressBar.test.js +89 -0
- package/dist/components/feedback/index.d.ts +8 -0
- package/dist/components/feedback/index.d.ts.map +1 -0
- package/dist/components/feedback/index.js +10 -0
- package/dist/components/layout/Container.svelte +53 -0
- package/dist/components/layout/Container.svelte.d.ts +11 -0
- package/dist/components/layout/Container.svelte.d.ts.map +1 -0
- package/dist/components/layout/EmptyState.svelte +187 -0
- package/dist/components/layout/EmptyState.svelte.d.ts +28 -0
- package/dist/components/layout/EmptyState.svelte.d.ts.map +1 -0
- package/dist/components/layout/Footer.svelte +63 -0
- package/dist/components/layout/Footer.svelte.d.ts +8 -0
- package/dist/components/layout/Footer.svelte.d.ts.map +1 -0
- package/dist/components/layout/Grid.svelte +241 -0
- package/dist/components/layout/Grid.svelte.d.ts +56 -0
- package/dist/components/layout/Grid.svelte.d.ts.map +1 -0
- package/dist/components/layout/Header.svelte +86 -0
- package/dist/components/layout/Header.svelte.d.ts +9 -0
- package/dist/components/layout/Header.svelte.d.ts.map +1 -0
- package/dist/components/layout/Masthead.svelte +219 -0
- package/dist/components/layout/Masthead.svelte.d.ts +13 -0
- package/dist/components/layout/Masthead.svelte.d.ts.map +1 -0
- package/dist/components/layout/PageHeader.svelte +131 -0
- package/dist/components/layout/PageHeader.svelte.d.ts +26 -0
- package/dist/components/layout/PageHeader.svelte.d.ts.map +1 -0
- package/dist/components/layout/SummaryCard.svelte +203 -0
- package/dist/components/layout/SummaryCard.svelte.d.ts +20 -0
- package/dist/components/layout/SummaryCard.svelte.d.ts.map +1 -0
- package/dist/components/layout/__tests__/Container.test.js +62 -0
- package/dist/components/layout/__tests__/EmptyState.test.js +83 -0
- package/dist/components/layout/__tests__/Footer.test.js +50 -0
- package/dist/components/layout/__tests__/Grid.test.js +121 -0
- package/dist/components/layout/__tests__/Header.test.js +48 -0
- package/dist/components/layout/__tests__/Masthead.test.js +93 -0
- package/dist/components/layout/__tests__/PageHeader.test.js +80 -0
- package/dist/components/layout/__tests__/SummaryCard.test.js +82 -0
- package/dist/components/layout/index.d.ts +12 -0
- package/dist/components/layout/index.d.ts.map +1 -0
- package/dist/components/layout/index.js +11 -0
- package/dist/components/memberships/MembershipCard.svelte +163 -0
- package/dist/components/memberships/MembershipCard.svelte.d.ts +12 -0
- package/dist/components/memberships/MembershipCard.svelte.d.ts.map +1 -0
- package/dist/components/memberships/MembershipList.svelte +98 -0
- package/dist/components/memberships/MembershipList.svelte.d.ts +19 -0
- package/dist/components/memberships/MembershipList.svelte.d.ts.map +1 -0
- package/dist/components/nav/FilterChips.svelte +152 -0
- package/dist/components/nav/FilterChips.svelte.d.ts +19 -0
- package/dist/components/nav/FilterChips.svelte.d.ts.map +1 -0
- package/dist/components/nav/Tabs.svelte +252 -0
- package/dist/components/nav/Tabs.svelte.d.ts +34 -0
- package/dist/components/nav/Tabs.svelte.d.ts.map +1 -0
- package/dist/components/nav/__tests__/FilterChips.test.js +94 -0
- package/dist/components/nav/__tests__/Tabs.test.js +128 -0
- package/dist/components/nav/index.d.ts +7 -0
- package/dist/components/nav/index.d.ts.map +1 -0
- package/dist/components/nav/index.js +6 -0
- package/dist/components/nav/types.d.ts +24 -0
- package/dist/components/nav/types.d.ts.map +1 -0
- package/dist/components/nav/types.js +4 -0
- package/dist/components/permissions/PermissionCheck.svelte +45 -0
- package/dist/components/permissions/PermissionCheck.svelte.d.ts +19 -0
- package/dist/components/permissions/PermissionCheck.svelte.d.ts.map +1 -0
- package/dist/components/roles/RoleBadge.svelte +84 -0
- package/dist/components/roles/RoleBadge.svelte.d.ts +13 -0
- package/dist/components/roles/RoleBadge.svelte.d.ts.map +1 -0
- package/dist/components/roles/RoleSelector.svelte +216 -0
- package/dist/components/roles/RoleSelector.svelte.d.ts +13 -0
- package/dist/components/roles/RoleSelector.svelte.d.ts.map +1 -0
- package/dist/components/theme/ThemeProvider.svelte +71 -0
- package/dist/components/theme/ThemeProvider.svelte.d.ts +10 -0
- package/dist/components/theme/ThemeProvider.svelte.d.ts.map +1 -0
- package/dist/components/theme/context.svelte.d.ts +15 -0
- package/dist/components/theme/context.svelte.d.ts.map +1 -0
- package/dist/components/theme/context.svelte.js +42 -0
- package/dist/components/theme/index.d.ts +3 -0
- package/dist/components/theme/index.d.ts.map +1 -0
- package/dist/components/theme/index.js +2 -0
- package/dist/components/ui/Avatar.svelte +167 -0
- package/dist/components/ui/Avatar.svelte.d.ts +26 -0
- package/dist/components/ui/Avatar.svelte.d.ts.map +1 -0
- package/dist/components/ui/Badge.svelte +70 -0
- package/dist/components/ui/Badge.svelte.d.ts +12 -0
- package/dist/components/ui/Badge.svelte.d.ts.map +1 -0
- package/dist/components/ui/Button.svelte +226 -0
- package/dist/components/ui/Button.svelte.d.ts +28 -0
- package/dist/components/ui/Button.svelte.d.ts.map +1 -0
- package/dist/components/ui/Card.svelte +122 -0
- package/dist/components/ui/Card.svelte.d.ts +15 -0
- package/dist/components/ui/Card.svelte.d.ts.map +1 -0
- package/dist/components/ui/Chip.svelte +167 -0
- package/dist/components/ui/Chip.svelte.d.ts +33 -0
- package/dist/components/ui/Chip.svelte.d.ts.map +1 -0
- package/dist/components/ui/Dropdown.svelte +250 -0
- package/dist/components/ui/Dropdown.svelte.d.ts +20 -0
- package/dist/components/ui/Dropdown.svelte.d.ts.map +1 -0
- package/dist/components/ui/Pagination.svelte +294 -0
- package/dist/components/ui/Pagination.svelte.d.ts +21 -0
- package/dist/components/ui/Pagination.svelte.d.ts.map +1 -0
- package/dist/components/ui/Skeleton.svelte +113 -0
- package/dist/components/ui/Skeleton.svelte.d.ts +24 -0
- package/dist/components/ui/Skeleton.svelte.d.ts.map +1 -0
- package/dist/components/ui/Tooltip.svelte +120 -0
- package/dist/components/ui/Tooltip.svelte.d.ts +24 -0
- package/dist/components/ui/Tooltip.svelte.d.ts.map +1 -0
- package/dist/components/ui/Tree.svelte +209 -0
- package/dist/components/ui/Tree.svelte.d.ts +17 -0
- package/dist/components/ui/Tree.svelte.d.ts.map +1 -0
- package/dist/components/ui/__tests__/Badge.test.js +76 -0
- package/dist/components/ui/__tests__/Button.test.js +69 -0
- package/dist/components/ui/__tests__/Card.test.js +103 -0
- package/dist/components/ui/__tests__/Pagination.test.js +99 -0
- package/dist/components/ui/__tests__/gap-primitives-interactive.test.js +112 -0
- package/dist/components/ui/__tests__/gap-primitives.test.js +84 -0
- package/dist/components/ui/index.d.ts +14 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/index.js +18 -0
- package/dist/i18n/Trans.svelte +29 -0
- package/dist/i18n/Trans.svelte.d.ts +24 -0
- package/dist/i18n/Trans.svelte.d.ts.map +1 -0
- package/dist/i18n/__tests__/i18n.test.js +74 -0
- package/dist/i18n/__tests__/render-parity.spec.js +37 -0
- package/dist/i18n/context.svelte.d.ts +43 -0
- package/dist/i18n/context.svelte.d.ts.map +1 -0
- package/dist/i18n/context.svelte.js +69 -0
- package/dist/i18n/index.d.ts +17 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +24 -0
- package/dist/i18n/registry.d.ts +44 -0
- package/dist/i18n/registry.d.ts.map +1 -0
- package/dist/i18n/registry.js +60 -0
- package/dist/i18n/render.d.ts +22 -0
- package/dist/i18n/render.d.ts.map +1 -0
- package/dist/i18n/render.js +44 -0
- package/dist/i18n/strings.d.ts +7 -0
- package/dist/i18n/strings.d.ts.map +1 -0
- package/dist/i18n/strings.js +19 -0
- package/dist/i18n/strings.ui.d.ts +34 -0
- package/dist/i18n/strings.ui.d.ts.map +1 -0
- package/dist/i18n/strings.ui.js +44 -0
- package/dist/i18n/use-i18n.d.ts +20 -0
- package/dist/i18n/use-i18n.d.ts.map +1 -0
- package/dist/i18n/use-i18n.js +21 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/registry/index.d.ts +6 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +4 -0
- package/dist/registry/module-registry.d.ts +58 -0
- package/dist/registry/module-registry.d.ts.map +1 -0
- package/dist/registry/module-registry.js +94 -0
- package/dist/styles/index.d.ts +4 -0
- package/dist/styles/index.d.ts.map +1 -0
- package/dist/styles/index.js +6 -0
- package/dist/styles/tokens.css +76 -0
- package/dist/test-support/a11y.d.ts +16 -0
- package/dist/test-support/a11y.d.ts.map +1 -0
- package/dist/test-support/a11y.js +32 -0
- package/dist/test-support/setup.d.ts +11 -0
- package/dist/test-support/setup.d.ts.map +1 -0
- package/dist/test-support/setup.js +33 -0
- package/dist/theme/ThemeProvider.svelte +207 -0
- package/dist/theme/ThemeProvider.svelte.d.ts +22 -0
- package/dist/theme/ThemeProvider.svelte.d.ts.map +1 -0
- package/dist/theme/context.d.ts +49 -0
- package/dist/theme/context.d.ts.map +1 -0
- package/dist/theme/context.js +32 -0
- package/dist/theme/index.d.ts +7 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +9 -0
- package/dist/theme/tokens.d.ts +309 -0
- package/dist/theme/tokens.d.ts.map +1 -0
- package/dist/theme/tokens.js +418 -0
- package/dist/themes/CUSTOM_THEME_GUIDE.md +341 -0
- package/dist/themes/README.md +675 -0
- package/dist/themes/ThemeProvider.svelte +275 -0
- package/dist/themes/ThemeProvider.svelte.d.ts +24 -0
- package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -0
- package/dist/themes/__tests__/css-generator.test.js +32 -0
- package/dist/themes/__tests__/registry.test.js +43 -0
- package/dist/themes/__tests__/token-aliases.test.js +176 -0
- package/dist/themes/components/ColorSchemeToggle.svelte +205 -0
- package/dist/themes/components/ColorSchemeToggle.svelte.d.ts +14 -0
- package/dist/themes/components/ColorSchemeToggle.svelte.d.ts.map +1 -0
- package/dist/themes/components/ThemeSwitcher.svelte +188 -0
- package/dist/themes/components/ThemeSwitcher.svelte.d.ts +14 -0
- package/dist/themes/components/ThemeSwitcher.svelte.d.ts.map +1 -0
- package/dist/themes/components/index.d.ts +8 -0
- package/dist/themes/components/index.d.ts.map +1 -0
- package/dist/themes/components/index.js +7 -0
- package/dist/themes/context.svelte.d.ts +30 -0
- package/dist/themes/context.svelte.d.ts.map +1 -0
- package/dist/themes/context.svelte.js +42 -0
- package/dist/themes/create-theme.d.ts +99 -0
- package/dist/themes/create-theme.d.ts.map +1 -0
- package/dist/themes/create-theme.js +389 -0
- package/dist/themes/css-generator.d.ts +44 -0
- package/dist/themes/css-generator.d.ts.map +1 -0
- package/dist/themes/css-generator.js +226 -0
- package/dist/themes/glass/index.d.ts +14 -0
- package/dist/themes/glass/index.d.ts.map +1 -0
- package/dist/themes/glass/index.js +286 -0
- package/dist/themes/index.d.ts +31 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +37 -0
- package/dist/themes/material/index.d.ts +13 -0
- package/dist/themes/material/index.d.ts.map +1 -0
- package/dist/themes/material/index.js +269 -0
- package/dist/themes/registry.d.ts +64 -0
- package/dist/themes/registry.d.ts.map +1 -0
- package/dist/themes/registry.js +122 -0
- package/dist/themes/shared.d.ts +78 -0
- package/dist/themes/shared.d.ts.map +1 -0
- package/dist/themes/shared.js +179 -0
- package/dist/themes/studio/index.d.ts +14 -0
- package/dist/themes/studio/index.d.ts.map +1 -0
- package/dist/themes/studio/index.js +270 -0
- package/dist/themes/styles/all.css +12 -0
- package/dist/themes/styles/glass.css +432 -0
- package/dist/themes/styles/index.d.ts +22 -0
- package/dist/themes/styles/index.d.ts.map +1 -0
- package/dist/themes/styles/index.js +23 -0
- package/dist/themes/styles/material.css +364 -0
- package/dist/themes/styles/studio.css +416 -0
- package/dist/themes/types.d.ts +273 -0
- package/dist/themes/types.d.ts.map +1 -0
- package/dist/themes/types.js +15 -0
- package/dist/types-generic.d.ts +75 -0
- package/dist/types-generic.d.ts.map +1 -0
- package/dist/types-generic.js +1 -0
- package/dist/utils/forms/__tests__/formatters.test.js +27 -0
- package/dist/utils/forms/formatters.d.ts +14 -0
- package/dist/utils/forms/formatters.d.ts.map +1 -0
- package/dist/utils/forms/formatters.js +77 -0
- package/dist/utils/import-optional.d.ts +5 -0
- package/dist/utils/import-optional.d.ts.map +1 -0
- package/dist/utils/import-optional.js +7 -0
- package/dist/utils/theme/__tests__/color.test.js +72 -0
- package/dist/utils/theme/__tests__/typography.test.js +11 -0
- package/dist/utils/theme/color.d.ts +70 -0
- package/dist/utils/theme/color.d.ts.map +1 -0
- package/dist/utils/theme/color.js +221 -0
- package/dist/utils/theme/typography.d.ts +27 -0
- package/dist/utils/theme/typography.d.ts.map +1 -0
- package/dist/utils/theme/typography.js +30 -0
- package/package.json +143 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create Theme Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for creating custom themes that match the SMRT theme system.
|
|
5
|
+
*/
|
|
6
|
+
import { hasCustomTheme, registerCustomTheme, themes as registeredThemes, } from './registry.js';
|
|
7
|
+
import { borderRadiusScale, durationScale, materialEasing, spacingScale, } from './shared.js';
|
|
8
|
+
/**
|
|
9
|
+
* Default color palette structure with neutral grays
|
|
10
|
+
*/
|
|
11
|
+
const defaultColorStructure = {
|
|
12
|
+
// These will be generated from the primary color
|
|
13
|
+
onPrimary: '#ffffff',
|
|
14
|
+
primaryContainer: '',
|
|
15
|
+
onPrimaryContainer: '',
|
|
16
|
+
secondary: '#64748b',
|
|
17
|
+
onSecondary: '#ffffff',
|
|
18
|
+
secondaryContainer: '#f1f5f9',
|
|
19
|
+
onSecondaryContainer: '#1e293b',
|
|
20
|
+
tertiary: '#8b5cf6',
|
|
21
|
+
onTertiary: '#ffffff',
|
|
22
|
+
tertiaryContainer: '#ede9fe',
|
|
23
|
+
onTertiaryContainer: '#3b0764',
|
|
24
|
+
error: '#dc2626',
|
|
25
|
+
onError: '#ffffff',
|
|
26
|
+
errorContainer: '#fee2e2',
|
|
27
|
+
onErrorContainer: '#7f1d1d',
|
|
28
|
+
warning: '#f59e0b',
|
|
29
|
+
onWarning: '#000000',
|
|
30
|
+
warningContainer: '#fef3c7',
|
|
31
|
+
onWarningContainer: '#78350f',
|
|
32
|
+
success: '#22c55e',
|
|
33
|
+
onSuccess: '#000000',
|
|
34
|
+
successContainer: '#dcfce7',
|
|
35
|
+
onSuccessContainer: '#14532d',
|
|
36
|
+
surface: '#ffffff',
|
|
37
|
+
onSurface: '#111827',
|
|
38
|
+
surfaceVariant: '#f9fafb',
|
|
39
|
+
onSurfaceVariant: '#6b7280',
|
|
40
|
+
surfaceContainer: '#f3f4f6',
|
|
41
|
+
surfaceContainerLow: '#f9fafb',
|
|
42
|
+
surfaceContainerHigh: '#e5e7eb',
|
|
43
|
+
surfaceContainerHighest: '#d1d5db',
|
|
44
|
+
surfaceContainerLowest: '#ffffff',
|
|
45
|
+
surfaceDim: '#e5e7eb',
|
|
46
|
+
surfaceBright: '#ffffff',
|
|
47
|
+
onBackground: '#111827',
|
|
48
|
+
outline: '#d1d5db',
|
|
49
|
+
outlineVariant: '#e5e7eb',
|
|
50
|
+
inverseSurface: '#1f2937',
|
|
51
|
+
inverseOnSurface: '#f9fafb',
|
|
52
|
+
inversePrimary: '',
|
|
53
|
+
shadow: '#000000',
|
|
54
|
+
scrim: 'rgba(0, 0, 0, 0.5)',
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Helper function to clamp a value between min and max
|
|
58
|
+
*/
|
|
59
|
+
function clamp(value, min, max) {
|
|
60
|
+
return Math.min(max, Math.max(min, value));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Helper function to convert RGB component to 2-digit hex
|
|
64
|
+
*/
|
|
65
|
+
function toHexComponent(value) {
|
|
66
|
+
const clamped = Math.round(clamp(value, 0, 255));
|
|
67
|
+
return clamped.toString(16).padStart(2, '0');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Generate dark mode colors from light mode colors
|
|
71
|
+
* Uses simple inversion logic - for production use, manually define dark colors
|
|
72
|
+
*/
|
|
73
|
+
function generateDarkColors(light) {
|
|
74
|
+
// Helper to adjust color brightness with proper rounding and hex conversion
|
|
75
|
+
const adjustBrightness = (hex, factor) => {
|
|
76
|
+
// Handle 3-character hex codes
|
|
77
|
+
let fullHex = hex;
|
|
78
|
+
if (hex.length === 4 && hex[0] === '#') {
|
|
79
|
+
fullHex = `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;
|
|
80
|
+
}
|
|
81
|
+
const r = parseInt(fullHex.slice(1, 3), 16) * factor;
|
|
82
|
+
const g = parseInt(fullHex.slice(3, 5), 16) * factor;
|
|
83
|
+
const b = parseInt(fullHex.slice(5, 7), 16) * factor;
|
|
84
|
+
return `#${toHexComponent(r)}${toHexComponent(g)}${toHexComponent(b)}`;
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
...light,
|
|
88
|
+
primary: light.inversePrimary || adjustBrightness(light.primary, 1.2),
|
|
89
|
+
onPrimary: adjustBrightness(light.onPrimary, 0.8),
|
|
90
|
+
primaryContainer: adjustBrightness(light.primaryContainer || light.primary, 0.3),
|
|
91
|
+
onPrimaryContainer: adjustBrightness(light.onPrimaryContainer || light.onPrimary, 1.2),
|
|
92
|
+
secondary: adjustBrightness(light.secondary, 1.3),
|
|
93
|
+
onSecondary: adjustBrightness(light.onSecondary, 0.8),
|
|
94
|
+
secondaryContainer: adjustBrightness(light.secondaryContainer, 0.3),
|
|
95
|
+
onSecondaryContainer: adjustBrightness(light.onSecondaryContainer, 1.2),
|
|
96
|
+
surface: '#111827',
|
|
97
|
+
onSurface: '#f9fafb',
|
|
98
|
+
surfaceVariant: '#1f2937',
|
|
99
|
+
onSurfaceVariant: '#9ca3af',
|
|
100
|
+
surfaceContainer: '#1f2937',
|
|
101
|
+
surfaceContainerLow: '#111827',
|
|
102
|
+
surfaceContainerHigh: '#374151',
|
|
103
|
+
surfaceContainerHighest: '#4b5563',
|
|
104
|
+
surfaceContainerLowest: '#030712',
|
|
105
|
+
surfaceDim: '#1f2937',
|
|
106
|
+
surfaceBright: '#374151',
|
|
107
|
+
background: '#030712',
|
|
108
|
+
onBackground: '#f9fafb',
|
|
109
|
+
outline: '#4b5563',
|
|
110
|
+
outlineVariant: '#374151',
|
|
111
|
+
inverseSurface: '#f9fafb',
|
|
112
|
+
inverseOnSurface: '#1f2937',
|
|
113
|
+
inversePrimary: light.primary,
|
|
114
|
+
shadow: light.shadow,
|
|
115
|
+
scrim: 'rgba(0, 0, 0, 0.7)',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Merge typography with defaults
|
|
120
|
+
*/
|
|
121
|
+
function mergeTypography(custom) {
|
|
122
|
+
const defaults = {
|
|
123
|
+
displayLarge: {
|
|
124
|
+
size: '3.5rem',
|
|
125
|
+
lineHeight: '1.1',
|
|
126
|
+
weight: '400',
|
|
127
|
+
tracking: '-0.02em',
|
|
128
|
+
},
|
|
129
|
+
displayMedium: {
|
|
130
|
+
size: '2.75rem',
|
|
131
|
+
lineHeight: '1.15',
|
|
132
|
+
weight: '400',
|
|
133
|
+
tracking: '-0.01em',
|
|
134
|
+
},
|
|
135
|
+
displaySmall: {
|
|
136
|
+
size: '2.25rem',
|
|
137
|
+
lineHeight: '1.2',
|
|
138
|
+
weight: '400',
|
|
139
|
+
tracking: '0',
|
|
140
|
+
},
|
|
141
|
+
headlineLarge: {
|
|
142
|
+
size: '2rem',
|
|
143
|
+
lineHeight: '1.25',
|
|
144
|
+
weight: '400',
|
|
145
|
+
tracking: '0',
|
|
146
|
+
},
|
|
147
|
+
headlineMedium: {
|
|
148
|
+
size: '1.75rem',
|
|
149
|
+
lineHeight: '1.3',
|
|
150
|
+
weight: '400',
|
|
151
|
+
tracking: '0',
|
|
152
|
+
},
|
|
153
|
+
headlineSmall: {
|
|
154
|
+
size: '1.5rem',
|
|
155
|
+
lineHeight: '1.35',
|
|
156
|
+
weight: '400',
|
|
157
|
+
tracking: '0',
|
|
158
|
+
},
|
|
159
|
+
titleLarge: {
|
|
160
|
+
size: '1.375rem',
|
|
161
|
+
lineHeight: '1.4',
|
|
162
|
+
weight: '500',
|
|
163
|
+
tracking: '0',
|
|
164
|
+
},
|
|
165
|
+
titleMedium: {
|
|
166
|
+
size: '1rem',
|
|
167
|
+
lineHeight: '1.5',
|
|
168
|
+
weight: '500',
|
|
169
|
+
tracking: '0.01em',
|
|
170
|
+
},
|
|
171
|
+
titleSmall: {
|
|
172
|
+
size: '0.875rem',
|
|
173
|
+
lineHeight: '1.5',
|
|
174
|
+
weight: '500',
|
|
175
|
+
tracking: '0.01em',
|
|
176
|
+
},
|
|
177
|
+
bodyLarge: {
|
|
178
|
+
size: '1rem',
|
|
179
|
+
lineHeight: '1.5',
|
|
180
|
+
weight: '400',
|
|
181
|
+
tracking: '0.03em',
|
|
182
|
+
},
|
|
183
|
+
bodyMedium: {
|
|
184
|
+
size: '0.875rem',
|
|
185
|
+
lineHeight: '1.5',
|
|
186
|
+
weight: '400',
|
|
187
|
+
tracking: '0.02em',
|
|
188
|
+
},
|
|
189
|
+
bodySmall: {
|
|
190
|
+
size: '0.75rem',
|
|
191
|
+
lineHeight: '1.4',
|
|
192
|
+
weight: '400',
|
|
193
|
+
tracking: '0.03em',
|
|
194
|
+
},
|
|
195
|
+
labelLarge: {
|
|
196
|
+
size: '0.875rem',
|
|
197
|
+
lineHeight: '1.4',
|
|
198
|
+
weight: '500',
|
|
199
|
+
tracking: '0.01em',
|
|
200
|
+
},
|
|
201
|
+
labelMedium: {
|
|
202
|
+
size: '0.75rem',
|
|
203
|
+
lineHeight: '1.4',
|
|
204
|
+
weight: '500',
|
|
205
|
+
tracking: '0.05em',
|
|
206
|
+
},
|
|
207
|
+
labelSmall: {
|
|
208
|
+
size: '0.6875rem',
|
|
209
|
+
lineHeight: '1.4',
|
|
210
|
+
weight: '500',
|
|
211
|
+
tracking: '0.05em',
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
if (!custom)
|
|
215
|
+
return defaults;
|
|
216
|
+
return {
|
|
217
|
+
displayLarge: { ...defaults.displayLarge, ...custom.displayLarge },
|
|
218
|
+
displayMedium: { ...defaults.displayMedium, ...custom.displayMedium },
|
|
219
|
+
displaySmall: { ...defaults.displaySmall, ...custom.displaySmall },
|
|
220
|
+
headlineLarge: { ...defaults.headlineLarge, ...custom.headlineLarge },
|
|
221
|
+
headlineMedium: { ...defaults.headlineMedium, ...custom.headlineMedium },
|
|
222
|
+
headlineSmall: { ...defaults.headlineSmall, ...custom.headlineSmall },
|
|
223
|
+
titleLarge: { ...defaults.titleLarge, ...custom.titleLarge },
|
|
224
|
+
titleMedium: { ...defaults.titleMedium, ...custom.titleMedium },
|
|
225
|
+
titleSmall: { ...defaults.titleSmall, ...custom.titleSmall },
|
|
226
|
+
bodyLarge: { ...defaults.bodyLarge, ...custom.bodyLarge },
|
|
227
|
+
bodyMedium: { ...defaults.bodyMedium, ...custom.bodyMedium },
|
|
228
|
+
bodySmall: { ...defaults.bodySmall, ...custom.bodySmall },
|
|
229
|
+
labelLarge: { ...defaults.labelLarge, ...custom.labelLarge },
|
|
230
|
+
labelMedium: { ...defaults.labelMedium, ...custom.labelMedium },
|
|
231
|
+
labelSmall: { ...defaults.labelSmall, ...custom.labelSmall },
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Create a custom theme
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* import { createTheme, registerTheme } from '@happyvertical/smrt-ui/themes';
|
|
240
|
+
*
|
|
241
|
+
* const myTheme = createTheme({
|
|
242
|
+
* id: 'brand',
|
|
243
|
+
* name: 'Brand Theme',
|
|
244
|
+
* light: {
|
|
245
|
+
* primary: '#ff6b35',
|
|
246
|
+
* background: '#fafafa',
|
|
247
|
+
* surface: '#ffffff',
|
|
248
|
+
* },
|
|
249
|
+
* dark: {
|
|
250
|
+
* primary: '#ff8c5a',
|
|
251
|
+
* background: '#0a0a0a',
|
|
252
|
+
* surface: '#1a1a1a',
|
|
253
|
+
* },
|
|
254
|
+
* fontFamily: 'Inter, sans-serif',
|
|
255
|
+
* });
|
|
256
|
+
*
|
|
257
|
+
* registerTheme(myTheme);
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
export function createTheme(options) {
|
|
261
|
+
const { id, name, light: lightPartial, dark: darkPartial, extend = 'material', } = options;
|
|
262
|
+
// Get base theme if extending (lazy import to avoid circular deps)
|
|
263
|
+
const baseTheme = extend ? getBaseThemeSync(extend) : null;
|
|
264
|
+
// Build light colors
|
|
265
|
+
const lightColors = {
|
|
266
|
+
...defaultColorStructure,
|
|
267
|
+
...baseTheme?.light,
|
|
268
|
+
...lightPartial,
|
|
269
|
+
// Generate derived colors
|
|
270
|
+
primaryContainer: lightPartial.primaryContainer || `${lightPartial.primary}20`,
|
|
271
|
+
onPrimaryContainer: lightPartial.onPrimaryContainer || lightPartial.primary,
|
|
272
|
+
inversePrimary: lightPartial.inversePrimary || lightPartial.primary,
|
|
273
|
+
};
|
|
274
|
+
// Build dark colors
|
|
275
|
+
const darkColors = darkPartial
|
|
276
|
+
? { ...lightColors, ...darkPartial }
|
|
277
|
+
: generateDarkColors(lightColors);
|
|
278
|
+
return {
|
|
279
|
+
id: id,
|
|
280
|
+
name,
|
|
281
|
+
light: lightColors,
|
|
282
|
+
dark: darkColors,
|
|
283
|
+
typography: mergeTypography(options.typography),
|
|
284
|
+
elevation: {
|
|
285
|
+
...(baseTheme?.elevation || materialElevation()),
|
|
286
|
+
...options.elevation,
|
|
287
|
+
},
|
|
288
|
+
spacing: spacingScale,
|
|
289
|
+
borderRadius: borderRadiusScale,
|
|
290
|
+
duration: durationScale,
|
|
291
|
+
easing: {
|
|
292
|
+
...(baseTheme?.easing || materialEasing),
|
|
293
|
+
...options.easing,
|
|
294
|
+
},
|
|
295
|
+
glass: options.glass,
|
|
296
|
+
fontFamily: options.fontFamily || baseTheme?.fontFamily || 'system-ui, sans-serif',
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
// Cache for base themes to avoid repeated dynamic imports
|
|
300
|
+
let themeRegistryCache = null;
|
|
301
|
+
/**
|
|
302
|
+
* Get a base theme for extension - synchronous version using cache
|
|
303
|
+
* Falls back to null if registry not loaded
|
|
304
|
+
*/
|
|
305
|
+
function getBaseThemeSync(preset) {
|
|
306
|
+
if (themeRegistryCache && preset in themeRegistryCache) {
|
|
307
|
+
return themeRegistryCache[preset] || null;
|
|
308
|
+
}
|
|
309
|
+
// Return null if not in cache - will use defaults
|
|
310
|
+
// User should ensure themes are loaded before extending
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Preload the theme registry for extension support
|
|
315
|
+
* Call this before createTheme if using the extend option
|
|
316
|
+
*/
|
|
317
|
+
export async function preloadThemeRegistry() {
|
|
318
|
+
if (themeRegistryCache)
|
|
319
|
+
return;
|
|
320
|
+
themeRegistryCache = registeredThemes;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Material elevation defaults
|
|
324
|
+
*/
|
|
325
|
+
function materialElevation() {
|
|
326
|
+
return {
|
|
327
|
+
0: 'none',
|
|
328
|
+
1: '0 1px 2px 0 rgb(0 0 0 / 0.05), 0 1px 3px 0 rgb(0 0 0 / 0.02)',
|
|
329
|
+
2: '0 1px 2px 0 rgb(0 0 0 / 0.06), 0 2px 4px 0 rgb(0 0 0 / 0.04)',
|
|
330
|
+
3: '0 2px 4px 0 rgb(0 0 0 / 0.06), 0 4px 8px 0 rgb(0 0 0 / 0.04)',
|
|
331
|
+
4: '0 4px 8px 0 rgb(0 0 0 / 0.08), 0 8px 16px 0 rgb(0 0 0 / 0.04)',
|
|
332
|
+
5: '0 8px 16px 0 rgb(0 0 0 / 0.1), 0 16px 32px 0 rgb(0 0 0 / 0.04)',
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Register a custom theme for use with ThemeProvider
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```typescript
|
|
340
|
+
* import { createTheme, registerTheme } from '@happyvertical/smrt-ui/themes';
|
|
341
|
+
*
|
|
342
|
+
* const customTheme = createTheme({ id: 'brand', name: 'Brand', ... });
|
|
343
|
+
* registerTheme(customTheme);
|
|
344
|
+
*
|
|
345
|
+
* // Now use in your app
|
|
346
|
+
* <ThemeProvider preset="brand" />
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
export function registerTheme(theme) {
|
|
350
|
+
registerCustomTheme(theme);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Get a registered custom theme
|
|
354
|
+
*/
|
|
355
|
+
export function getRegisteredTheme(_id) {
|
|
356
|
+
// Dynamic import to avoid circular deps
|
|
357
|
+
// Return undefined synchronously - use isThemeRegistered for checks
|
|
358
|
+
return undefined;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Check if a theme is registered
|
|
362
|
+
* Note: This is async due to ESM dynamic import requirements
|
|
363
|
+
*/
|
|
364
|
+
export async function isThemeRegistered(id) {
|
|
365
|
+
return hasCustomTheme(id);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Create a simple theme from just a primary color
|
|
369
|
+
* Auto-generates all other colors
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* ```typescript
|
|
373
|
+
* const brandTheme = createThemeFromColor('#ff6b35', 'brand', 'Brand Theme');
|
|
374
|
+
* registerTheme(brandTheme);
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
export function createThemeFromColor(primaryColor, id, name, options) {
|
|
378
|
+
return createTheme({
|
|
379
|
+
id,
|
|
380
|
+
name,
|
|
381
|
+
light: {
|
|
382
|
+
primary: primaryColor,
|
|
383
|
+
background: '#ffffff',
|
|
384
|
+
surface: '#ffffff',
|
|
385
|
+
},
|
|
386
|
+
...options,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
// Types are exported from index.ts
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS Variable Generator
|
|
3
|
+
*
|
|
4
|
+
* Converts theme definitions into CSS custom properties for runtime theming.
|
|
5
|
+
* Generates CSS variables for colors, typography, spacing, elevation, etc.
|
|
6
|
+
*/
|
|
7
|
+
import type { Theme } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* CSS variable generation options
|
|
10
|
+
*/
|
|
11
|
+
export interface GenerateCSSOptions {
|
|
12
|
+
/** CSS variable prefix (default: --smrt) */
|
|
13
|
+
prefix?: string;
|
|
14
|
+
/** Include theme ID as data attribute selector */
|
|
15
|
+
includeDataAttr?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generate all CSS custom properties for a theme
|
|
19
|
+
* @param theme - Theme definition
|
|
20
|
+
* @param isDark - Whether to use dark mode colors
|
|
21
|
+
* @param options - Generation options
|
|
22
|
+
* @returns Object with CSS variable names and values
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateThemeVariables(theme: Theme, isDark: boolean, options?: GenerateCSSOptions): Record<string, string>;
|
|
25
|
+
/**
|
|
26
|
+
* Convert variables object to CSS style string
|
|
27
|
+
* @param variables - Record of CSS variable names and values
|
|
28
|
+
* @returns CSS string for style attribute
|
|
29
|
+
*/
|
|
30
|
+
export declare function variablesToStyleString(variables: Record<string, string>): string;
|
|
31
|
+
/**
|
|
32
|
+
* Generate CSS class content for a theme
|
|
33
|
+
* @param theme - Theme definition
|
|
34
|
+
* @param isDark - Whether to use dark mode
|
|
35
|
+
* @param options - Generation options
|
|
36
|
+
* @returns CSS string for embedding in a <style> tag
|
|
37
|
+
*/
|
|
38
|
+
export declare function generateThemeCSS(theme: Theme, isDark: boolean, options?: GenerateCSSOptions): string;
|
|
39
|
+
/**
|
|
40
|
+
* Generate all theme CSS for all presets and modes
|
|
41
|
+
* @returns Complete CSS for all themes
|
|
42
|
+
*/
|
|
43
|
+
export declare function generateAllThemesCSS(): Promise<string>;
|
|
44
|
+
//# sourceMappingURL=css-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-generator.d.ts","sourceRoot":"","sources":["../../src/themes/css-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,KAAK,EAQV,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;AA+LD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,OAAO,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsCxB;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"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS Variable Generator
|
|
3
|
+
*
|
|
4
|
+
* Converts theme definitions into CSS custom properties for runtime theming.
|
|
5
|
+
* Generates CSS variables for colors, typography, spacing, elevation, etc.
|
|
6
|
+
*/
|
|
7
|
+
import { themes } from './registry.js';
|
|
8
|
+
import { borderRadiusAliases, durationAliases, fontFamilyAliases, fontWeightTokens, spacingAliases, zIndexTokens, } from './shared.js';
|
|
9
|
+
/**
|
|
10
|
+
* Generate CSS custom properties from a color palette
|
|
11
|
+
*/
|
|
12
|
+
function generateColorVariables(colors, prefix) {
|
|
13
|
+
const vars = {};
|
|
14
|
+
for (const [key, value] of Object.entries(colors)) {
|
|
15
|
+
// Convert camelCase to kebab-case: primaryContainer -> primary-container
|
|
16
|
+
const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
17
|
+
vars[`${prefix}-color-${cssKey}`] = value;
|
|
18
|
+
}
|
|
19
|
+
return vars;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate CSS custom properties from typography scale
|
|
23
|
+
*/
|
|
24
|
+
function generateTypographyVariables(typography, prefix) {
|
|
25
|
+
const vars = {};
|
|
26
|
+
for (const [key, token] of Object.entries(typography)) {
|
|
27
|
+
const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
28
|
+
vars[`${prefix}-typography-${cssKey}-size`] = token.size;
|
|
29
|
+
vars[`${prefix}-typography-${cssKey}-line-height`] = token.lineHeight;
|
|
30
|
+
vars[`${prefix}-typography-${cssKey}-weight`] = String(token.weight);
|
|
31
|
+
vars[`${prefix}-typography-${cssKey}-tracking`] = token.tracking;
|
|
32
|
+
if (token.fontFamily) {
|
|
33
|
+
vars[`${prefix}-typography-${cssKey}-font-family`] = token.fontFamily;
|
|
34
|
+
}
|
|
35
|
+
// Additive `font` shorthand alias (issue #1431): components use
|
|
36
|
+
// `font: var(--smrt-typography-body-medium-font)`, expecting the CSS
|
|
37
|
+
// `font` shorthand order (style variant size/line-height family). Built
|
|
38
|
+
// from the emitted longhands so it stays in sync.
|
|
39
|
+
const family = token.fontFamily ?? `var(${prefix}-font-family)`;
|
|
40
|
+
vars[`${prefix}-typography-${cssKey}-font`] =
|
|
41
|
+
`${token.weight} ${token.size}/${token.lineHeight} ${family}`;
|
|
42
|
+
}
|
|
43
|
+
return vars;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Generate CSS custom properties from spacing scale
|
|
47
|
+
*/
|
|
48
|
+
function generateSpacingVariables(spacing, prefix) {
|
|
49
|
+
const vars = {};
|
|
50
|
+
for (const [key, value] of Object.entries(spacing)) {
|
|
51
|
+
// Handle decimal keys like "0.5" - replace ALL dots with underscores
|
|
52
|
+
const cssKey = key.replace(/\./g, '_');
|
|
53
|
+
vars[`${prefix}-spacing-${cssKey}`] = value;
|
|
54
|
+
}
|
|
55
|
+
// Additive Material-3 named aliases (issue #1431), mapped to numeric values.
|
|
56
|
+
for (const [alias, numericKey] of Object.entries(spacingAliases)) {
|
|
57
|
+
const value = spacing[numericKey];
|
|
58
|
+
if (value !== undefined)
|
|
59
|
+
vars[`${prefix}-spacing-${alias}`] = value;
|
|
60
|
+
}
|
|
61
|
+
return vars;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Generate CSS custom properties from border radius scale
|
|
65
|
+
*/
|
|
66
|
+
function generateBorderRadiusVariables(borderRadius, prefix) {
|
|
67
|
+
const vars = {};
|
|
68
|
+
for (const [key, value] of Object.entries(borderRadius)) {
|
|
69
|
+
const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
70
|
+
vars[`${prefix}-radius-${cssKey}`] = value;
|
|
71
|
+
}
|
|
72
|
+
// Additive Material-3 named aliases (issue #1431), mapped to t-shirt values.
|
|
73
|
+
for (const [alias, scaleKey] of Object.entries(borderRadiusAliases)) {
|
|
74
|
+
const value = borderRadius[scaleKey];
|
|
75
|
+
if (value !== undefined)
|
|
76
|
+
vars[`${prefix}-radius-${alias}`] = value;
|
|
77
|
+
}
|
|
78
|
+
return vars;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Generate CSS custom properties from elevation scale
|
|
82
|
+
*/
|
|
83
|
+
function generateElevationVariables(elevation, prefix) {
|
|
84
|
+
const vars = {};
|
|
85
|
+
for (const [key, value] of Object.entries(elevation)) {
|
|
86
|
+
vars[`${prefix}-elevation-${key}`] = value;
|
|
87
|
+
}
|
|
88
|
+
return vars;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Generate CSS custom properties from duration scale
|
|
92
|
+
*/
|
|
93
|
+
function generateDurationVariables(duration, prefix) {
|
|
94
|
+
const vars = {};
|
|
95
|
+
for (const [key, value] of Object.entries(duration)) {
|
|
96
|
+
const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
97
|
+
vars[`${prefix}-duration-${cssKey}`] = value;
|
|
98
|
+
}
|
|
99
|
+
// Additive Material-3 motion aliases (issue #1431): short1…long4.
|
|
100
|
+
for (const [alias, value] of Object.entries(durationAliases)) {
|
|
101
|
+
vars[`${prefix}-duration-${alias}`] = value;
|
|
102
|
+
}
|
|
103
|
+
return vars;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Generate CSS custom properties from easing scale
|
|
107
|
+
*/
|
|
108
|
+
function generateEasingVariables(easing, prefix) {
|
|
109
|
+
const vars = {};
|
|
110
|
+
for (const [key, value] of Object.entries(easing)) {
|
|
111
|
+
const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
112
|
+
vars[`${prefix}-easing-${cssKey}`] = value;
|
|
113
|
+
}
|
|
114
|
+
return vars;
|
|
115
|
+
}
|
|
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
|
+
/**
|
|
130
|
+
* Generate theme-independent helper tokens (issue #1431).
|
|
131
|
+
*
|
|
132
|
+
* Monospace font family, named font weights, and z-index stacking levels are
|
|
133
|
+
* the same across presets and color schemes. Emitting them as tokens lets
|
|
134
|
+
* components stop hardcoding magic values and keeps overlay layering / mono
|
|
135
|
+
* surfaces themeable.
|
|
136
|
+
*/
|
|
137
|
+
function generateStaticTokens(prefix) {
|
|
138
|
+
const vars = {};
|
|
139
|
+
for (const [alias, value] of Object.entries(fontFamilyAliases)) {
|
|
140
|
+
vars[`${prefix}-font-family-${alias}`] = value;
|
|
141
|
+
}
|
|
142
|
+
for (const [name, value] of Object.entries(fontWeightTokens)) {
|
|
143
|
+
vars[`${prefix}-typography-weight-${name}`] = value;
|
|
144
|
+
}
|
|
145
|
+
for (const [name, value] of Object.entries(zIndexTokens)) {
|
|
146
|
+
vars[`${prefix}-z-index-${name}`] = value;
|
|
147
|
+
}
|
|
148
|
+
return vars;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Generate all CSS custom properties for a theme
|
|
152
|
+
* @param theme - Theme definition
|
|
153
|
+
* @param isDark - Whether to use dark mode colors
|
|
154
|
+
* @param options - Generation options
|
|
155
|
+
* @returns Object with CSS variable names and values
|
|
156
|
+
*/
|
|
157
|
+
export function generateThemeVariables(theme, isDark, options = {}) {
|
|
158
|
+
const { prefix = '--smrt' } = options;
|
|
159
|
+
const colors = isDark ? theme.dark : theme.light;
|
|
160
|
+
return {
|
|
161
|
+
// Theme identification
|
|
162
|
+
[`${prefix}-theme-id`]: theme.id,
|
|
163
|
+
[`${prefix}-theme-name`]: theme.name,
|
|
164
|
+
[`${prefix}-color-scheme`]: isDark ? 'dark' : 'light',
|
|
165
|
+
[`${prefix}-font-family`]: theme.fontFamily,
|
|
166
|
+
// Colors
|
|
167
|
+
...generateColorVariables(colors, prefix),
|
|
168
|
+
// Typography
|
|
169
|
+
...generateTypographyVariables(theme.typography, prefix),
|
|
170
|
+
// Spacing
|
|
171
|
+
...generateSpacingVariables(theme.spacing, prefix),
|
|
172
|
+
// Border radius
|
|
173
|
+
...generateBorderRadiusVariables(theme.borderRadius, prefix),
|
|
174
|
+
// Elevation
|
|
175
|
+
...generateElevationVariables(theme.elevation, prefix),
|
|
176
|
+
// Duration
|
|
177
|
+
...generateDurationVariables(theme.duration, prefix),
|
|
178
|
+
// Easing
|
|
179
|
+
...generateEasingVariables(theme.easing, prefix),
|
|
180
|
+
// Theme-independent helper tokens (mono font, named weights, z-index)
|
|
181
|
+
...generateStaticTokens(prefix),
|
|
182
|
+
// Glass effects (if present)
|
|
183
|
+
...generateGlassVariables(theme.glass, prefix),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Convert variables object to CSS style string
|
|
188
|
+
* @param variables - Record of CSS variable names and values
|
|
189
|
+
* @returns CSS string for style attribute
|
|
190
|
+
*/
|
|
191
|
+
export function variablesToStyleString(variables) {
|
|
192
|
+
return Object.entries(variables)
|
|
193
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
194
|
+
.join('; ');
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Generate CSS class content for a theme
|
|
198
|
+
* @param theme - Theme definition
|
|
199
|
+
* @param isDark - Whether to use dark mode
|
|
200
|
+
* @param options - Generation options
|
|
201
|
+
* @returns CSS string for embedding in a <style> tag
|
|
202
|
+
*/
|
|
203
|
+
export function generateThemeCSS(theme, isDark, options = {}) {
|
|
204
|
+
const { prefix = '--smrt', includeDataAttr = true } = options;
|
|
205
|
+
const variables = generateThemeVariables(theme, isDark, { prefix });
|
|
206
|
+
const varDeclarations = Object.entries(variables)
|
|
207
|
+
.map(([key, value]) => ` ${key}: ${value};`)
|
|
208
|
+
.join('\n');
|
|
209
|
+
if (includeDataAttr) {
|
|
210
|
+
const scheme = isDark ? 'dark' : 'light';
|
|
211
|
+
return `[data-theme="${theme.id}"][data-color-scheme="${scheme}"] {\n${varDeclarations}\n}`;
|
|
212
|
+
}
|
|
213
|
+
return `:root {\n${varDeclarations}\n}`;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Generate all theme CSS for all presets and modes
|
|
217
|
+
* @returns Complete CSS for all themes
|
|
218
|
+
*/
|
|
219
|
+
export async function generateAllThemesCSS() {
|
|
220
|
+
const cssParts = [];
|
|
221
|
+
for (const theme of Object.values(themes)) {
|
|
222
|
+
cssParts.push(generateThemeCSS(theme, false, { includeDataAttr: true }));
|
|
223
|
+
cssParts.push(generateThemeCSS(theme, true, { includeDataAttr: true }));
|
|
224
|
+
}
|
|
225
|
+
return cssParts.join('\n\n');
|
|
226
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glass Theme
|
|
3
|
+
*
|
|
4
|
+
* Apple-inspired glass morphism theme with backdrop blur effects,
|
|
5
|
+
* translucency, and layered depth. Features frosted glass surfaces
|
|
6
|
+
* and vibrant material effects.
|
|
7
|
+
*/
|
|
8
|
+
import type { Theme } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Glass theme definition
|
|
11
|
+
*/
|
|
12
|
+
export declare const glassTheme: Theme;
|
|
13
|
+
export default glassTheme;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/themes/glass/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,KAAK,EAIV,KAAK,EAEN,MAAM,aAAa,CAAC;AAiSrB;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,KAcxB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|