@maz-ui/mcp 5.0.0-beta.2 → 5.0.0-beta.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +1 -1
  2. package/dist/mcp.d.mts +22 -9
  3. package/dist/mcp.d.ts +22 -9
  4. package/dist/mcp.mjs +160 -83
  5. package/docs/generated-docs/maz-avatar.doc.md +25 -25
  6. package/docs/generated-docs/maz-btn.doc.md +1 -1
  7. package/docs/generated-docs/maz-checkbox.doc.md +16 -17
  8. package/docs/generated-docs/maz-circular-progress-bar.doc.md +1 -1
  9. package/docs/generated-docs/maz-code-highlight.doc.md +11 -0
  10. package/docs/generated-docs/maz-date-picker.doc.md +41 -41
  11. package/docs/generated-docs/maz-drawer.doc.md +7 -8
  12. package/docs/generated-docs/maz-expand-animation.doc.md +4 -4
  13. package/docs/generated-docs/maz-fullscreen-loader.doc.md +5 -5
  14. package/docs/generated-docs/maz-gallery.doc.md +15 -15
  15. package/docs/generated-docs/maz-input-code.doc.md +16 -16
  16. package/docs/generated-docs/maz-input-phone-number.doc.md +42 -38
  17. package/docs/generated-docs/maz-input-price.doc.md +14 -14
  18. package/docs/generated-docs/maz-input-tags.doc.md +16 -16
  19. package/docs/generated-docs/maz-input.doc.md +33 -33
  20. package/docs/generated-docs/maz-lazy-img.doc.md +14 -14
  21. package/docs/generated-docs/maz-loading-bar.doc.md +4 -4
  22. package/docs/generated-docs/maz-pull-to-refresh.doc.md +10 -10
  23. package/docs/generated-docs/maz-radio-buttons.doc.md +17 -17
  24. package/docs/generated-docs/maz-radio.doc.md +16 -16
  25. package/docs/generated-docs/maz-reading-progress-bar.doc.md +4 -4
  26. package/docs/generated-docs/maz-sidebar-content.doc.md +5 -0
  27. package/docs/generated-docs/maz-sidebar-footer.doc.md +5 -0
  28. package/docs/generated-docs/maz-sidebar-group.doc.md +11 -0
  29. package/docs/generated-docs/maz-sidebar-header.doc.md +5 -0
  30. package/docs/generated-docs/maz-sidebar-menu-button.doc.md +27 -0
  31. package/docs/generated-docs/maz-sidebar-menu-item.doc.md +5 -0
  32. package/docs/generated-docs/maz-sidebar-menu-sub.doc.md +16 -0
  33. package/docs/generated-docs/maz-sidebar-menu.doc.md +5 -0
  34. package/docs/generated-docs/maz-sidebar-separator.doc.md +0 -0
  35. package/docs/generated-docs/maz-sidebar-trigger.doc.md +5 -0
  36. package/docs/generated-docs/maz-sidebar.doc.md +36 -0
  37. package/docs/generated-docs/maz-slider.doc.md +1 -1
  38. package/docs/generated-docs/maz-spinner.doc.md +4 -4
  39. package/docs/generated-docs/maz-switch.doc.md +14 -14
  40. package/docs/generated-docs/maz-table.doc.md +5 -5
  41. package/docs/generated-docs/maz-textarea.doc.md +25 -24
  42. package/docs/generated-docs/maz-ticker.doc.md +1 -1
  43. package/docs/generated-docs/maz-window-mockup.doc.md +23 -0
  44. package/docs/src/blog/v4.md +1 -1
  45. package/docs/src/blog/v5.md +5 -7
  46. package/docs/src/components/maz-btn.md +1 -1
  47. package/docs/src/components/maz-code-highlight.md +233 -0
  48. package/docs/src/components/maz-container.md +2 -2
  49. package/docs/src/components/maz-date-picker.md +1 -1
  50. package/docs/src/components/maz-dialog.md +46 -0
  51. package/docs/src/components/maz-icon.md +2 -2
  52. package/docs/src/components/maz-input-phone-number.md +106 -103
  53. package/docs/src/components/maz-sidebar.md +719 -0
  54. package/docs/src/components/maz-textarea.md +27 -1
  55. package/docs/src/components/maz-timeline.md +60 -0
  56. package/docs/src/components/maz-window-mockup.md +249 -0
  57. package/docs/src/directives/click-outside.md +8 -15
  58. package/docs/src/directives/fullscreen-img.md +1 -1
  59. package/docs/src/directives/lazy-img.md +5 -5
  60. package/docs/src/directives/tooltip.md +24 -1
  61. package/docs/src/directives/zoom-img.md +1 -1
  62. package/docs/src/ecosystem/eslint-config.md +95 -1
  63. package/docs/src/{guide/icons.md → ecosystem/icons/index.md} +1 -1
  64. package/docs/src/ecosystem/node/exec-promise.md +87 -0
  65. package/docs/src/ecosystem/node/index.md +53 -0
  66. package/docs/src/ecosystem/node/logger.md +146 -0
  67. package/docs/src/ecosystem/node/print-banner.md +93 -0
  68. package/docs/src/{guide → ecosystem}/nuxt.md +81 -47
  69. package/docs/src/{guide → ecosystem}/themes.md +153 -72
  70. package/docs/src/{guide → ecosystem}/translations.md +1 -1
  71. package/docs/src/ecosystem/utils/camel-case.md +31 -0
  72. package/docs/src/{helpers → ecosystem/utils}/capitalize.md +2 -3
  73. package/docs/src/ecosystem/utils/check-availability.md +79 -0
  74. package/docs/src/ecosystem/utils/cookie.md +80 -0
  75. package/docs/src/{helpers → ecosystem/utils}/currency.md +2 -2
  76. package/docs/src/{helpers → ecosystem/utils}/date.md +2 -2
  77. package/docs/src/ecosystem/utils/debounce-callback.md +38 -0
  78. package/docs/src/ecosystem/utils/debounce-id.md +69 -0
  79. package/docs/src/ecosystem/utils/debounce.md +65 -0
  80. package/docs/src/ecosystem/utils/fetch-locale-ip.md +33 -0
  81. package/docs/src/ecosystem/utils/format-json.md +33 -0
  82. package/docs/src/ecosystem/utils/format-phone-number.md +37 -0
  83. package/docs/src/ecosystem/utils/get-browser-locale.md +29 -0
  84. package/docs/src/ecosystem/utils/get-error-message.md +39 -0
  85. package/docs/src/ecosystem/utils/idle-timeout.md +90 -0
  86. package/docs/src/ecosystem/utils/index.md +60 -0
  87. package/docs/src/ecosystem/utils/is-client.md +32 -0
  88. package/docs/src/ecosystem/utils/is-equal.md +38 -0
  89. package/docs/src/ecosystem/utils/is-server.md +31 -0
  90. package/docs/src/ecosystem/utils/is-standalone-mode.md +43 -0
  91. package/docs/src/ecosystem/utils/kebab-case.md +36 -0
  92. package/docs/src/ecosystem/utils/normalize-string.md +77 -0
  93. package/docs/src/{helpers → ecosystem/utils}/number.md +2 -2
  94. package/docs/src/ecosystem/utils/pascal-case.md +35 -0
  95. package/docs/src/ecosystem/utils/script-loader.md +77 -0
  96. package/docs/src/ecosystem/utils/sleep.md +59 -0
  97. package/docs/src/ecosystem/utils/snake-case.md +36 -0
  98. package/docs/src/ecosystem/utils/swipe-handler.md +91 -0
  99. package/docs/src/ecosystem/utils/textarea-autogrow.md +41 -0
  100. package/docs/src/ecosystem/utils/throttle-id.md +48 -0
  101. package/docs/src/ecosystem/utils/throttle.md +57 -0
  102. package/docs/src/ecosystem/utils/truthy-filter.md +31 -0
  103. package/docs/src/ecosystem/utils/types/deep-key-of.md +48 -0
  104. package/docs/src/ecosystem/utils/types/deep-partial.md +42 -0
  105. package/docs/src/ecosystem/utils/types/deep-required.md +39 -0
  106. package/docs/src/ecosystem/utils/types/flatten-object-keys.md +44 -0
  107. package/docs/src/ecosystem/utils/types/generic-instance-type.md +42 -0
  108. package/docs/src/ecosystem/utils/types/infer-maybe-ref.md +35 -0
  109. package/docs/src/ecosystem/utils/upper-first.md +32 -0
  110. package/docs/src/ecosystem/utils/user-visibility.md +69 -0
  111. package/docs/src/guide/getting-started.md +15 -13
  112. package/docs/src/guide/global-defaults.md +101 -0
  113. package/docs/src/guide/maz-ui-provider.md +6 -3
  114. package/docs/src/guide/migration-v4.md +13 -9
  115. package/docs/src/guide/migration-v5.md +67 -12
  116. package/docs/src/guide/resolvers.md +7 -7
  117. package/docs/src/guide/tailwind.md +4 -0
  118. package/docs/src/guide/vue.md +4 -4
  119. package/docs/src/index.md +12 -12
  120. package/docs/src/plugins/aos.md +1 -1
  121. package/docs/src/plugins/wait.md +1 -1
  122. package/package.json +6 -5
  123. package/docs/src/helpers/camel-case.md +0 -14
  124. package/docs/src/helpers/check-availability.md +0 -14
  125. package/docs/src/helpers/debounce-callback.md +0 -14
  126. package/docs/src/helpers/debounce-id.md +0 -14
  127. package/docs/src/helpers/debounce.md +0 -14
  128. package/docs/src/helpers/is-client.md +0 -14
  129. package/docs/src/helpers/is-equal.md +0 -14
  130. package/docs/src/helpers/is-standalone-mode.md +0 -14
  131. package/docs/src/helpers/kebab-case.md +0 -14
  132. package/docs/src/helpers/normalize-string.md +0 -14
  133. package/docs/src/helpers/pascal-case.md +0 -14
  134. package/docs/src/helpers/script-loader.md +0 -14
  135. package/docs/src/helpers/sleep.md +0 -14
  136. package/docs/src/helpers/snake-case.md +0 -14
  137. package/docs/src/helpers/throttle-id.md +0 -14
  138. package/docs/src/helpers/throttle.md +0 -14
  139. /package/docs/src/{guide → ecosystem/icons}/icon-set.md +0 -0
  140. /package/docs/src/{guide → ecosystem}/mcp.md +0 -0
  141. /package/docs/src/{helpers → ecosystem/utils}/country-code-to-unicode-flag.md +0 -0
  142. /package/docs/src/{helpers → ecosystem/utils}/get-country-flag-url.md +0 -0
