@moni-labs/moni-ui 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -194
- package/custom-elements.json +1636 -350
- package/dist/actions/index.d.ts +6 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +6 -0
- package/dist/components/_base/field-styles.d.ts +51 -16
- package/dist/components/_base/field-styles.d.ts.map +1 -1
- package/dist/components/_base/field-styles.js +164 -36
- package/dist/components/_base/index.d.ts +25 -0
- package/dist/components/_base/index.d.ts.map +1 -1
- package/dist/components/_base/index.js +25 -0
- package/dist/components/_base/interaction-styles.d.ts +39 -12
- package/dist/components/_base/interaction-styles.d.ts.map +1 -1
- package/dist/components/_base/interaction-styles.js +85 -33
- package/dist/components/_base/moni-element.d.ts +43 -8
- package/dist/components/_base/moni-element.d.ts.map +1 -1
- package/dist/components/_base/moni-element.js +43 -8
- package/dist/components/_base/shared-styles.d.ts +41 -17
- package/dist/components/_base/shared-styles.d.ts.map +1 -1
- package/dist/components/_base/shared-styles.js +113 -21
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +6 -0
- package/dist/components/loading-shapes.d.ts +6 -0
- package/dist/components/loading-shapes.d.ts.map +1 -1
- package/dist/components/loading-shapes.js +6 -0
- package/dist/components/moni-app-bar.d.ts +128 -33
- package/dist/components/moni-app-bar.d.ts.map +1 -1
- package/dist/components/moni-app-bar.js +121 -26
- package/dist/components/moni-badge.d.ts +122 -14
- package/dist/components/moni-badge.d.ts.map +1 -1
- package/dist/components/moni-badge.js +122 -14
- package/dist/components/moni-bottom-sheet.d.ts +120 -15
- package/dist/components/moni-bottom-sheet.d.ts.map +1 -1
- package/dist/components/moni-bottom-sheet.js +116 -12
- package/dist/components/moni-button-group.d.ts +53 -27
- package/dist/components/moni-button-group.d.ts.map +1 -1
- package/dist/components/moni-button-group.js +49 -23
- package/dist/components/moni-button-segment.d.ts +28 -8
- package/dist/components/moni-button-segment.d.ts.map +1 -1
- package/dist/components/moni-button-segment.js +27 -7
- package/dist/components/moni-button.d.ts +51 -32
- package/dist/components/moni-button.d.ts.map +1 -1
- package/dist/components/moni-button.js +50 -31
- package/dist/components/moni-card.d.ts +91 -31
- package/dist/components/moni-card.d.ts.map +1 -1
- package/dist/components/moni-card.js +86 -26
- package/dist/components/moni-carousel.d.ts +67 -17
- package/dist/components/moni-carousel.d.ts.map +1 -1
- package/dist/components/moni-carousel.js +59 -16
- package/dist/components/moni-checkbox.d.ts +122 -17
- package/dist/components/moni-checkbox.d.ts.map +1 -1
- package/dist/components/moni-checkbox.js +118 -14
- package/dist/components/moni-chip.d.ts +56 -30
- package/dist/components/moni-chip.d.ts.map +1 -1
- package/dist/components/moni-chip.js +51 -25
- package/dist/components/moni-color-field.d.ts +44 -6
- package/dist/components/moni-color-field.d.ts.map +1 -1
- package/dist/components/moni-color-field.js +43 -5
- package/dist/components/moni-context-menu.d.ts +44 -22
- package/dist/components/moni-context-menu.d.ts.map +1 -1
- package/dist/components/moni-context-menu.js +43 -21
- package/dist/components/moni-dialog.d.ts +107 -15
- package/dist/components/moni-dialog.d.ts.map +1 -1
- package/dist/components/moni-dialog.js +105 -14
- package/dist/components/moni-divider.d.ts +50 -15
- package/dist/components/moni-divider.d.ts.map +1 -1
- package/dist/components/moni-divider.js +49 -14
- package/dist/components/moni-expansion.d.ts +44 -8
- package/dist/components/moni-expansion.d.ts.map +1 -1
- package/dist/components/moni-expansion.js +43 -7
- package/dist/components/moni-fab-menu.d.ts +39 -20
- package/dist/components/moni-fab-menu.d.ts.map +1 -1
- package/dist/components/moni-fab-menu.js +38 -19
- package/dist/components/moni-fab.d.ts +49 -23
- package/dist/components/moni-fab.d.ts.map +1 -1
- package/dist/components/moni-fab.js +46 -20
- package/dist/components/moni-file-field.d.ts +54 -14
- package/dist/components/moni-file-field.d.ts.map +1 -1
- package/dist/components/moni-file-field.js +53 -13
- package/dist/components/moni-icon.d.ts +78 -11
- package/dist/components/moni-icon.d.ts.map +1 -1
- package/dist/components/moni-icon.js +77 -10
- package/dist/components/moni-list-item.d.ts +61 -30
- package/dist/components/moni-list-item.d.ts.map +1 -1
- package/dist/components/moni-list-item.js +55 -24
- package/dist/components/moni-list.d.ts +37 -13
- package/dist/components/moni-list.d.ts.map +1 -1
- package/dist/components/moni-list.js +36 -12
- package/dist/components/moni-loading-indicator.d.ts +38 -11
- package/dist/components/moni-loading-indicator.d.ts.map +1 -1
- package/dist/components/moni-loading-indicator.js +37 -10
- package/dist/components/moni-menu-item.d.ts +31 -8
- package/dist/components/moni-menu-item.d.ts.map +1 -1
- package/dist/components/moni-menu-item.js +30 -7
- package/dist/components/moni-menu.d.ts +58 -33
- package/dist/components/moni-menu.d.ts.map +1 -1
- package/dist/components/moni-menu.js +51 -26
- package/dist/components/moni-morph-modal.d.ts +7 -1
- package/dist/components/moni-morph-modal.d.ts.map +1 -1
- package/dist/components/moni-morph-modal.js +46 -24
- package/dist/components/moni-nav-item.d.ts +50 -10
- package/dist/components/moni-nav-item.d.ts.map +1 -1
- package/dist/components/moni-nav-item.js +48 -8
- package/dist/components/moni-nav.d.ts +57 -22
- package/dist/components/moni-nav.d.ts.map +1 -1
- package/dist/components/moni-nav.js +53 -18
- package/dist/components/moni-progress.d.ts +108 -20
- package/dist/components/moni-progress.d.ts.map +1 -1
- package/dist/components/moni-progress.js +104 -16
- package/dist/components/moni-radio.d.ts +106 -14
- package/dist/components/moni-radio.d.ts.map +1 -1
- package/dist/components/moni-radio.js +104 -13
- package/dist/components/moni-ripple.d.ts +121 -10
- package/dist/components/moni-ripple.d.ts.map +1 -1
- package/dist/components/moni-ripple.js +120 -9
- package/dist/components/moni-segmented-button.d.ts +31 -11
- package/dist/components/moni-segmented-button.d.ts.map +1 -1
- package/dist/components/moni-segmented-button.js +30 -10
- package/dist/components/moni-select-option.d.ts +43 -9
- package/dist/components/moni-select-option.d.ts.map +1 -1
- package/dist/components/moni-select-option.js +41 -7
- package/dist/components/moni-select.d.ts +59 -2
- package/dist/components/moni-select.d.ts.map +1 -1
- package/dist/components/moni-select.js +58 -1
- package/dist/components/moni-shape.d.ts +1 -1
- package/dist/components/moni-side-sheet.d.ts +56 -19
- package/dist/components/moni-side-sheet.d.ts.map +1 -1
- package/dist/components/moni-side-sheet.js +53 -16
- package/dist/components/moni-slider.d.ts +56 -25
- package/dist/components/moni-slider.d.ts.map +1 -1
- package/dist/components/moni-slider.js +55 -24
- package/dist/components/moni-snackbar.d.ts +86 -17
- package/dist/components/moni-snackbar.d.ts.map +1 -1
- package/dist/components/moni-snackbar.js +85 -16
- package/dist/components/moni-split-button.d.ts +38 -9
- package/dist/components/moni-split-button.d.ts.map +1 -1
- package/dist/components/moni-split-button.js +37 -8
- package/dist/components/moni-step.d.ts +42 -9
- package/dist/components/moni-step.d.ts.map +1 -1
- package/dist/components/moni-step.js +41 -8
- package/dist/components/moni-stepper.d.ts +43 -6
- package/dist/components/moni-stepper.d.ts.map +1 -1
- package/dist/components/moni-stepper.js +42 -5
- package/dist/components/moni-switch.d.ts +103 -16
- package/dist/components/moni-switch.d.ts.map +1 -1
- package/dist/components/moni-switch.js +99 -13
- package/dist/components/moni-tab.d.ts +35 -8
- package/dist/components/moni-tab.d.ts.map +1 -1
- package/dist/components/moni-tab.js +34 -7
- package/dist/components/moni-tabs.d.ts +51 -13
- package/dist/components/moni-tabs.d.ts.map +1 -1
- package/dist/components/moni-tabs.js +48 -10
- package/dist/components/moni-text-field.d.ts +55 -10
- package/dist/components/moni-text-field.d.ts.map +1 -1
- package/dist/components/moni-text-field.js +54 -9
- package/dist/components/moni-textarea.d.ts +51 -21
- package/dist/components/moni-textarea.d.ts.map +1 -1
- package/dist/components/moni-textarea.js +48 -18
- package/dist/components/moni-time-picker.d.ts +41 -11
- package/dist/components/moni-time-picker.d.ts.map +1 -1
- package/dist/components/moni-time-picker.js +40 -10
- package/dist/components/moni-toolbar.d.ts +43 -15
- package/dist/components/moni-toolbar.d.ts.map +1 -1
- package/dist/components/moni-toolbar.js +42 -14
- package/dist/components/moni-tooltip.d.ts +55 -25
- package/dist/components/moni-tooltip.d.ts.map +1 -1
- package/dist/components/moni-tooltip.js +54 -24
- package/dist/components/moni-typography.d.ts +43 -18
- package/dist/components/moni-typography.d.ts.map +1 -1
- package/dist/components/moni-typography.js +42 -17
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -2
- package/dist/styles/tailwind.css +67 -0
- package/dist/styles/tokens.css +111 -99
- package/dist/utils/color.d.ts +181 -2
- package/dist/utils/color.d.ts.map +1 -1
- package/dist/utils/color.js +182 -4
- package/dist/utils/theme.svelte.d.ts +305 -2
- package/dist/utils/theme.svelte.d.ts.map +1 -1
- package/dist/utils/theme.svelte.js +331 -2
- package/dist/web-components.d.ts +28 -0
- package/dist/web-components.d.ts.map +1 -1
- package/dist/web-components.js +29 -2
- package/package.json +1 -1
- package/src/actions/index.ts +7 -0
- package/src/components/_base/field-styles.ts +165 -37
- package/src/components/_base/index.ts +27 -0
- package/src/components/_base/interaction-styles.ts +86 -33
- package/src/components/_base/moni-element.ts +44 -8
- package/src/components/_base/shared-styles.ts +114 -21
- package/src/components/index.ts +7 -0
- package/src/components/loading-shapes.ts +7 -0
- package/src/components/moni-app-bar.ts +127 -26
- package/src/components/moni-badge.ts +128 -14
- package/src/components/moni-bottom-sheet.ts +125 -13
- package/src/components/moni-button-group.ts +50 -23
- package/src/components/moni-button-segment.ts +28 -7
- package/src/components/moni-button.ts +51 -31
- package/src/components/moni-card.ts +90 -26
- package/src/components/moni-carousel.ts +67 -16
- package/src/components/moni-checkbox.ts +125 -14
- package/src/components/moni-chip.ts +52 -25
- package/src/components/moni-color-field.ts +44 -5
- package/src/components/moni-context-menu.ts +44 -21
- package/src/components/moni-dialog.ts +111 -14
- package/src/components/moni-divider.ts +50 -14
- package/src/components/moni-expansion.ts +44 -7
- package/src/components/moni-fab-menu.ts +39 -19
- package/src/components/moni-fab.ts +47 -20
- package/src/components/moni-file-field.ts +54 -13
- package/src/components/moni-icon.ts +80 -10
- package/src/components/moni-list-item.ts +56 -24
- package/src/components/moni-list.ts +37 -12
- package/src/components/moni-loading-indicator.ts +38 -10
- package/src/components/moni-menu-item.ts +31 -7
- package/src/components/moni-menu.ts +52 -26
- package/src/components/moni-morph-modal.ts +58 -24
- package/src/components/moni-nav-item.ts +49 -8
- package/src/components/moni-nav.ts +54 -18
- package/src/components/moni-progress.ts +109 -16
- package/src/components/moni-radio.ts +111 -13
- package/src/components/moni-ripple.ts +126 -9
- package/src/components/moni-segmented-button.ts +31 -10
- package/src/components/moni-select-option.ts +42 -7
- package/src/components/moni-select.ts +79 -1
- package/src/components/moni-side-sheet.ts +54 -16
- package/src/components/moni-slider.ts +56 -24
- package/src/components/moni-snackbar.ts +90 -16
- package/src/components/moni-split-button.ts +38 -8
- package/src/components/moni-step.ts +42 -8
- package/src/components/moni-stepper.ts +43 -5
- package/src/components/moni-switch.ts +106 -13
- package/src/components/moni-tab.ts +35 -7
- package/src/components/moni-tabs.ts +49 -10
- package/src/components/moni-text-field.ts +55 -9
- package/src/components/moni-textarea.ts +49 -18
- package/src/components/moni-time-picker.ts +41 -10
- package/src/components/moni-toolbar.ts +43 -14
- package/src/components/moni-tooltip.ts +55 -24
- package/src/components/moni-typography.ts +43 -17
- package/src/index.ts +67 -3
- package/src/styles/tailwind.css +67 -0
- package/src/styles/tokens.css +111 -99
- package/src/types/svelte-runes.d.ts +64 -2
- package/src/utils/color.ts +286 -5
- package/src/utils/theme.svelte.ts +411 -2
- package/src/web-components.ts +31 -2
- package/dist/assets/shapes/arch.svg +0 -1
- package/dist/assets/shapes/arrow.svg +0 -1
- package/dist/assets/shapes/boom.svg +0 -1
- package/dist/assets/shapes/burst.svg +0 -1
- package/dist/assets/shapes/circle.svg +0 -1
- package/dist/assets/shapes/clamshell.svg +0 -1
- package/dist/assets/shapes/diamond.svg +0 -1
- package/dist/assets/shapes/fan.svg +0 -1
- package/dist/assets/shapes/flower.svg +0 -1
- package/dist/assets/shapes/gem.svg +0 -1
- package/dist/assets/shapes/ghost-ish.svg +0 -1
- package/dist/assets/shapes/heart.svg +0 -1
- package/dist/assets/shapes/leaf-clover4.svg +0 -1
- package/dist/assets/shapes/leaf-clover8.svg +0 -1
- package/dist/assets/shapes/loading-indicator.svg +0 -1
- package/dist/assets/shapes/oval.svg +0 -1
- package/dist/assets/shapes/pentagon.svg +0 -1
- package/dist/assets/shapes/pill.svg +0 -1
- package/dist/assets/shapes/pixel-circle.svg +0 -1
- package/dist/assets/shapes/pixel-triangle.svg +0 -1
- package/dist/assets/shapes/puffy-diamond.svg +0 -1
- package/dist/assets/shapes/puffy.svg +0 -1
- package/dist/assets/shapes/semicircle.svg +0 -1
- package/dist/assets/shapes/sided-cookie12.svg +0 -1
- package/dist/assets/shapes/sided-cookie4.svg +0 -1
- package/dist/assets/shapes/sided-cookie6.svg +0 -1
- package/dist/assets/shapes/sided-cookie7.svg +0 -1
- package/dist/assets/shapes/sided-cookie9.svg +0 -1
- package/dist/assets/shapes/slanted.svg +0 -1
- package/dist/assets/shapes/soft-boom.svg +0 -1
- package/dist/assets/shapes/soft-burst.svg +0 -1
- package/dist/assets/shapes/square.svg +0 -1
- package/dist/assets/shapes/sunny.svg +0 -1
- package/dist/assets/shapes/triangle.svg +0 -1
- package/dist/assets/shapes/very-sunny.svg +0 -1
- package/dist/assets/shapes/wavy-circle.svg +0 -1
- package/dist/assets/shapes/wavy.svg +0 -1
- package/src/assets/shapes/arch.svg +0 -1
- package/src/assets/shapes/arrow.svg +0 -1
- package/src/assets/shapes/boom.svg +0 -1
- package/src/assets/shapes/burst.svg +0 -1
- package/src/assets/shapes/circle.svg +0 -1
- package/src/assets/shapes/clamshell.svg +0 -1
- package/src/assets/shapes/diamond.svg +0 -1
- package/src/assets/shapes/fan.svg +0 -1
- package/src/assets/shapes/flower.svg +0 -1
- package/src/assets/shapes/gem.svg +0 -1
- package/src/assets/shapes/ghost-ish.svg +0 -1
- package/src/assets/shapes/heart.svg +0 -1
- package/src/assets/shapes/leaf-clover4.svg +0 -1
- package/src/assets/shapes/leaf-clover8.svg +0 -1
- package/src/assets/shapes/loading-indicator.svg +0 -1
- package/src/assets/shapes/oval.svg +0 -1
- package/src/assets/shapes/pentagon.svg +0 -1
- package/src/assets/shapes/pill.svg +0 -1
- package/src/assets/shapes/pixel-circle.svg +0 -1
- package/src/assets/shapes/pixel-triangle.svg +0 -1
- package/src/assets/shapes/puffy-diamond.svg +0 -1
- package/src/assets/shapes/puffy.svg +0 -1
- package/src/assets/shapes/semicircle.svg +0 -1
- package/src/assets/shapes/sided-cookie12.svg +0 -1
- package/src/assets/shapes/sided-cookie4.svg +0 -1
- package/src/assets/shapes/sided-cookie6.svg +0 -1
- package/src/assets/shapes/sided-cookie7.svg +0 -1
- package/src/assets/shapes/sided-cookie9.svg +0 -1
- package/src/assets/shapes/slanted.svg +0 -1
- package/src/assets/shapes/soft-boom.svg +0 -1
- package/src/assets/shapes/soft-burst.svg +0 -1
- package/src/assets/shapes/square.svg +0 -1
- package/src/assets/shapes/sunny.svg +0 -1
- package/src/assets/shapes/triangle.svg +0 -1
- package/src/assets/shapes/very-sunny.svg +0 -1
- package/src/assets/shapes/wavy-circle.svg +0 -1
- package/src/assets/shapes/wavy.svg +0 -1
package/dist/utils/color.js
CHANGED
|
@@ -1,21 +1,76 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* @file utils/color.ts
|
|
3
|
+
* @package @moni-labs/moni-ui
|
|
4
|
+
* @license MIT
|
|
5
|
+
* @contributors Moni Labs & Contributors
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* @module color
|
|
9
|
+
*
|
|
10
|
+
* Color utilities for generating and applying Material Design 3–compliant
|
|
11
|
+
* dynamic color schemes.
|
|
12
|
+
*
|
|
13
|
+
* This module wraps `@material/material-color-utilities` to expose a
|
|
14
|
+
* simplified, opinionated API that covers the full Moni theming pipeline:
|
|
15
|
+
*
|
|
16
|
+
* 1. Convert a user-supplied "seed" hex color to the HCT color space.
|
|
17
|
+
* 2. Generate a complete 27-role `ColorScheme` via `SchemeTonalSpot`.
|
|
18
|
+
* 3. Apply the scheme to the document root as CSS custom properties under
|
|
19
|
+
* three namespaces (`--md-sys-color-*`, `--moni-*`, and bare `--*`)
|
|
20
|
+
* so any component or stylesheet can consume the tokens.
|
|
21
|
+
*
|
|
22
|
+
* **Contrast levels** map to the MD3 contrast spec:
|
|
23
|
+
* - `standard` → 0.0 (WCAG AA baseline)
|
|
24
|
+
* - `medium` → 0.5 (enhanced readability)
|
|
25
|
+
* - `high` → 1.0 (WCAG AAA, maximum legibility)
|
|
26
|
+
*
|
|
27
|
+
* @see https://m3.material.io/styles/color/dynamic-color/overview
|
|
28
|
+
* @see https://github.com/material-foundation/material-color-utilities
|
|
4
29
|
*/
|
|
5
30
|
import { SchemeTonalSpot, Hct, argbFromHex, hexFromArgb } from '@material/material-color-utilities';
|
|
31
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
32
|
+
// Color conversion utilities
|
|
33
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
34
|
+
/**
|
|
35
|
+
* Converts a 6-digit hex color string to the HSL color model.
|
|
36
|
+
*
|
|
37
|
+
* Normalizes the input (strips optional `#`), parses each 8-bit RGB channel
|
|
38
|
+
* into a [0, 1] float, then applies the standard RGB→HSL algorithm:
|
|
39
|
+
*
|
|
40
|
+
* - Lightness = (max + min) / 2
|
|
41
|
+
* - Saturation = delta / (2 − max − min) if L > 0.5
|
|
42
|
+
* = delta / (max + min) otherwise
|
|
43
|
+
* - Hue = derived from which channel is the maximum
|
|
44
|
+
*
|
|
45
|
+
* When the color is achromatic (r = g = b), hue and saturation are both 0.
|
|
46
|
+
*
|
|
47
|
+
* @param hex - A 6-digit hex color, with or without the `#` prefix.
|
|
48
|
+
* Examples: `'#4f46e5'`, `'4f46e5'`.
|
|
49
|
+
* @returns An {@link HSL} object where `h` ∈ [0, 360), `s` ∈ [0, 100], `l` ∈ [0, 100].
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* hexToHsl('#ff0000') // { h: 0, s: 100, l: 50 }
|
|
53
|
+
* hexToHsl('#ffffff') // { h: 0, s: 0, l: 100 }
|
|
54
|
+
* hexToHsl('#4f46e5') // { h: 243, s: 73, l: 59 } (approx)
|
|
55
|
+
*/
|
|
6
56
|
export function hexToHsl(hex) {
|
|
7
57
|
const normalized = hex.replace('#', '');
|
|
58
|
+
// Parse each 8-bit channel and normalize to [0, 1].
|
|
8
59
|
const r = parseInt(normalized.substring(0, 2), 16) / 255;
|
|
9
60
|
const g = parseInt(normalized.substring(2, 4), 16) / 255;
|
|
10
61
|
const b = parseInt(normalized.substring(4, 6), 16) / 255;
|
|
11
62
|
const max = Math.max(r, g, b);
|
|
12
63
|
const min = Math.min(r, g, b);
|
|
64
|
+
// Initialize hue and saturation; they stay 0 for achromatic colors.
|
|
13
65
|
let h = 0;
|
|
14
66
|
let s = 0;
|
|
67
|
+
// Lightness is always the midpoint between brightest and darkest channel.
|
|
15
68
|
const l = (max + min) / 2;
|
|
16
69
|
if (max !== min) {
|
|
17
70
|
const d = max - min;
|
|
71
|
+
// Saturation formula differs above and below the 50% lightness threshold.
|
|
18
72
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
73
|
+
// Hue is determined by which channel dominates.
|
|
19
74
|
switch (max) {
|
|
20
75
|
case r:
|
|
21
76
|
h = (g - b) / d + (g < b ? 6 : 0);
|
|
@@ -27,15 +82,40 @@ export function hexToHsl(hex) {
|
|
|
27
82
|
h = (r - g) / d + 4;
|
|
28
83
|
break;
|
|
29
84
|
}
|
|
85
|
+
// Normalize hue from a 0–6 sector index to degrees [0, 360).
|
|
30
86
|
h /= 6;
|
|
31
87
|
}
|
|
32
88
|
return { h: h * 360, s: s * 100, l: l * 100 };
|
|
33
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Converts an HSL color to a 6-digit hex string.
|
|
92
|
+
*
|
|
93
|
+
* Uses the CSS Color Level 4 reference algorithm. Internally computes R, G,
|
|
94
|
+
* and B via a piecewise function `f(n)` that maps chroma sector offsets to
|
|
95
|
+
* individual channel values.
|
|
96
|
+
*
|
|
97
|
+
* @param hsl - An {@link HSL} object where `h` ∈ [0, 360), `s` ∈ [0, 100], `l` ∈ [0, 100].
|
|
98
|
+
* @returns A lowercase 7-character hex string including the `#` prefix (e.g. `'#4f46e5'`).
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* hslToHex({ h: 0, s: 100, l: 50 }) // '#ff0000'
|
|
102
|
+
* hslToHex({ h: 0, s: 0, l: 100 }) // '#ffffff'
|
|
103
|
+
*/
|
|
34
104
|
export function hslToHex({ h, s, l }) {
|
|
105
|
+
// Normalize percentages to [0, 1] for the algorithm.
|
|
35
106
|
s /= 100;
|
|
36
107
|
l /= 100;
|
|
108
|
+
/**
|
|
109
|
+
* Sector index helper. Maps the offset `n` (0, 4, 8) to a position within
|
|
110
|
+
* the 12-sector hue wheel (each sector = 30°).
|
|
111
|
+
*/
|
|
37
112
|
const k = (n) => (n + h / 30) % 12;
|
|
113
|
+
/** Chroma magnitude: 0 at lightness extremes, max at L=0.5. */
|
|
38
114
|
const a = s * Math.min(l, 1 - l);
|
|
115
|
+
/**
|
|
116
|
+
* Per-channel computation. Returns a 2-character hex string for the
|
|
117
|
+
* channel corresponding to sector offset `n` (0=R, 8=G, 4=B).
|
|
118
|
+
*/
|
|
39
119
|
const f = (n) => {
|
|
40
120
|
const color = l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
|
|
41
121
|
return Math.round(color * 255)
|
|
@@ -44,10 +124,52 @@ export function hslToHex({ h, s, l }) {
|
|
|
44
124
|
};
|
|
45
125
|
return `#${f(0)}${f(8)}${f(4)}`;
|
|
46
126
|
}
|
|
127
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
128
|
+
// Scheme generation
|
|
129
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
130
|
+
/**
|
|
131
|
+
* Generates a complete Material Design 3 color scheme from a seed hex color.
|
|
132
|
+
*
|
|
133
|
+
* Uses `SchemeTonalSpot` — the standard M3 dynamic color algorithm — which
|
|
134
|
+
* derives all 27 color roles from a single source hue while respecting the
|
|
135
|
+
* target lightness/contrast requirements for each role.
|
|
136
|
+
*
|
|
137
|
+
* **Algorithm pipeline:**
|
|
138
|
+
* 1. Parse `seedHex` → ARGB integer via `argbFromHex`.
|
|
139
|
+
* 2. Convert ARGB → HCT (Hue–Chroma–Tone) color space.
|
|
140
|
+
* 3. Construct a `SchemeTonalSpot` with the requested mode and contrast level.
|
|
141
|
+
* 4. Extract each scheme role via `hexFromArgb` and build the {@link ColorScheme}.
|
|
142
|
+
*
|
|
143
|
+
* @param seedHex - The source/brand color as a hex string. The `#` prefix
|
|
144
|
+
* is optional (e.g. `'#4f46e5'` or `'4f46e5'`).
|
|
145
|
+
* @param mode - Color scheme polarity. `'light'` produces light backgrounds
|
|
146
|
+
* with dark text; `'dark'` inverts the tone mapping.
|
|
147
|
+
* Defaults to `'light'`.
|
|
148
|
+
* @param contrast - WCAG contrast enhancement level. Defaults to `'standard'`.
|
|
149
|
+
*
|
|
150
|
+
* @returns A fully populated {@link ColorScheme} where every value is a
|
|
151
|
+
* lowercase 7-character hex string (e.g. `'#6750a4'`).
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* // Generate a standard light scheme from an indigo seed.
|
|
155
|
+
* const scheme = generateScheme('#4f46e5');
|
|
156
|
+
* console.log(scheme.primary); // e.g. '#5046e4'
|
|
157
|
+
* console.log(scheme.primaryContainer); // e.g. '#e9e7ff'
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* // High-contrast dark scheme.
|
|
161
|
+
* const darkHC = generateScheme('#4f46e5', 'dark', 'high');
|
|
162
|
+
*/
|
|
47
163
|
export function generateScheme(seedHex, mode = 'light', contrast = 'standard') {
|
|
164
|
+
// Ensure the seed always has a leading '#' for argbFromHex.
|
|
48
165
|
const seed = seedHex.startsWith('#') ? seedHex : `#${seedHex}`;
|
|
166
|
+
// Step 1: Convert hex → ARGB integer.
|
|
49
167
|
const argb = argbFromHex(seed);
|
|
168
|
+
// Step 2: Convert ARGB → HCT. HCT is the perceptual color space used
|
|
169
|
+
// internally by the MD3 algorithm; it preserves human color perception
|
|
170
|
+
// better than RGB or HSL for palette generation.
|
|
50
171
|
const hct = Hct.fromInt(argb);
|
|
172
|
+
// Step 3: Map the ContrastLevel union to a numeric value expected by the SDK.
|
|
51
173
|
let contrastLevel = 0.0;
|
|
52
174
|
if (contrast === 'medium') {
|
|
53
175
|
contrastLevel = 0.5;
|
|
@@ -55,7 +177,10 @@ export function generateScheme(seedHex, mode = 'light', contrast = 'standard') {
|
|
|
55
177
|
else if (contrast === 'high') {
|
|
56
178
|
contrastLevel = 1.0;
|
|
57
179
|
}
|
|
180
|
+
// Step 4: Build the tonal-spot scheme. isDark=true shifts every tone value
|
|
181
|
+
// to keep roles readable on dark backgrounds.
|
|
58
182
|
const scheme = new SchemeTonalSpot(hct, mode === 'dark', contrastLevel);
|
|
183
|
+
// Step 5: Extract every color role from the scheme and convert back to hex.
|
|
59
184
|
return {
|
|
60
185
|
primary: hexFromArgb(scheme.primary),
|
|
61
186
|
onPrimary: hexFromArgb(scheme.onPrimary),
|
|
@@ -92,16 +217,69 @@ export function generateScheme(seedHex, mode = 'light', contrast = 'standard') {
|
|
|
92
217
|
shadow: hexFromArgb(scheme.shadow)
|
|
93
218
|
};
|
|
94
219
|
}
|
|
220
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
221
|
+
// DOM integration
|
|
222
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
223
|
+
/**
|
|
224
|
+
* Writes a {@link ColorScheme} to the document root as CSS custom properties.
|
|
225
|
+
*
|
|
226
|
+
* For each color role in the scheme, **three aliases** are set on
|
|
227
|
+
* `document.documentElement` so every context can consume the tokens:
|
|
228
|
+
*
|
|
229
|
+
* | Namespace prefix | Example | Consumer |
|
|
230
|
+
* |----------------------|----------------------------------|-----------------------|
|
|
231
|
+
* | `--md-sys-color-` | `--md-sys-color-primary` | MD3 spec / third-party|
|
|
232
|
+
* | `--moni-` | `--moni-primary` | Moni components |
|
|
233
|
+
* | `--` (bare) | `--primary` | BeerCSS / legacy |
|
|
234
|
+
*
|
|
235
|
+
* camelCase role names are converted to kebab-case automatically
|
|
236
|
+
* (e.g. `primaryContainer` → `primary-container`).
|
|
237
|
+
*
|
|
238
|
+
* Additionally sets `data-theme="light|dark"` on `<html>` so CSS can use
|
|
239
|
+
* `:root[data-theme='dark']` selectors for any additional overrides.
|
|
240
|
+
*
|
|
241
|
+
* **Side effects:** Mutates `doc.documentElement.style` and attributes.
|
|
242
|
+
* This function should only be called in browser environments.
|
|
243
|
+
*
|
|
244
|
+
* @param scheme - The color scheme to apply, as produced by {@link generateScheme}.
|
|
245
|
+
* @param mode - The resolved mode (`'light'` or `'dark'`); written to `data-theme`.
|
|
246
|
+
* @param doc - The `Document` to target. Pass `document` in normal usage;
|
|
247
|
+
* accepts a custom document for iframe or SSR scenarios.
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* const scheme = generateScheme('#4f46e5', 'dark');
|
|
251
|
+
* applySchemeToDocument(scheme, 'dark', document);
|
|
252
|
+
* // <html data-theme="dark" style="--md-sys-color-primary: #...; --moni-primary: #...; --primary: #...">
|
|
253
|
+
*/
|
|
95
254
|
export function applySchemeToDocument(scheme, mode, doc) {
|
|
96
255
|
const root = doc.documentElement;
|
|
256
|
+
// MD3 canonical namespace prefix.
|
|
97
257
|
const prefix = '--md-sys-color-';
|
|
98
258
|
for (const [key, value] of Object.entries(scheme)) {
|
|
259
|
+
// Convert camelCase → kebab-case (e.g. 'onPrimary' → 'on-primary').
|
|
99
260
|
const kebab = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
100
|
-
|
|
101
|
-
root.style.setProperty(
|
|
261
|
+
// Set all three namespace aliases simultaneously.
|
|
262
|
+
root.style.setProperty(`${prefix}${kebab}`, value); // MD3 spec namespace
|
|
263
|
+
root.style.setProperty(`--moni-${kebab}`, value); // Moni namespace
|
|
264
|
+
root.style.setProperty(`--${kebab}`, value); // Bare/BeerCSS namespace
|
|
102
265
|
}
|
|
266
|
+
// Mark the document with the resolved mode for CSS `[data-theme]` selectors.
|
|
103
267
|
root.setAttribute('data-theme', mode);
|
|
104
268
|
}
|
|
269
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
270
|
+
// Defaults
|
|
271
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
272
|
+
/**
|
|
273
|
+
* Returns the default seed color used by the Moni design system.
|
|
274
|
+
*
|
|
275
|
+
* The default seed is a deep indigo (`#4f46e5`) that maps to a material-spec
|
|
276
|
+
* primary hue of roughly 243°. It was chosen because it:
|
|
277
|
+
* - Generates accessible contrast ratios in both light and dark modes.
|
|
278
|
+
* - Feels brand-neutral enough to serve as a placeholder before users
|
|
279
|
+
* customize their color.
|
|
280
|
+
*
|
|
281
|
+
* @returns The default seed hex string `'#4f46e5'`.
|
|
282
|
+
*/
|
|
105
283
|
export function getDefaultSeed() {
|
|
106
284
|
return '#4f46e5';
|
|
107
285
|
}
|
|
@@ -1,45 +1,348 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* @file utils/theme.svelte.ts
|
|
3
|
+
* @package @moni-labs/moni-ui
|
|
4
|
+
* @license MIT
|
|
5
|
+
* @contributors Moni Labs & Contributors
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* @module theme
|
|
9
|
+
*
|
|
10
|
+
* Reactive theme engine for the Moni design system.
|
|
11
|
+
*
|
|
12
|
+
* `ThemeEngine` is the single source of truth for all visual customization
|
|
13
|
+
* options exposed to users: color seed, light/dark mode, contrast, density,
|
|
14
|
+
* border radius, typography, and motion reduction.
|
|
15
|
+
*
|
|
16
|
+
* **Architecture:**
|
|
17
|
+
* - The engine is a **singleton** accessed via {@link getThemeEngine}. This
|
|
18
|
+
* ensures that all app-level components share the same reactive state.
|
|
19
|
+
* - Settings are persisted to `localStorage` under {@link STORAGE_KEY} so
|
|
20
|
+
* they survive page reloads.
|
|
21
|
+
* - The class uses Svelte 5 `$state` runes for reactivity. Consumers in
|
|
22
|
+
* Svelte components can read `engine.resolvedMode` or `engine.scheme`
|
|
23
|
+
* reactively without any additional subscription setup.
|
|
24
|
+
* - In SSR or non-browser environments, all DOM-side effects are skipped
|
|
25
|
+
* gracefully via `typeof window === 'undefined'` / `typeof document === 'undefined'` guards.
|
|
26
|
+
*
|
|
27
|
+
* **CSS custom properties set by {@link ThemeEngine.apply}:**
|
|
28
|
+
* - `--moni-spacing-density` — numeric multiplier (e.g. 0.75, 1.0, 1.25, 1.6)
|
|
29
|
+
* - `--moni-radius-base` — border-radius base value (e.g. `'0px'`, `'12px'`, `'20px'`)
|
|
30
|
+
* - `--moni-font-sans` — font-family stack for body text
|
|
31
|
+
* - `--moni-font-title` — font-family stack for headings
|
|
32
|
+
* - `--moni-grain-opacity` — CSS opacity for the texture overlay (0–1)
|
|
33
|
+
* - `moni-reduce-motion` — class toggled on `<html>` when reduce-motion is active
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // In a Svelte component or framework-agnostic module:
|
|
38
|
+
* import { getThemeEngine } from '@moni-labs/moni-ui';
|
|
39
|
+
*
|
|
40
|
+
* const theme = getThemeEngine();
|
|
41
|
+
* theme.setSeedColor('#4f46e5');
|
|
42
|
+
* theme.setMode('dark');
|
|
43
|
+
* ```
|
|
4
44
|
*/
|
|
5
45
|
import { type ColorScheme, type ContrastLevel } from './color.js';
|
|
46
|
+
/**
|
|
47
|
+
* Color scheme polarity / light-dark preference.
|
|
48
|
+
*
|
|
49
|
+
* - `'light'` — Always apply the light palette regardless of OS setting.
|
|
50
|
+
* - `'dark'` — Always apply the dark palette regardless of OS setting.
|
|
51
|
+
* - `'system'` — Follow `prefers-color-scheme` media query. Updates
|
|
52
|
+
* automatically when the user changes their OS preference.
|
|
53
|
+
*/
|
|
6
54
|
export type ThemeMode = 'light' | 'dark' | 'system';
|
|
55
|
+
/**
|
|
56
|
+
* Spacing density scale.
|
|
57
|
+
*
|
|
58
|
+
* Controls the `--moni-spacing-density` custom property, which scales padding,
|
|
59
|
+
* gap, and height values throughout the component library.
|
|
60
|
+
*
|
|
61
|
+
* | Value | Multiplier | Use case |
|
|
62
|
+
* |---------------|------------|----------------------------------------|
|
|
63
|
+
* | `'compact'` | 0.75 | Dense data tables, admin dashboards |
|
|
64
|
+
* | `'default'` | 1.0 | Standard consumer UIs |
|
|
65
|
+
* | `'comfortable'`| 1.25 | Touch-friendly interfaces |
|
|
66
|
+
* | `'spacious'` | 1.6 | Large-display / presentation screens |
|
|
67
|
+
*/
|
|
7
68
|
export type ThemeDensity = 'compact' | 'default' | 'comfortable' | 'spacious';
|
|
69
|
+
/**
|
|
70
|
+
* Global border-radius style.
|
|
71
|
+
*
|
|
72
|
+
* Sets the `--moni-radius-base` custom property used as the base radius for
|
|
73
|
+
* cards, dialogs, sheets, and other container elements.
|
|
74
|
+
*
|
|
75
|
+
* - `'sharp'` → `0px` — No rounding; geometric aesthetic.
|
|
76
|
+
* - `'default'` → `12px` — Moderate rounding per M3 spec (medium shape).
|
|
77
|
+
* - `'rounded'` → `20px` — Expressive full-curve shapes; default for Moni brand.
|
|
78
|
+
*/
|
|
8
79
|
export type ThemeRadius = 'sharp' | 'default' | 'rounded';
|
|
80
|
+
/**
|
|
81
|
+
* Available typeface families for body and title text.
|
|
82
|
+
*
|
|
83
|
+
* Each value maps to a specific font-family stack in {@link fontFamily}.
|
|
84
|
+
*
|
|
85
|
+
* - `'geist'` — Geist (Vercel), system-ui fallback. Default body font.
|
|
86
|
+
* - `'inter'` — Inter, system-ui fallback. Classic UI sans-serif.
|
|
87
|
+
* - `'roboto'` — Roboto, system-ui fallback. Material Design reference font.
|
|
88
|
+
* - `'instrument'` — Instrument Serif, Georgia fallback. Editorial serif for titles.
|
|
89
|
+
*/
|
|
9
90
|
export type ThemeFont = 'geist' | 'inter' | 'roboto' | 'instrument';
|
|
91
|
+
/**
|
|
92
|
+
* Complete snapshot of all user-configurable theme preferences.
|
|
93
|
+
*
|
|
94
|
+
* This interface is serialized to JSON and stored in `localStorage`. Adding
|
|
95
|
+
* new optional fields is backward-compatible; the {@link parseSettings}
|
|
96
|
+
* function merges with {@link defaults} to fill any missing keys.
|
|
97
|
+
*/
|
|
10
98
|
export interface ThemeSettings {
|
|
99
|
+
/** Light/dark/system color scheme preference. */
|
|
11
100
|
mode: ThemeMode;
|
|
101
|
+
/** Seed hex color used to generate the full color scheme. */
|
|
12
102
|
seedColor: string;
|
|
103
|
+
/** WCAG contrast enhancement level for generated colors. */
|
|
13
104
|
contrast: ContrastLevel;
|
|
105
|
+
/** Component spacing density multiplier. */
|
|
14
106
|
density: ThemeDensity;
|
|
107
|
+
/** Global border-radius style for containers. */
|
|
15
108
|
radius: ThemeRadius;
|
|
109
|
+
/** Typeface for body and UI text. */
|
|
16
110
|
font: ThemeFont;
|
|
111
|
+
/** Typeface for display, headline, and title text. */
|
|
17
112
|
titleFont: ThemeFont;
|
|
113
|
+
/** Opacity of the film-grain texture overlay (0–1). `0` disables the grain. */
|
|
18
114
|
grainOpacity: number;
|
|
115
|
+
/** When `true`, disables non-essential CSS transitions and animations. */
|
|
19
116
|
reduceMotion: boolean;
|
|
20
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Reactive singleton that orchestrates the full Moni visual theme.
|
|
120
|
+
*
|
|
121
|
+
* `ThemeEngine` is responsible for:
|
|
122
|
+
* 1. Loading persisted settings from `localStorage` on construction.
|
|
123
|
+
* 2. Listening to OS `prefers-color-scheme` changes when mode is `'system'`.
|
|
124
|
+
* 3. Generating the full 27-role `ColorScheme` from the current seed color.
|
|
125
|
+
* 4. Writing all CSS custom properties to the document root.
|
|
126
|
+
* 5. Persisting settings to `localStorage` on every user-initiated change.
|
|
127
|
+
*
|
|
128
|
+
* **Reactivity:** Public fields `settings`, `resolvedMode`, and `scheme` are
|
|
129
|
+
* Svelte 5 `$state` runes. Any Svelte template reading these fields will
|
|
130
|
+
* automatically re-render when they change.
|
|
131
|
+
*
|
|
132
|
+
* **Singleton pattern:** Do not instantiate this class directly. Always use
|
|
133
|
+
* {@link getThemeEngine}, which returns a module-level singleton and ensures
|
|
134
|
+
* exactly one engine exists per page lifecycle.
|
|
135
|
+
*
|
|
136
|
+
* **SSR compatibility:** The constructor is safe to call in a server context —
|
|
137
|
+
* all DOM/window access is guarded and skipped when unavailable.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* import { getThemeEngine } from '@moni-labs/moni-ui';
|
|
142
|
+
*
|
|
143
|
+
* const theme = getThemeEngine();
|
|
144
|
+
*
|
|
145
|
+
* // Change the seed color — triggers scheme regeneration and DOM update.
|
|
146
|
+
* theme.setSeedColor('#e91e63');
|
|
147
|
+
*
|
|
148
|
+
* // Read the current resolved scheme in a framework-agnostic way.
|
|
149
|
+
* console.log(theme.scheme.primary);
|
|
150
|
+
*
|
|
151
|
+
* // Reset to factory defaults.
|
|
152
|
+
* theme.reset();
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
21
155
|
export declare class ThemeEngine {
|
|
156
|
+
/**
|
|
157
|
+
* The complete set of current user preferences.
|
|
158
|
+
*
|
|
159
|
+
* Mutate via the setter methods (e.g. `setMode`, `setSeedColor`) rather
|
|
160
|
+
* than directly, to ensure DOM updates and persistence are triggered.
|
|
161
|
+
*/
|
|
22
162
|
settings: ThemeSettings;
|
|
163
|
+
/**
|
|
164
|
+
* The resolved light/dark mode after applying the `'system'` logic.
|
|
165
|
+
*
|
|
166
|
+
* Always either `'light'` or `'dark'` — never `'system'`. Use this value
|
|
167
|
+
* for icon toggling, conditional rendering, and `aria-*` attributes.
|
|
168
|
+
*/
|
|
23
169
|
resolvedMode: "light" | "dark";
|
|
170
|
+
/**
|
|
171
|
+
* The currently active 27-role color scheme, derived from `settings.seedColor`,
|
|
172
|
+
* `resolvedMode`, and `settings.contrast`.
|
|
173
|
+
*
|
|
174
|
+
* Reactive: re-assigned every time {@link apply} runs.
|
|
175
|
+
*/
|
|
24
176
|
scheme: ColorScheme;
|
|
177
|
+
/**
|
|
178
|
+
* The OS `prefers-color-scheme` media query list.
|
|
179
|
+
* Used to listen for system-level dark mode changes when mode is `'system'`.
|
|
180
|
+
* `null` in SSR or when `window` is unavailable.
|
|
181
|
+
*/
|
|
25
182
|
private mediaQuery;
|
|
183
|
+
/**
|
|
184
|
+
* Guard flag to prevent attaching duplicate `'change'` listeners to
|
|
185
|
+
* {@link mediaQuery} if `bindSystem` is called more than once.
|
|
186
|
+
*/
|
|
26
187
|
private bound;
|
|
188
|
+
/**
|
|
189
|
+
* Initializes the engine.
|
|
190
|
+
*
|
|
191
|
+
* In browser environments:
|
|
192
|
+
* 1. Loads and merges stored settings from `localStorage`.
|
|
193
|
+
* 2. Captures the `prefers-color-scheme` media query.
|
|
194
|
+
* 3. Attaches a `'change'` listener to react to OS preference updates.
|
|
195
|
+
* 4. Runs the first {@link apply} pass to paint the document immediately.
|
|
196
|
+
*
|
|
197
|
+
* In SSR environments, the constructor is a no-op.
|
|
198
|
+
*/
|
|
27
199
|
constructor();
|
|
200
|
+
/**
|
|
201
|
+
* Attaches a listener to the OS color-scheme media query.
|
|
202
|
+
*
|
|
203
|
+
* Calls {@link apply} whenever the OS switches between light and dark mode,
|
|
204
|
+
* but only when `settings.mode === 'system'` — the effective mode check
|
|
205
|
+
* inside `apply` handles the conditional logic.
|
|
206
|
+
*
|
|
207
|
+
* Idempotent: calling this method multiple times is safe; the `bound` flag
|
|
208
|
+
* ensures only one listener is ever attached.
|
|
209
|
+
*/
|
|
28
210
|
private bindSystem;
|
|
211
|
+
/**
|
|
212
|
+
* Resolves the effective polarity (`'light'` or `'dark'`) from `settings.mode`.
|
|
213
|
+
*
|
|
214
|
+
* When mode is `'system'`, defers to {@link getSystemMode} which reads the
|
|
215
|
+
* OS media query. Otherwise returns the explicit mode directly.
|
|
216
|
+
*
|
|
217
|
+
* @returns `'light'` or `'dark'`.
|
|
218
|
+
*/
|
|
29
219
|
private getEffectiveMode;
|
|
220
|
+
/**
|
|
221
|
+
* Regenerates the color scheme and applies all theme tokens to the document.
|
|
222
|
+
*
|
|
223
|
+
* This is the central "render" method of the engine. It:
|
|
224
|
+
* 1. Resolves the effective mode (`'light'` | `'dark'`).
|
|
225
|
+
* 2. Generates a fresh {@link ColorScheme} from the current seed and contrast.
|
|
226
|
+
* 3. Writes all 81 CSS custom properties (3 namespaces × 27 roles) to `<html>`.
|
|
227
|
+
* 4. Sets `--moni-spacing-density`, `--moni-radius-base`, `--moni-font-sans`,
|
|
228
|
+
* `--moni-font-title`, and `--moni-grain-opacity`.
|
|
229
|
+
* 5. Toggles the `moni-reduce-motion` class on `<html>`.
|
|
230
|
+
*
|
|
231
|
+
* **Side effects:** Mutates `document.documentElement.style` and `classList`.
|
|
232
|
+
* No-op in SSR (`typeof document === 'undefined'`).
|
|
233
|
+
*/
|
|
30
234
|
apply(): void;
|
|
235
|
+
/**
|
|
236
|
+
* Persists the current {@link settings} to `localStorage` and re-applies the theme.
|
|
237
|
+
*
|
|
238
|
+
* Called internally by all setter methods after mutating `settings`.
|
|
239
|
+
* No-op when `localStorage` is unavailable (SSR, private browsing, quota exceeded).
|
|
240
|
+
*/
|
|
31
241
|
persist(): void;
|
|
242
|
+
/**
|
|
243
|
+
* Updates the color scheme polarity.
|
|
244
|
+
*
|
|
245
|
+
* @param mode - `'light'`, `'dark'`, or `'system'` (follows OS preference).
|
|
246
|
+
*/
|
|
32
247
|
setMode(mode: ThemeMode): void;
|
|
248
|
+
/**
|
|
249
|
+
* Updates the seed color used to generate the full color scheme.
|
|
250
|
+
*
|
|
251
|
+
* Automatically prepends `#` if the value doesn't already have one,
|
|
252
|
+
* ensuring the stored value is always a valid 7-character hex string.
|
|
253
|
+
*
|
|
254
|
+
* @param color - A hex color string, with or without the `#` prefix
|
|
255
|
+
* (e.g. `'#4f46e5'` or `'4f46e5'`).
|
|
256
|
+
*/
|
|
33
257
|
setSeedColor(color: string): void;
|
|
258
|
+
/**
|
|
259
|
+
* Updates the WCAG contrast enhancement level for the generated palette.
|
|
260
|
+
*
|
|
261
|
+
* @param contrast - `'standard'` (AA), `'medium'` (enhanced), or `'high'` (AAA).
|
|
262
|
+
*/
|
|
34
263
|
setContrast(contrast: ContrastLevel): void;
|
|
264
|
+
/**
|
|
265
|
+
* Updates the spacing density multiplier.
|
|
266
|
+
*
|
|
267
|
+
* @param density - `'compact'`, `'default'`, `'comfortable'`, or `'spacious'`.
|
|
268
|
+
*/
|
|
35
269
|
setDensity(density: ThemeDensity): void;
|
|
270
|
+
/**
|
|
271
|
+
* Updates the global border-radius style.
|
|
272
|
+
*
|
|
273
|
+
* @param radius - `'sharp'` (0px), `'default'` (12px), or `'rounded'` (20px).
|
|
274
|
+
*/
|
|
36
275
|
setRadius(radius: ThemeRadius): void;
|
|
276
|
+
/**
|
|
277
|
+
* Updates the body/UI typeface.
|
|
278
|
+
*
|
|
279
|
+
* @param font - One of `'geist'` | `'inter'` | `'roboto'` | `'instrument'`.
|
|
280
|
+
*/
|
|
37
281
|
setFont(font: ThemeFont): void;
|
|
282
|
+
/**
|
|
283
|
+
* Updates the display/title typeface.
|
|
284
|
+
*
|
|
285
|
+
* @param font - One of `'geist'` | `'inter'` | `'roboto'` | `'instrument'`.
|
|
286
|
+
*/
|
|
38
287
|
setTitleFont(font: ThemeFont): void;
|
|
288
|
+
/**
|
|
289
|
+
* Updates the grain texture opacity.
|
|
290
|
+
*
|
|
291
|
+
* The value is clamped to [0, 1] before storing. Setting to `0` effectively
|
|
292
|
+
* disables the grain overlay without removing the element from the DOM.
|
|
293
|
+
*
|
|
294
|
+
* @param opacity - A number in the range [0, 1].
|
|
295
|
+
*/
|
|
39
296
|
setGrainOpacity(opacity: number): void;
|
|
297
|
+
/**
|
|
298
|
+
* Enables or disables user-initiated motion reduction.
|
|
299
|
+
*
|
|
300
|
+
* When `true`, the `moni-reduce-motion` class is added to `<html>`, which
|
|
301
|
+
* CSS components use to disable non-essential transitions and animations.
|
|
302
|
+
* This is separate from `prefers-reduced-motion` (OS-level) and allows
|
|
303
|
+
* users to opt in without changing their OS settings.
|
|
304
|
+
*
|
|
305
|
+
* @param reduce - `true` to disable motion, `false` to restore it.
|
|
306
|
+
*/
|
|
40
307
|
setReduceMotion(reduce: boolean): void;
|
|
308
|
+
/**
|
|
309
|
+
* Resets all settings to factory defaults and re-applies the theme.
|
|
310
|
+
*
|
|
311
|
+
* The reset is also persisted to `localStorage` so subsequent page loads
|
|
312
|
+
* start from defaults rather than the old stored values.
|
|
313
|
+
*/
|
|
41
314
|
reset(): void;
|
|
42
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Returns the module-level {@link ThemeEngine} singleton, creating it on first call.
|
|
318
|
+
*
|
|
319
|
+
* This is the **recommended** entry point for all consumers. Calling this
|
|
320
|
+
* function multiple times always returns the same instance.
|
|
321
|
+
*
|
|
322
|
+
* @returns The shared `ThemeEngine` instance.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* import { getThemeEngine } from '@moni-labs/moni-ui';
|
|
327
|
+
*
|
|
328
|
+
* const theme = getThemeEngine();
|
|
329
|
+
* theme.setMode('dark');
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
43
332
|
export declare function getThemeEngine(): ThemeEngine;
|
|
333
|
+
/**
|
|
334
|
+
* Destroys the module-level singleton, forcing the next call to
|
|
335
|
+
* {@link getThemeEngine} to create a fresh instance.
|
|
336
|
+
*
|
|
337
|
+
* **Intended for test isolation only.** Do not call this in application code,
|
|
338
|
+
* as it will cause components sharing the singleton to lose their reference.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```ts
|
|
342
|
+
* afterEach(() => {
|
|
343
|
+
* resetThemeEngine(); // Start each test with a clean engine.
|
|
344
|
+
* });
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
44
347
|
export declare function resetThemeEngine(): void;
|
|
45
348
|
//# sourceMappingURL=theme.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.svelte.d.ts","sourceRoot":"","sources":["../../src/utils/theme.svelte.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"theme.svelte.d.ts","sourceRoot":"","sources":["../../src/utils/theme.svelte.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAyD,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAMzH;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEpD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,UAAU,CAAC;AAE9E;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAE1D;;;;;;;;;GASG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,YAAY,CAAC;AAMpE;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC7B,iDAAiD;IACjD,IAAI,EAAE,SAAS,CAAC;IAChB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,QAAQ,EAAE,aAAa,CAAC;IACxB,4CAA4C;IAC5C,OAAO,EAAE,YAAY,CAAC;IACtB,iDAAiD;IACjD,MAAM,EAAE,WAAW,CAAC;IACpB,qCAAqC;IACrC,IAAI,EAAE,SAAS,CAAC;IAChB,sDAAsD;IACtD,SAAS,EAAE,SAAS,CAAC;IACrB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,YAAY,EAAE,OAAO,CAAC;CACtB;AA4ID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,WAAW;IACvB;;;;;OAKG;IACH,QAAQ,gBAA0C;IAElD;;;;;OAKG;IACH,YAAY,mBAAqC;IAEjD;;;;;OAKG;IACH,MAAM,cAAuF;IAE7F;;;;OAIG;IACH,OAAO,CAAC,UAAU,CAA+B;IAEjD;;;OAGG;IACH,OAAO,CAAC,KAAK,CAAS;IAEtB;;;;;;;;;;OAUG;;IAUH;;;;;;;;;OASG;IACH,OAAO,CAAC,UAAU;IAMlB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IAKxB;;;;;;;;;;;;;OAaG;IACH,KAAK;IA0BL;;;;;OAKG;IACH,OAAO;IASP;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,SAAS;IAKvB;;;;;;;;OAQG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM;IAK1B;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,aAAa;IAKnC;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,YAAY;IAKhC;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,WAAW;IAK7B;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,SAAS;IAKvB;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE,SAAS;IAK5B;;;;;;;OAOG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM;IAK/B;;;;;;;;;OASG;IACH,eAAe,CAAC,MAAM,EAAE,OAAO;IAK/B;;;;;OAKG;IACH,KAAK;CAIL;AAeD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,IAAI,WAAW,CAG5C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,SAE/B"}
|