@@ -126,11 +126,13 @@ export default defineNuxtConfig({
126
126
  theme: {
127
127
  preset: 'maz-ui', // 'maz-ui' | 'pristine' | 'ocean' | 'obsidian' | 'nova' | custom object
128
128
  strategy: 'runtime', // 'runtime' | 'buildtime'
129
- darkModeStrategy: 'class', // 'class' | 'media' | 'auto'
129
+ darkModeStrategy: 'class', // 'class' | 'media'
130
+ darkClass: 'dark', // class on <html> when colorMode === 'dark' (default: 'dark')
131
+ lightClass: 'light', // class on <html> when colorMode === 'light' (default: 'light')
130
132
  overrides: {
131
133
  colors: {
132
- light: { primary: '220 100% 50%' },
133
- dark: { primary: '220 100% 70%' }
134
+ light: { primary: 'oklch(0.65 0.19 254)' },
135
+ dark: { primary: 'oklch(0.72 0.18 254)' }
134
136
  }
135
137
  },
136
138
  mode: 'both', // 'light' | 'dark' | 'both'
@@ -150,6 +152,13 @@ export default defineNuxtConfig({
150
152
  autoImport: true, // All components globally available
151
153
  },
152
154
 
155
+ // Global component defaults (priority: instance prop > defaults[Component] > defaults.global > library default)
156
+ defaults: {
157
+ global: { roundedSize: 'lg' }, // cross-cutting (roundedSize, size)
158
+ MazBtn: { roundedSize: 'full' }, // per-component, wins over global
159
+ MazCard: { bordered: false, elevation: true },
160
+ },
161
+
153
162
  // Plugins (not enabled by default)
154
163
  plugins: {
155
164
  aos: true,
@@ -220,16 +229,16 @@ const theme = {
220
229
  overrides: {
221
230
  colors: {
222
231
  light: {
223
- primary: '220 100% 50%',
224
- secondary: '220 14% 96%',
225
- surface: '0 0% 100%',
226
- foreground: '222 84% 5%',
232
+ primary: 'oklch(0.6 0.18 254)',
233
+ secondary: 'oklch(0.96 0.01 254)',
234
+ surface: 'oklch(1 0 0)',
235
+ foreground: 'oklch(0.16 0.02 254)',
227
236
  },
228
237
  dark: {
229
- primary: '220 100% 70%',
230
- secondary: '220 14% 4%',
231
- surface: '222 84% 5%',
232
- foreground: '210 40% 98%',
238
+ primary: 'oklch(0.72 0.18 254)',
239
+ secondary: 'oklch(0.22 0.02 254)',
240
+ surface: 'oklch(0.16 0.02 254)',
241
+ foreground: 'oklch(0.96 0.005 254)',
233
242
  }
234
243
  },
235
244
  // Override other theme properties...
@@ -245,7 +254,14 @@ const theme = {
245
254
  strategy: 'runtime', // 'runtime' (recommended) | 'buildtime'
246
255
 
247
256
  // Dark mode handling
248
- darkModeStrategy: 'class', // 'class' | 'media' | 'auto'
257
+ darkModeStrategy: 'class', // 'class' | 'media'
258
+
259
+ // Class added to <html> when colorMode === 'dark' (default: 'dark')
260
+ darkClass: 'dark',
261
+
262
+ // Class added to <html> when colorMode === 'light' (default: 'light')
263
+ // Mirror of darkClass — used to force `color-scheme: only light`.
264
+ lightClass: 'light',
249
265
 
250
266
  // Persist the active preset name in the `maz-preset` cookie so the
251
267
  // user's last-used theme is restored on reload. Default: true.
@@ -253,6 +269,26 @@ const theme = {
253
269
  }
254
270
  ```
255
271
 
272
+ ### Global Component Defaults
273
+
274
+ Set default prop values once for every component. Resolution priority, per prop: instance prop > `defaults[Component]` > `defaults.global` > library default. A global default never overrides a prop set on the instance.
275
+
276
+ ```ts
277
+ const defaults = {
278
+ // Cross-cutting tokens applied to every component that exposes them
279
+ global: {
280
+ roundedSize: 'lg', // 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full'
281
+ size: 'sm', // 'mini' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'
282
+ },
283
+ // Per-component defaults, strongly typed as Partial<ComponentNameProps>, win over `global`
284
+ MazBtn: { roundedSize: 'full' },
285
+ MazCard: { bordered: false, elevation: true },
286
+ MazContainer: { bordered: false },
287
+ }
288
+ ```
289
+
290
+ See the [Global component defaults guide](/guide/global-defaults) for the full list of globalizable props.
291
+
256
292
  ## Theme Strategies Explained
257
293
 
258
294
  ### Runtime (Recommended)
@@ -379,41 +415,39 @@ import { definePreset } from '@maz-ui/themes'
379
415
 
380
416
  export const customTheme = definePreset({
381
417
  base: 'maz-ui',
382
- name: 'custom',
383
- foundation: {
384
- 'base-font-size': '14px',
385
- 'font-family': `Manrope, sans-serif, system-ui, -apple-system`,
386
- 'space': '0.25rem',
387
- 'border-width': '0.0625rem',
388
- },
389
- scales: {
390
- rounded: { md: '0.7rem' },
391
- },
392
- colors: {
393
- light: {
394
- primary: '350 100% 50%', // Custom pink
395
- secondary: '350 14% 96%',
396
- surface: '0 0% 100%',
397
- foreground: '222 84% 5%',
398
- muted: '210 40% 96%',
399
- accent: '210 40% 90%',
400
- destructive: '0 84% 60%',
401
- border: '214 32% 91%',
402
- input: '214 32% 91%',
403
- ring: '350 100% 50%',
418
+ overrides: {
419
+ name: 'custom',
420
+ foundation: {
421
+ 'base-font-size': '14px',
422
+ 'font-family': `Manrope, sans-serif, system-ui, -apple-system`,
423
+ 'space': '0.25rem',
424
+ 'border-width': '0.0625rem',
425
+ },
426
+ scales: {
427
+ rounded: { md: '0.7rem' },
428
+ },
429
+ colors: {
430
+ light: {
431
+ primary: 'oklch(0.65 0.27 5)', // Custom pink
432
+ secondary: 'oklch(0.96 0.01 5)',
433
+ surface: 'oklch(1 0 0)',
434
+ foreground: 'oklch(0.16 0.02 254)',
435
+ muted: 'oklch(0.6 0.01 254)',
436
+ accent: 'oklch(0.7 0.05 5)',
437
+ destructive: 'oklch(0.6 0.22 27)',
438
+ divider: 'oklch(0.92 0.005 254)',
439
+ },
440
+ dark: {
441
+ primary: 'oklch(0.75 0.22 5)',
442
+ secondary: 'oklch(0.24 0.02 5)',
443
+ surface: 'oklch(0.16 0.02 254)',
444
+ foreground: 'oklch(0.96 0.005 254)',
445
+ muted: 'oklch(0.6 0.01 254)',
446
+ accent: 'oklch(0.3 0.04 5)',
447
+ destructive: 'oklch(0.55 0.2 27)',
448
+ divider: 'oklch(0.3 0.01 254)',
449
+ }
404
450
  },
405
- dark: {
406
- primary: '350 100% 70%',
407
- secondary: '350 14% 4%',
408
- surface: '222 84% 5%',
409
- foreground: '210 40% 98%',
410
- muted: '217 33% 17%',
411
- accent: '217 33% 17%',
412
- destructive: '0 62% 30%',
413
- border: '217 33% 17%',
414
- input: '217 33% 17%',
415
- ring: '350 100% 70%',
416
- }
417
451
  },
418
452
  })
419
453
 
@@ -429,7 +463,7 @@ export default defineNuxtConfig({
429
463
  ```
430
464
 
431
465
  ::: tip Subtree Overrides with MazUiProvider
432
- You can use [`MazUiProvider`](./maz-ui-provider.md) within a Nuxt app to override theme or translations in a specific subtree, while the module handles global defaults.
466
+ You can use [`MazUiProvider`](../guide/maz-ui-provider.md) within a Nuxt app to override theme or translations in a specific subtree, while the module handles global defaults.
433
467
  :::
434
468
 
435
469
  ## Troubleshooting
@@ -1,19 +1,21 @@
1
1
  ---
2
2
  title: Theming
3
- description: Modern and performant theme system for Maz-UI with TypeScript, HSL CSS variables and flexible strategies.
3
+ description: Modern and performant theme system for Maz-UI built on native CSS features (light-dark(), color-scheme, color-mix(in oklch)) for v5.
4
4
  ---
5
5
 
6
6
  # {{ $frontmatter.title }}
7
7
 
8
- {{ $frontmatter.description }}
8
+ Modern and performant theme system for Maz-UI built on native CSS features (`light-dark()`, `color-scheme`, `color-mix(in oklch)`) for v5.
9
9
 
10
10
  <NpmBadge package="@maz-ui/themes"></NpmBadge>
11
11
 
12
12
  ## Features
13
13
 
14
- - **Modern HSL CSS Variables** - Maximum flexibility with colors
15
- - **Smart Dark Mode** - Automatic support with `prefers-color-scheme`
16
- - **Automatic Generation** - Color scales (50-950) created automatically
14
+ - **Native `light-dark()` + `color-scheme`** - Modern CSS theming with zero JS overhead for the light/dark switch
15
+ - **Native widget theming** - `color-scheme` makes scrollbars, native `<select>`, date pickers and autofill follow the active mode automatically
16
+ - **Animated theme switch** - Optional full-page View Transitions via `setColorMode(..., { animate: true })`
17
+ - **Anti-FART** - `<meta name="color-scheme">` injected at boot to prevent any Flash of inAccurate coloR Theme (no setup needed)
18
+ - **Automatic color scales** - `--maz-X-50` through `--maz-X-950` derived via OKLCh relative color syntax — perceptually uniform and chroma-preserving
17
19
  - **Performance Strategies** - Runtime injection or build-time generation according to your needs
18
20
  - **Strict TypeScript** - Complete types for perfect DX
19
21
  - **Zero FOUC** - Pass the preset object up front; the full CSS is injected synchronously on first paint
@@ -44,13 +46,17 @@ app.use(MazUi, {
44
46
  darkModeStrategy: 'class', // 'class' | 'media' (only if mode is `both`)
45
47
  mode: 'both', // 'light' | 'dark' | 'both' (supported color modes)
46
48
  colorMode: 'auto', // 'auto' | 'light' | 'dark' (initial color mode, only if mode is 'both')
49
+ // Class added to <html> when dark mode is forced (default: 'dark')
50
+ darkClass: 'dark',
51
+ // Class added to <html> when light mode is forced (default: 'light')
52
+ lightClass: 'light',
47
53
  persistPreset: true, // remember the active preset name across reloads
48
54
  }
49
55
  })
50
56
  ```
51
57
 
52
58
  ::: tip Alternative: MazUiProvider
53
- You can also initialize the theme via the [`MazUiProvider`](./maz-ui-provider.md) component for lazy-loaded pages or subtree-scoped themes.
59
+ You can also initialize the theme via the [`MazUiProvider`](../guide/maz-ui-provider.md) component for lazy-loaded pages or subtree-scoped themes.
54
60
  :::
55
61
 
56
62
  ### 2. Setup your CSS to support theme foundation and dark mode
@@ -89,10 +95,12 @@ const { toggleDarkMode, isDark, updateTheme } = useTheme()
89
95
 
90
96
  - `preset`: The theme preset to use
91
97
  - `overrides` (optional): Override specific parts of the theme
92
- - `strategy` (optional): The rendering strategy to use
93
- - `darkModeStrategy` (optional): The dark mode strategy to use, only if you use mode `both`
94
- - `mode` (optional): The supported color modes to use (light, dark, both)
95
- - `colorMode` (optional): The initial color mode to use (only if mode is 'both')
98
+ - `strategy` (optional, default `'runtime'`): The rendering strategy to use — `'runtime' | 'buildtime'`
99
+ - `darkModeStrategy` (optional, default `'class'`): The dark mode strategy `'class' | 'media'`, only if you use mode `both`
100
+ - `mode` (optional, default `'both'`): The supported color modes `'light' | 'dark' | 'both'`
101
+ - `colorMode` (optional, default `'auto'`): The initial color mode `'light' | 'dark' | 'auto'` (only if mode is `'both'`)
102
+ - `darkClass` (optional, default `'dark'`): Class added to `<html>` when `colorMode === 'dark'`
103
+ - `lightClass` (optional, default `'light'`): Class added to `<html>` when `colorMode === 'light'` — mirror of `darkClass`
96
104
  - `persistPreset` (optional, default `true`): Persist the active preset name in the `maz-preset` cookie so it is restored on reload.
97
105
 
98
106
  ### Preset persistence
@@ -118,6 +126,48 @@ Useful when:
118
126
  - You want zero theme-related cookies (privacy / regulatory).
119
127
  - The active preset is fully driven by the consumer app and no end-user switching is exposed.
120
128
 
129
+ ## Color modes and class toggling
130
+
131
+ `darkClass` and `lightClass` interact with `darkModeStrategy` to control how `<html>` is decorated when the user picks an explicit mode.
132
+
133
+ ### `darkModeStrategy: 'class'` (default)
134
+
135
+ - `setColorMode('dark')` adds `darkClass` (default `.dark`) to `<html>` → `color-scheme: only dark`.
136
+ - `setColorMode('light')` adds `lightClass` (default `.light`) to `<html>` → `color-scheme: only light`.
137
+ - `setColorMode('auto')` removes both classes → `color-scheme: light dark` lets the browser follow the system `prefers-color-scheme`.
138
+
139
+ Forcing both classes on the root ensures native widgets (scrollbars, native `<select>`, date pickers, autofill backgrounds, …) match the explicit user choice rather than the OS preference.
140
+
141
+ ### `darkModeStrategy: 'media'`
142
+
143
+ - No class is ever added to `<html>`.
144
+ - The browser always follows `prefers-color-scheme` via `color-scheme: light dark`.
145
+ - `setColorMode()` still updates the persisted cookie but does **not** force a visual override.
146
+
147
+ ## Animated theme switch
148
+
149
+ For a full-page animated swap (rather than per-variable color tweens), pass `{ animate: true }` to `setColorMode` or `toggleDarkMode`:
150
+
151
+ ```vue
152
+ <script setup>
153
+ import { useTheme } from '@maz-ui/themes'
154
+
155
+ const { toggleDarkMode, setColorMode } = useTheme()
156
+
157
+ async function onToggle() {
158
+ await toggleDarkMode({ animate: true })
159
+ }
160
+
161
+ async function forceDark() {
162
+ await setColorMode('dark', { animate: true })
163
+ }
164
+ </script>
165
+ ```
166
+
167
+ - Wraps the switch in `document.startViewTransition()` so the browser captures a snapshot of the page before/after and crossfades between them.
168
+ - The View Transition glue is **lazy-imported** — when `animate` is not used, it stays out of the boot bundle.
169
+ - **Graceful degradation:** in browsers that don't support the API, the change is applied immediately with no animation (no error thrown).
170
+
121
171
  ## Interactive Demo
122
172
 
123
173
  <ComponentDemo title="Real-time theme control">
@@ -395,14 +445,14 @@ const customTheme = await definePreset({
395
445
  },
396
446
  colors: {
397
447
  light: {
398
- primary: '280 100% 60%',
399
- secondary: '300 50% 90%',
400
- accent: '260 100% 70%'
448
+ primary: 'oklch(0.62 0.24 305)',
449
+ secondary: 'oklch(0.94 0.04 320)',
450
+ accent: 'oklch(0.7 0.22 290)'
401
451
  },
402
452
  dark: {
403
- primary: '280 100% 70%',
404
- secondary: '300 30% 20%',
405
- accent: '260 100% 80%'
453
+ primary: 'oklch(0.72 0.22 305)',
454
+ secondary: 'oklch(0.28 0.06 320)',
455
+ accent: 'oklch(0.78 0.2 290)'
406
456
  }
407
457
  }
408
458
  },
@@ -449,16 +499,16 @@ const brandTheme = await definePreset({
449
499
  },
450
500
  colors: {
451
501
  light: {
452
- primary: '210 100% 50%',
453
- secondary: '210 40% 96%',
454
- surface: '210 20% 98%',
455
- accent: '280 100% 70%'
502
+ primary: 'oklch(0.6 0.18 254)',
503
+ secondary: 'oklch(0.96 0.01 254)',
504
+ surface: 'oklch(0.99 0.005 254)',
505
+ accent: 'oklch(0.7 0.22 305)'
456
506
  },
457
507
  dark: {
458
- primary: '210 100% 60%',
459
- secondary: '210 40% 15%',
460
- surface: '210 20% 8%',
461
- accent: '280 100% 80%'
508
+ primary: 'oklch(0.7 0.18 254)',
509
+ secondary: 'oklch(0.22 0.03 254)',
510
+ surface: 'oklch(0.18 0.02 254)',
511
+ accent: 'oklch(0.78 0.2 305)'
462
512
  }
463
513
  }
464
514
  }
@@ -530,7 +580,7 @@ const surfaceTheme = definePreset({
530
580
  },
531
581
  container: {
532
582
  // Cards / dialogs / popovers / drawers — light = page surface, dark = a tier above
533
- bg: { light: 'var(--maz-surface)', dark: 'var(--maz-surface-300)' },
583
+ bg: { light: 'var(--maz-surface)', dark: 'var(--maz-color-surface-300)' },
534
584
  },
535
585
  input: {
536
586
  // All form-control surfaces
@@ -543,23 +593,58 @@ const surfaceTheme = definePreset({
543
593
 
544
594
  Components consume these via `maz:bg-container` / `maz:bg-input` Tailwind utilities, so a single override propagates everywhere — no per-component class hunt.
545
595
 
596
+ ### Dialog sizing
597
+
598
+ `components.dialog` controls the width of [`MazDialog`](./../components/maz-dialog.md) on tablet and up. The two keys are emitted as `--maz-dialog-max-width` / `--maz-dialog-min-width` and consumed by the component through `var(--maz-dialog-max-width, 38rem)` / `var(--maz-dialog-min-width, 32rem)`:
599
+
600
+ ```typescript
601
+ const wideDialogTheme = definePreset({
602
+ base: 'maz-ui',
603
+ overrides: {
604
+ name: 'wide-dialogs',
605
+ components: {
606
+ dialog: {
607
+ 'max-width': '48rem',
608
+ 'min-width': '36rem',
609
+ },
610
+ },
611
+ },
612
+ })
613
+ ```
614
+
615
+ Both values are in `rem`, so they scale with the preset's `base-font-size`. Bundled presets anchored on `14px` use `38rem` / `32rem`; `ocean` (`16px`) ships scaled rem values (`33.25rem` / `28rem`) to keep the same rendered pixel width. The `max-width` / `min-width` props on `MazDialog` still override the preset per instance.
616
+
546
617
  ## useTheme Composable API
547
618
 
548
619
  ```typescript
549
620
  const {
550
621
  // Reactive state
622
+ preset, // ComputedRef<ThemePreset>
551
623
  presetName, // ComputedRef<string>
552
- colorMode, // ComputedRef<'light' | 'dark' | 'auto'>
624
+ colorMode, // Ref<'light' | 'dark' | 'auto'> — also accepts assignment (computed setter)
553
625
  isDark, // ComputedRef<boolean>
554
626
  strategy, // ComputedRef<'runtime' | 'buildtime'>
627
+ mode, // ComputedRef<'light' | 'dark' | 'both'>
628
+ darkModeStrategy, // ComputedRef<'class' | 'media'>
555
629
 
556
630
  // Actions
557
- updateTheme, // (preset: ThemePreset | ThemePresetOverrides) => void
558
- setColorMode, // (mode: 'light' | 'dark' | 'auto') => void
559
- toggleDarkMode // () => void
631
+ updateTheme, // (preset: ThemePreset | ThemePresetName | ThemePresetOverrides) => Promise<void>
632
+ setColorMode, // (mode: 'light' | 'dark' | 'auto', options?: { animate?: boolean }) => Promise<void>
633
+ toggleDarkMode, // (options?: { animate?: boolean }) => Promise<void>
560
634
  } = useTheme()
635
+
636
+ // Set the color mode imperatively
637
+ await setColorMode('dark')
638
+
639
+ // Or assign to `colorMode` — it's a computed with a setter
640
+ colorMode.value = 'dark'
641
+
642
+ // Animated full-page switch via View Transitions
643
+ await toggleDarkMode({ animate: true })
561
644
  ```
562
645
 
646
+ `setColorMode` and `toggleDarkMode` are **async** (`Promise<void>`). The promise resolves once the change — and the optional View Transition — has been applied. Callers can ignore the return value when no transition is needed.
647
+
563
648
  ### Advanced Usage Examples
564
649
 
565
650
  ```vue
@@ -623,8 +708,8 @@ const customPreset = definePreset({
623
708
  overrides: {
624
709
  name: 'custom',
625
710
  colors: {
626
- light: { primary: '221.2 83.2% 53.3%' },
627
- dark: { primary: '217.2 91.2% 59.8%' },
711
+ light: { primary: 'oklch(0.6 0.18 254)' },
712
+ dark: { primary: 'oklch(0.7 0.18 254)' },
628
713
  },
629
714
  },
630
715
  })
@@ -687,8 +772,8 @@ const customPreset = definePreset({
687
772
  overrides: {
688
773
  name: 'custom',
689
774
  colors: {
690
- light: { primary: '221.2 83.2% 53.3%' },
691
- dark: { primary: '217.2 91.2% 59.8%' },
775
+ light: { primary: 'oklch(0.6 0.18 254)' },
776
+ dark: { primary: 'oklch(0.7 0.18 254)' },
692
777
  },
693
778
  },
694
779
  })
@@ -729,8 +814,8 @@ const customPreset = definePreset({
729
814
  overrides: {
730
815
  name: 'custom',
731
816
  colors: {
732
- light: { primary: '221.2 83.2% 53.3%' },
733
- dark: { primary: '217.2 91.2% 59.8%' },
817
+ light: { primary: 'oklch(0.6 0.18 254)' },
818
+ dark: { primary: 'oklch(0.7 0.18 254)' },
734
819
  },
735
820
  },
736
821
  })
@@ -819,7 +904,7 @@ const styleTag = createThemeStylesheet(css, {
819
904
 
820
905
  ## Token Reference
821
906
 
822
- Every preset emits the same set of CSS variables on `:root` (and a `.dark` block when `mode: 'both'`). Use these names directly in your own CSS — `var(--maz-primary)`, `calc(var(--maz-space) * 4)`, etc.
907
+ Every preset emits the same set of CSS variables on `:root`. With `mode: 'both'`, each base color is a single `light-dark(L, D)` declaration that the browser resolves to the active scheme. Use these names directly in your own CSS — `var(--maz-primary)`, `calc(var(--maz-space) * 4)`, etc.
823
908
 
824
909
  ### Foundation
825
910
 
@@ -893,16 +978,27 @@ Per-component knobs under `components.<key>`. All optional — omit to fall back
893
978
  | `btn.font-weight` | `--maz-btn-font-weight` | Font-weight on `.m-btn`. Defaults to `'500'`. |
894
979
  | `container.bg.light` / `.dark` | `--maz-container-bg` (per mode) | Background of `Card`, `Container`, `Dialog`, `Popover`, `Drawer`, … Defaults to `var(--maz-surface)`. Bridged to `--color-container`. |
895
980
  | `input.bg.light` / `.dark` | `--maz-input-bg` (per mode) | Background of `Input`, `Textarea`, `Select`, `Checkbox`, … Defaults to `var(--maz-surface)` light, `var(--maz-surface-400)` dark. Bridged to `--color-input`. |
981
+ | `dialog.max-width` | `--maz-dialog-max-width` | Max-width of `MazDialog` on tablet and up. Defaults to `38rem` (`33.25rem` on `ocean`). Overridable via the `max-width` prop. |
982
+ | `dialog.min-width` | `--maz-dialog-min-width` | Min-width of `MazDialog` on tablet and up. Defaults to `32rem` (`28rem` on `ocean`). Overridable via the `min-width` prop. |
896
983
 
897
984
  ### Sample output
898
985
 
986
+ Each base color is emitted as a `light-dark()` value; scales `--maz-X-50` through `--maz-X-950` are derived via OKLCh relative color syntax so they automatically follow base color overrides at runtime, preserving chroma at every step.
987
+
899
988
  ```css
900
989
  :root {
901
- /* Main colors */
902
- --maz-primary: oklch(0.6495 0.1913 253.63);
903
- --maz-primary-foreground: oklch(1 0 0);
904
- --maz-surface: oklch(1 0 0);
905
- --maz-foreground: oklch(0.2573 0.0068 248.09);
990
+ color-scheme: light dark;
991
+
992
+ /* Base colors — one declaration each, resolved by the browser */
993
+ --maz-primary: light-dark(oklch(0.65 0.19 254), oklch(0.72 0.18 254));
994
+ --maz-primary-foreground: light-dark(oklch(1 0 0), oklch(0.16 0.01 254));
995
+ --maz-surface: light-dark(oklch(1 0 0), oklch(0.18 0.01 254));
996
+ --maz-foreground: light-dark(oklch(0.26 0.01 254), oklch(0.96 0.005 254));
997
+
998
+ /* Auto-generated 50–950 scale — derived via relative color syntax */
999
+ --maz-primary-500: var(--maz-primary);
1000
+ --maz-primary-600: oklch(from var(--maz-primary) clamp(0, calc(l - 0.07), 1) c h);
1001
+ /* ... */
906
1002
 
907
1003
  /* Foundation */
908
1004
  --maz-base-font-size: 14px;
@@ -914,35 +1010,19 @@ Per-component knobs under `components.<key>`. All optional — omit to fall back
914
1010
  /* Scales */
915
1011
  --maz-rounded-md: 0.7rem;
916
1012
  --maz-shadow-style-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), …;
917
-
918
- /* Auto-generated 50–950 scale */
919
- --maz-primary-500: oklch(…);
920
- /* ... */
921
1013
  }
922
- ```
923
-
924
- ### Dark Mode
925
1014
 
926
- ```css
927
- .dark {
928
- --maz-surface: 235 16% 15%;
929
- --maz-foreground: 0 0% 85%;
930
- /* Variables automatically adapted */
931
- }
932
-
933
- /* Or with media query */
934
- @media (prefers-color-scheme: dark) {
935
- :root {
936
- --maz-surface: 235 16% 15%;
937
- --maz-foreground: 0 0% 85%;
938
- }
939
- }
1015
+ /* With darkModeStrategy: 'class' — explicit user choice overrides the system */
1016
+ .dark { color-scheme: only dark; }
1017
+ .light { color-scheme: only light; }
940
1018
  ```
941
1019
 
1020
+ For deeper detail on the generated CSS contract, see the [`@maz-ui/themes` README](https://github.com/LouisMazel/maz-ui/tree/master/packages/themes#generated-css-variables).
1021
+
942
1022
 
943
1023
  ## Usage with Nuxt
944
1024
 
945
- For Nuxt users, check the [dedicated Nuxt documentation](/guide/nuxt) which covers installation and framework-specific configuration.
1025
+ For Nuxt users, check the [dedicated Nuxt documentation](/ecosystem/nuxt) which covers installation and framework-specific configuration.
946
1026
 
947
1027
  ## Migration from Legacy System
948
1028
 
@@ -965,20 +1045,21 @@ export default defineConfig({
965
1045
  ```typescript [After (@maz-ui/themes)]
966
1046
  // main.ts
967
1047
  import { definePreset, mazUi } from '@maz-ui/themes'
1048
+ import { MazUiTheme } from '@maz-ui/themes/plugin'
968
1049
 
969
1050
  const myTheme = definePreset({
970
1051
  base: mazUi,
971
1052
  overrides: {
972
1053
  colors: {
973
1054
  light: {
974
- primary: '210 100% 56%',
975
- secondary: '164 76% 46%'
1055
+ primary: 'oklch(0.65 0.19 254)',
1056
+ secondary: 'oklch(0.72 0.16 168)'
976
1057
  }
977
1058
  }
978
1059
  }
979
1060
  })
980
1061
 
981
- app.use(MazThemePlugin, { preset: myTheme })
1062
+ app.use(MazUiTheme, { preset: myTheme })
982
1063
  ```
983
1064
 
984
1065
  :::
@@ -1007,14 +1088,14 @@ const customPreset = await definePreset({
1007
1088
  name: 'custom-purple',
1008
1089
  colors: {
1009
1090
  light: {
1010
- 'primary': '280 100% 60%',
1011
- 'secondary': '300 50% 90%',
1012
- 'accent': '260 100% 70%'
1091
+ 'primary': 'oklch(0.62 0.24 305)',
1092
+ 'secondary': 'oklch(0.94 0.04 320)',
1093
+ 'accent': 'oklch(0.7 0.22 290)'
1013
1094
  },
1014
1095
  dark: {
1015
- 'primary': '280 100% 70%',
1016
- 'secondary': '300 30% 20%',
1017
- 'accent': '260 100% 80%'
1096
+ 'primary': 'oklch(0.72 0.22 305)',
1097
+ 'secondary': 'oklch(0.28 0.06 320)',
1098
+ 'accent': 'oklch(0.78 0.2 290)'
1018
1099
  }
1019
1100
  }
1020
1101
  }
@@ -73,7 +73,7 @@ app.use(MazUi, {
73
73
  ```
74
74
 
75
75
  ::: tip Alternative: MazUiProvider
76
- You can also provide translations via the [`MazUiProvider`](./maz-ui-provider.md) component for lazy-loaded pages or subtree-scoped configurations.
76
+ You can also provide translations via the [`MazUiProvider`](../guide/maz-ui-provider.md) component for lazy-loaded pages or subtree-scoped configurations.
77
77
  :::
78
78
 
79
79
  ## How it works
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: camelCase
3
+ description: Convert a kebab-case string to camelCase by stripping dashes and uppercasing the following letter.
4
+ ---
5
+
6
+ # {{ $frontmatter.title }}
7
+
8
+ {{ $frontmatter.description }}
9
+
10
+ ## Usage
11
+
12
+ ```ts
13
+ import { camelCase } from '@maz-ui/utils'
14
+
15
+ camelCase('my-component-name') // → 'myComponentName'
16
+ camelCase('hello-world') // → 'helloWorld'
17
+ ```
18
+
19
+ ## API
20
+
21
+ ```ts
22
+ function camelCase(str: string): string
23
+ ```
24
+
25
+ | Parameter | Type | Description |
26
+ | --------- | -------- | --------------------- |
27
+ | `str` | `string` | The string to convert |
28
+
29
+ ## Notes
30
+
31
+ `camelCase` is intentionally minimal — it only handles `kebab-case` input. For more general normalization (snake_case, spaces, PascalCase), use [`normalizeString`](./normalize-string) with the `case: 'camelCase'` option.
@@ -10,8 +10,7 @@ description: The module capitalize is a function that adds a capital letter to a
10
10
  <MazInput v-model="stringValue" />
11
11
 
12
12
  <div
13
- style="padding: 16px; margin-top: 16px; background-color: var(--maz-surface-300);"
14
- class="flex flex-center rounded gap-05"
13
+ class="maz:flex maz:flex-center maz:rounded-md maz:gap-0.5 maz:p-4 maz:mt-16 maz:bg-surface-300"
15
14
  >
16
15
  formatted value: <strong>{{ stringFormatted }}</strong>
17
16
  </div>
@@ -32,7 +31,7 @@ const stringFormatted = computed(() =>
32
31
  <MazInput v-model="stringValue" />
33
32
 
34
33
  <div
35
- style="padding: 16px; margin-top: 16px; background-color: var(--maz-surface-300);"
34
+ class="flex flex-center rounded-md gap-0.5 p-4 mt-16 bg-surface-300"
36
35
  >
37
36
  {{ stringFormatted }}
38
37
  </div>