@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.
Files changed (323) hide show
  1. package/README.md +52 -194
  2. package/custom-elements.json +1636 -350
  3. package/dist/actions/index.d.ts +6 -0
  4. package/dist/actions/index.d.ts.map +1 -1
  5. package/dist/actions/index.js +6 -0
  6. package/dist/components/_base/field-styles.d.ts +51 -16
  7. package/dist/components/_base/field-styles.d.ts.map +1 -1
  8. package/dist/components/_base/field-styles.js +164 -36
  9. package/dist/components/_base/index.d.ts +25 -0
  10. package/dist/components/_base/index.d.ts.map +1 -1
  11. package/dist/components/_base/index.js +25 -0
  12. package/dist/components/_base/interaction-styles.d.ts +39 -12
  13. package/dist/components/_base/interaction-styles.d.ts.map +1 -1
  14. package/dist/components/_base/interaction-styles.js +85 -33
  15. package/dist/components/_base/moni-element.d.ts +43 -8
  16. package/dist/components/_base/moni-element.d.ts.map +1 -1
  17. package/dist/components/_base/moni-element.js +43 -8
  18. package/dist/components/_base/shared-styles.d.ts +41 -17
  19. package/dist/components/_base/shared-styles.d.ts.map +1 -1
  20. package/dist/components/_base/shared-styles.js +113 -21
  21. package/dist/components/index.d.ts +6 -0
  22. package/dist/components/index.d.ts.map +1 -1
  23. package/dist/components/index.js +6 -0
  24. package/dist/components/loading-shapes.d.ts +6 -0
  25. package/dist/components/loading-shapes.d.ts.map +1 -1
  26. package/dist/components/loading-shapes.js +6 -0
  27. package/dist/components/moni-app-bar.d.ts +128 -33
  28. package/dist/components/moni-app-bar.d.ts.map +1 -1
  29. package/dist/components/moni-app-bar.js +121 -26
  30. package/dist/components/moni-badge.d.ts +122 -14
  31. package/dist/components/moni-badge.d.ts.map +1 -1
  32. package/dist/components/moni-badge.js +122 -14
  33. package/dist/components/moni-bottom-sheet.d.ts +120 -15
  34. package/dist/components/moni-bottom-sheet.d.ts.map +1 -1
  35. package/dist/components/moni-bottom-sheet.js +116 -12
  36. package/dist/components/moni-button-group.d.ts +53 -27
  37. package/dist/components/moni-button-group.d.ts.map +1 -1
  38. package/dist/components/moni-button-group.js +49 -23
  39. package/dist/components/moni-button-segment.d.ts +28 -8
  40. package/dist/components/moni-button-segment.d.ts.map +1 -1
  41. package/dist/components/moni-button-segment.js +27 -7
  42. package/dist/components/moni-button.d.ts +51 -32
  43. package/dist/components/moni-button.d.ts.map +1 -1
  44. package/dist/components/moni-button.js +50 -31
  45. package/dist/components/moni-card.d.ts +91 -31
  46. package/dist/components/moni-card.d.ts.map +1 -1
  47. package/dist/components/moni-card.js +86 -26
  48. package/dist/components/moni-carousel.d.ts +67 -17
  49. package/dist/components/moni-carousel.d.ts.map +1 -1
  50. package/dist/components/moni-carousel.js +59 -16
  51. package/dist/components/moni-checkbox.d.ts +122 -17
  52. package/dist/components/moni-checkbox.d.ts.map +1 -1
  53. package/dist/components/moni-checkbox.js +118 -14
  54. package/dist/components/moni-chip.d.ts +56 -30
  55. package/dist/components/moni-chip.d.ts.map +1 -1
  56. package/dist/components/moni-chip.js +51 -25
  57. package/dist/components/moni-color-field.d.ts +44 -6
  58. package/dist/components/moni-color-field.d.ts.map +1 -1
  59. package/dist/components/moni-color-field.js +43 -5
  60. package/dist/components/moni-context-menu.d.ts +44 -22
  61. package/dist/components/moni-context-menu.d.ts.map +1 -1
  62. package/dist/components/moni-context-menu.js +43 -21
  63. package/dist/components/moni-dialog.d.ts +107 -15
  64. package/dist/components/moni-dialog.d.ts.map +1 -1
  65. package/dist/components/moni-dialog.js +105 -14
  66. package/dist/components/moni-divider.d.ts +50 -15
  67. package/dist/components/moni-divider.d.ts.map +1 -1
  68. package/dist/components/moni-divider.js +49 -14
  69. package/dist/components/moni-expansion.d.ts +44 -8
  70. package/dist/components/moni-expansion.d.ts.map +1 -1
  71. package/dist/components/moni-expansion.js +43 -7
  72. package/dist/components/moni-fab-menu.d.ts +39 -20
  73. package/dist/components/moni-fab-menu.d.ts.map +1 -1
  74. package/dist/components/moni-fab-menu.js +38 -19
  75. package/dist/components/moni-fab.d.ts +49 -23
  76. package/dist/components/moni-fab.d.ts.map +1 -1
  77. package/dist/components/moni-fab.js +46 -20
  78. package/dist/components/moni-file-field.d.ts +54 -14
  79. package/dist/components/moni-file-field.d.ts.map +1 -1
  80. package/dist/components/moni-file-field.js +53 -13
  81. package/dist/components/moni-icon.d.ts +78 -11
  82. package/dist/components/moni-icon.d.ts.map +1 -1
  83. package/dist/components/moni-icon.js +77 -10
  84. package/dist/components/moni-list-item.d.ts +61 -30
  85. package/dist/components/moni-list-item.d.ts.map +1 -1
  86. package/dist/components/moni-list-item.js +55 -24
  87. package/dist/components/moni-list.d.ts +37 -13
  88. package/dist/components/moni-list.d.ts.map +1 -1
  89. package/dist/components/moni-list.js +36 -12
  90. package/dist/components/moni-loading-indicator.d.ts +38 -11
  91. package/dist/components/moni-loading-indicator.d.ts.map +1 -1
  92. package/dist/components/moni-loading-indicator.js +37 -10
  93. package/dist/components/moni-menu-item.d.ts +31 -8
  94. package/dist/components/moni-menu-item.d.ts.map +1 -1
  95. package/dist/components/moni-menu-item.js +30 -7
  96. package/dist/components/moni-menu.d.ts +58 -33
  97. package/dist/components/moni-menu.d.ts.map +1 -1
  98. package/dist/components/moni-menu.js +51 -26
  99. package/dist/components/moni-morph-modal.d.ts +7 -1
  100. package/dist/components/moni-morph-modal.d.ts.map +1 -1
  101. package/dist/components/moni-morph-modal.js +46 -24
  102. package/dist/components/moni-nav-item.d.ts +50 -10
  103. package/dist/components/moni-nav-item.d.ts.map +1 -1
  104. package/dist/components/moni-nav-item.js +48 -8
  105. package/dist/components/moni-nav.d.ts +57 -22
  106. package/dist/components/moni-nav.d.ts.map +1 -1
  107. package/dist/components/moni-nav.js +53 -18
  108. package/dist/components/moni-progress.d.ts +108 -20
  109. package/dist/components/moni-progress.d.ts.map +1 -1
  110. package/dist/components/moni-progress.js +104 -16
  111. package/dist/components/moni-radio.d.ts +106 -14
  112. package/dist/components/moni-radio.d.ts.map +1 -1
  113. package/dist/components/moni-radio.js +104 -13
  114. package/dist/components/moni-ripple.d.ts +121 -10
  115. package/dist/components/moni-ripple.d.ts.map +1 -1
  116. package/dist/components/moni-ripple.js +120 -9
  117. package/dist/components/moni-segmented-button.d.ts +31 -11
  118. package/dist/components/moni-segmented-button.d.ts.map +1 -1
  119. package/dist/components/moni-segmented-button.js +30 -10
  120. package/dist/components/moni-select-option.d.ts +43 -9
  121. package/dist/components/moni-select-option.d.ts.map +1 -1
  122. package/dist/components/moni-select-option.js +41 -7
  123. package/dist/components/moni-select.d.ts +59 -2
  124. package/dist/components/moni-select.d.ts.map +1 -1
  125. package/dist/components/moni-select.js +58 -1
  126. package/dist/components/moni-shape.d.ts +1 -1
  127. package/dist/components/moni-side-sheet.d.ts +56 -19
  128. package/dist/components/moni-side-sheet.d.ts.map +1 -1
  129. package/dist/components/moni-side-sheet.js +53 -16
  130. package/dist/components/moni-slider.d.ts +56 -25
  131. package/dist/components/moni-slider.d.ts.map +1 -1
  132. package/dist/components/moni-slider.js +55 -24
  133. package/dist/components/moni-snackbar.d.ts +86 -17
  134. package/dist/components/moni-snackbar.d.ts.map +1 -1
  135. package/dist/components/moni-snackbar.js +85 -16
  136. package/dist/components/moni-split-button.d.ts +38 -9
  137. package/dist/components/moni-split-button.d.ts.map +1 -1
  138. package/dist/components/moni-split-button.js +37 -8
  139. package/dist/components/moni-step.d.ts +42 -9
  140. package/dist/components/moni-step.d.ts.map +1 -1
  141. package/dist/components/moni-step.js +41 -8
  142. package/dist/components/moni-stepper.d.ts +43 -6
  143. package/dist/components/moni-stepper.d.ts.map +1 -1
  144. package/dist/components/moni-stepper.js +42 -5
  145. package/dist/components/moni-switch.d.ts +103 -16
  146. package/dist/components/moni-switch.d.ts.map +1 -1
  147. package/dist/components/moni-switch.js +99 -13
  148. package/dist/components/moni-tab.d.ts +35 -8
  149. package/dist/components/moni-tab.d.ts.map +1 -1
  150. package/dist/components/moni-tab.js +34 -7
  151. package/dist/components/moni-tabs.d.ts +51 -13
  152. package/dist/components/moni-tabs.d.ts.map +1 -1
  153. package/dist/components/moni-tabs.js +48 -10
  154. package/dist/components/moni-text-field.d.ts +55 -10
  155. package/dist/components/moni-text-field.d.ts.map +1 -1
  156. package/dist/components/moni-text-field.js +54 -9
  157. package/dist/components/moni-textarea.d.ts +51 -21
  158. package/dist/components/moni-textarea.d.ts.map +1 -1
  159. package/dist/components/moni-textarea.js +48 -18
  160. package/dist/components/moni-time-picker.d.ts +41 -11
  161. package/dist/components/moni-time-picker.d.ts.map +1 -1
  162. package/dist/components/moni-time-picker.js +40 -10
  163. package/dist/components/moni-toolbar.d.ts +43 -15
  164. package/dist/components/moni-toolbar.d.ts.map +1 -1
  165. package/dist/components/moni-toolbar.js +42 -14
  166. package/dist/components/moni-tooltip.d.ts +55 -25
  167. package/dist/components/moni-tooltip.d.ts.map +1 -1
  168. package/dist/components/moni-tooltip.js +54 -24
  169. package/dist/components/moni-typography.d.ts +43 -18
  170. package/dist/components/moni-typography.d.ts.map +1 -1
  171. package/dist/components/moni-typography.js +42 -17
  172. package/dist/index.d.ts +47 -0
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/index.js +59 -2
  175. package/dist/styles/tailwind.css +67 -0
  176. package/dist/styles/tokens.css +111 -99
  177. package/dist/utils/color.d.ts +181 -2
  178. package/dist/utils/color.d.ts.map +1 -1
  179. package/dist/utils/color.js +182 -4
  180. package/dist/utils/theme.svelte.d.ts +305 -2
  181. package/dist/utils/theme.svelte.d.ts.map +1 -1
  182. package/dist/utils/theme.svelte.js +331 -2
  183. package/dist/web-components.d.ts +28 -0
  184. package/dist/web-components.d.ts.map +1 -1
  185. package/dist/web-components.js +29 -2
  186. package/package.json +1 -1
  187. package/src/actions/index.ts +7 -0
  188. package/src/components/_base/field-styles.ts +165 -37
  189. package/src/components/_base/index.ts +27 -0
  190. package/src/components/_base/interaction-styles.ts +86 -33
  191. package/src/components/_base/moni-element.ts +44 -8
  192. package/src/components/_base/shared-styles.ts +114 -21
  193. package/src/components/index.ts +7 -0
  194. package/src/components/loading-shapes.ts +7 -0
  195. package/src/components/moni-app-bar.ts +127 -26
  196. package/src/components/moni-badge.ts +128 -14
  197. package/src/components/moni-bottom-sheet.ts +125 -13
  198. package/src/components/moni-button-group.ts +50 -23
  199. package/src/components/moni-button-segment.ts +28 -7
  200. package/src/components/moni-button.ts +51 -31
  201. package/src/components/moni-card.ts +90 -26
  202. package/src/components/moni-carousel.ts +67 -16
  203. package/src/components/moni-checkbox.ts +125 -14
  204. package/src/components/moni-chip.ts +52 -25
  205. package/src/components/moni-color-field.ts +44 -5
  206. package/src/components/moni-context-menu.ts +44 -21
  207. package/src/components/moni-dialog.ts +111 -14
  208. package/src/components/moni-divider.ts +50 -14
  209. package/src/components/moni-expansion.ts +44 -7
  210. package/src/components/moni-fab-menu.ts +39 -19
  211. package/src/components/moni-fab.ts +47 -20
  212. package/src/components/moni-file-field.ts +54 -13
  213. package/src/components/moni-icon.ts +80 -10
  214. package/src/components/moni-list-item.ts +56 -24
  215. package/src/components/moni-list.ts +37 -12
  216. package/src/components/moni-loading-indicator.ts +38 -10
  217. package/src/components/moni-menu-item.ts +31 -7
  218. package/src/components/moni-menu.ts +52 -26
  219. package/src/components/moni-morph-modal.ts +58 -24
  220. package/src/components/moni-nav-item.ts +49 -8
  221. package/src/components/moni-nav.ts +54 -18
  222. package/src/components/moni-progress.ts +109 -16
  223. package/src/components/moni-radio.ts +111 -13
  224. package/src/components/moni-ripple.ts +126 -9
  225. package/src/components/moni-segmented-button.ts +31 -10
  226. package/src/components/moni-select-option.ts +42 -7
  227. package/src/components/moni-select.ts +79 -1
  228. package/src/components/moni-side-sheet.ts +54 -16
  229. package/src/components/moni-slider.ts +56 -24
  230. package/src/components/moni-snackbar.ts +90 -16
  231. package/src/components/moni-split-button.ts +38 -8
  232. package/src/components/moni-step.ts +42 -8
  233. package/src/components/moni-stepper.ts +43 -5
  234. package/src/components/moni-switch.ts +106 -13
  235. package/src/components/moni-tab.ts +35 -7
  236. package/src/components/moni-tabs.ts +49 -10
  237. package/src/components/moni-text-field.ts +55 -9
  238. package/src/components/moni-textarea.ts +49 -18
  239. package/src/components/moni-time-picker.ts +41 -10
  240. package/src/components/moni-toolbar.ts +43 -14
  241. package/src/components/moni-tooltip.ts +55 -24
  242. package/src/components/moni-typography.ts +43 -17
  243. package/src/index.ts +67 -3
  244. package/src/styles/tailwind.css +67 -0
  245. package/src/styles/tokens.css +111 -99
  246. package/src/types/svelte-runes.d.ts +64 -2
  247. package/src/utils/color.ts +286 -5
  248. package/src/utils/theme.svelte.ts +411 -2
  249. package/src/web-components.ts +31 -2
  250. package/dist/assets/shapes/arch.svg +0 -1
  251. package/dist/assets/shapes/arrow.svg +0 -1
  252. package/dist/assets/shapes/boom.svg +0 -1
  253. package/dist/assets/shapes/burst.svg +0 -1
  254. package/dist/assets/shapes/circle.svg +0 -1
  255. package/dist/assets/shapes/clamshell.svg +0 -1
  256. package/dist/assets/shapes/diamond.svg +0 -1
  257. package/dist/assets/shapes/fan.svg +0 -1
  258. package/dist/assets/shapes/flower.svg +0 -1
  259. package/dist/assets/shapes/gem.svg +0 -1
  260. package/dist/assets/shapes/ghost-ish.svg +0 -1
  261. package/dist/assets/shapes/heart.svg +0 -1
  262. package/dist/assets/shapes/leaf-clover4.svg +0 -1
  263. package/dist/assets/shapes/leaf-clover8.svg +0 -1
  264. package/dist/assets/shapes/loading-indicator.svg +0 -1
  265. package/dist/assets/shapes/oval.svg +0 -1
  266. package/dist/assets/shapes/pentagon.svg +0 -1
  267. package/dist/assets/shapes/pill.svg +0 -1
  268. package/dist/assets/shapes/pixel-circle.svg +0 -1
  269. package/dist/assets/shapes/pixel-triangle.svg +0 -1
  270. package/dist/assets/shapes/puffy-diamond.svg +0 -1
  271. package/dist/assets/shapes/puffy.svg +0 -1
  272. package/dist/assets/shapes/semicircle.svg +0 -1
  273. package/dist/assets/shapes/sided-cookie12.svg +0 -1
  274. package/dist/assets/shapes/sided-cookie4.svg +0 -1
  275. package/dist/assets/shapes/sided-cookie6.svg +0 -1
  276. package/dist/assets/shapes/sided-cookie7.svg +0 -1
  277. package/dist/assets/shapes/sided-cookie9.svg +0 -1
  278. package/dist/assets/shapes/slanted.svg +0 -1
  279. package/dist/assets/shapes/soft-boom.svg +0 -1
  280. package/dist/assets/shapes/soft-burst.svg +0 -1
  281. package/dist/assets/shapes/square.svg +0 -1
  282. package/dist/assets/shapes/sunny.svg +0 -1
  283. package/dist/assets/shapes/triangle.svg +0 -1
  284. package/dist/assets/shapes/very-sunny.svg +0 -1
  285. package/dist/assets/shapes/wavy-circle.svg +0 -1
  286. package/dist/assets/shapes/wavy.svg +0 -1
  287. package/src/assets/shapes/arch.svg +0 -1
  288. package/src/assets/shapes/arrow.svg +0 -1
  289. package/src/assets/shapes/boom.svg +0 -1
  290. package/src/assets/shapes/burst.svg +0 -1
  291. package/src/assets/shapes/circle.svg +0 -1
  292. package/src/assets/shapes/clamshell.svg +0 -1
  293. package/src/assets/shapes/diamond.svg +0 -1
  294. package/src/assets/shapes/fan.svg +0 -1
  295. package/src/assets/shapes/flower.svg +0 -1
  296. package/src/assets/shapes/gem.svg +0 -1
  297. package/src/assets/shapes/ghost-ish.svg +0 -1
  298. package/src/assets/shapes/heart.svg +0 -1
  299. package/src/assets/shapes/leaf-clover4.svg +0 -1
  300. package/src/assets/shapes/leaf-clover8.svg +0 -1
  301. package/src/assets/shapes/loading-indicator.svg +0 -1
  302. package/src/assets/shapes/oval.svg +0 -1
  303. package/src/assets/shapes/pentagon.svg +0 -1
  304. package/src/assets/shapes/pill.svg +0 -1
  305. package/src/assets/shapes/pixel-circle.svg +0 -1
  306. package/src/assets/shapes/pixel-triangle.svg +0 -1
  307. package/src/assets/shapes/puffy-diamond.svg +0 -1
  308. package/src/assets/shapes/puffy.svg +0 -1
  309. package/src/assets/shapes/semicircle.svg +0 -1
  310. package/src/assets/shapes/sided-cookie12.svg +0 -1
  311. package/src/assets/shapes/sided-cookie4.svg +0 -1
  312. package/src/assets/shapes/sided-cookie6.svg +0 -1
  313. package/src/assets/shapes/sided-cookie7.svg +0 -1
  314. package/src/assets/shapes/sided-cookie9.svg +0 -1
  315. package/src/assets/shapes/slanted.svg +0 -1
  316. package/src/assets/shapes/soft-boom.svg +0 -1
  317. package/src/assets/shapes/soft-burst.svg +0 -1
  318. package/src/assets/shapes/square.svg +0 -1
  319. package/src/assets/shapes/sunny.svg +0 -1
  320. package/src/assets/shapes/triangle.svg +0 -1
  321. package/src/assets/shapes/very-sunny.svg +0 -1
  322. package/src/assets/shapes/wavy-circle.svg +0 -1
  323. package/src/assets/shapes/wavy.svg +0 -1
@@ -1,9 +1,63 @@
1
1
  /**
2
- * ThemeEngine — gestión reactiva del tema visual de Moni.
3
- * Soporta: modo claro/oscuro, color semilla, densidad, radio, fuente y grain.
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 { generateScheme, applySchemeToDocument, getDefaultSeed } from './color.js';
46
+ // ─────────────────────────────────────────────────────────────────────────────
47
+ // Constants
48
+ // ─────────────────────────────────────────────────────────────────────────────
49
+ /**
50
+ * `localStorage` key under which theme settings are persisted.
51
+ *
52
+ * The `v1` suffix allows future breaking changes to use a new key (e.g.
53
+ * `moni-theme-settings-v2`) without conflicting with stale stored values.
54
+ */
6
55
  const STORAGE_KEY = 'moni-theme-settings-v1';
56
+ /**
57
+ * Factory default values for all {@link ThemeSettings} fields.
58
+ *
59
+ * Applied when no stored settings exist or when {@link ThemeEngine.reset} is called.
60
+ */
7
61
  const defaults = {
8
62
  mode: 'system',
9
63
  seedColor: getDefaultSeed(),
@@ -15,22 +69,55 @@ const defaults = {
15
69
  grainOpacity: 0.03,
16
70
  reduceMotion: false
17
71
  };
72
+ // ─────────────────────────────────────────────────────────────────────────────
73
+ // Private helpers
74
+ // ─────────────────────────────────────────────────────────────────────────────
75
+ /**
76
+ * Parses a raw JSON string from `localStorage` into a {@link ThemeSettings} object.
77
+ *
78
+ * Unknown or missing keys are filled in from {@link defaults}, making this
79
+ * function safe to call after schema additions (forward-compatible reads).
80
+ * Malformed JSON falls back to defaults silently rather than throwing.
81
+ *
82
+ * @param raw - The raw string from `localStorage.getItem(STORAGE_KEY)`,
83
+ * or `null` if the key was not present.
84
+ * @returns A fully populated `ThemeSettings` object.
85
+ */
18
86
  function parseSettings(raw) {
19
87
  if (!raw)
20
88
  return { ...defaults };
21
89
  try {
22
90
  const parsed = JSON.parse(raw);
91
+ // Merge: stored values override defaults; missing keys fall back to defaults.
23
92
  return { ...defaults, ...parsed };
24
93
  }
25
94
  catch {
95
+ // JSON.parse failed (corrupted storage). Fall back to defaults.
26
96
  return { ...defaults };
27
97
  }
28
98
  }
99
+ /**
100
+ * Resolves the effective light/dark mode based on the OS media query.
101
+ *
102
+ * Safe to call in SSR — returns `'light'` when `window` is not available,
103
+ * which is the least disruptive default for server-rendered HTML.
104
+ *
105
+ * @returns `'dark'` if the user's OS prefers dark mode, otherwise `'light'`.
106
+ */
29
107
  function getSystemMode() {
30
108
  if (typeof window === 'undefined')
31
109
  return 'light';
32
110
  return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
33
111
  }
112
+ /**
113
+ * Maps a {@link ThemeDensity} token to its numeric multiplier.
114
+ *
115
+ * The returned value is written to `--moni-spacing-density`. Components that
116
+ * support density scaling multiply their base spacing by this factor.
117
+ *
118
+ * @param density - The density label to resolve.
119
+ * @returns A numeric multiplier: `0.75` | `1.0` | `1.25` | `1.6`.
120
+ */
34
121
  function densityValue(density) {
35
122
  switch (density) {
36
123
  case 'compact':
@@ -43,6 +130,15 @@ function densityValue(density) {
43
130
  return 1;
44
131
  }
45
132
  }
133
+ /**
134
+ * Maps a {@link ThemeRadius} token to a CSS length value.
135
+ *
136
+ * The returned string is written to `--moni-radius-base` and is consumed by
137
+ * component styles that derive their border-radius from this token.
138
+ *
139
+ * @param radius - The radius label to resolve.
140
+ * @returns A CSS length string: `'0px'` | `'12px'` | `'20px'`.
141
+ */
46
142
  function radiusValue(radius) {
47
143
  switch (radius) {
48
144
  case 'sharp':
@@ -53,6 +149,15 @@ function radiusValue(radius) {
53
149
  return '12px';
54
150
  }
55
151
  }
152
+ /**
153
+ * Maps a {@link ThemeFont} token to a CSS `font-family` stack string.
154
+ *
155
+ * The stacks follow the pattern `'Primary Font', system-ui fallback` to
156
+ * ensure graceful degradation when the primary font is not loaded.
157
+ *
158
+ * @param font - The font label to resolve.
159
+ * @returns A CSS `font-family` value string ready to pass to `setProperty`.
160
+ */
56
161
  function fontFamily(font) {
57
162
  switch (font) {
58
163
  case 'inter':
@@ -62,15 +167,94 @@ function fontFamily(font) {
62
167
  case 'instrument':
63
168
  return "'Instrument Serif', Georgia, serif";
64
169
  default:
170
+ // 'geist' is the Moni brand default.
65
171
  return "'Geist', system-ui, sans-serif";
66
172
  }
67
173
  }
174
+ // ─────────────────────────────────────────────────────────────────────────────
175
+ // ThemeEngine class
176
+ // ─────────────────────────────────────────────────────────────────────────────
177
+ /**
178
+ * Reactive singleton that orchestrates the full Moni visual theme.
179
+ *
180
+ * `ThemeEngine` is responsible for:
181
+ * 1. Loading persisted settings from `localStorage` on construction.
182
+ * 2. Listening to OS `prefers-color-scheme` changes when mode is `'system'`.
183
+ * 3. Generating the full 27-role `ColorScheme` from the current seed color.
184
+ * 4. Writing all CSS custom properties to the document root.
185
+ * 5. Persisting settings to `localStorage` on every user-initiated change.
186
+ *
187
+ * **Reactivity:** Public fields `settings`, `resolvedMode`, and `scheme` are
188
+ * Svelte 5 `$state` runes. Any Svelte template reading these fields will
189
+ * automatically re-render when they change.
190
+ *
191
+ * **Singleton pattern:** Do not instantiate this class directly. Always use
192
+ * {@link getThemeEngine}, which returns a module-level singleton and ensures
193
+ * exactly one engine exists per page lifecycle.
194
+ *
195
+ * **SSR compatibility:** The constructor is safe to call in a server context —
196
+ * all DOM/window access is guarded and skipped when unavailable.
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * import { getThemeEngine } from '@moni-labs/moni-ui';
201
+ *
202
+ * const theme = getThemeEngine();
203
+ *
204
+ * // Change the seed color — triggers scheme regeneration and DOM update.
205
+ * theme.setSeedColor('#e91e63');
206
+ *
207
+ * // Read the current resolved scheme in a framework-agnostic way.
208
+ * console.log(theme.scheme.primary);
209
+ *
210
+ * // Reset to factory defaults.
211
+ * theme.reset();
212
+ * ```
213
+ */
68
214
  export class ThemeEngine {
215
+ /**
216
+ * Initializes the engine.
217
+ *
218
+ * In browser environments:
219
+ * 1. Loads and merges stored settings from `localStorage`.
220
+ * 2. Captures the `prefers-color-scheme` media query.
221
+ * 3. Attaches a `'change'` listener to react to OS preference updates.
222
+ * 4. Runs the first {@link apply} pass to paint the document immediately.
223
+ *
224
+ * In SSR environments, the constructor is a no-op.
225
+ */
69
226
  constructor() {
227
+ /**
228
+ * The complete set of current user preferences.
229
+ *
230
+ * Mutate via the setter methods (e.g. `setMode`, `setSeedColor`) rather
231
+ * than directly, to ensure DOM updates and persistence are triggered.
232
+ */
70
233
  this.settings = $state({ ...defaults });
234
+ /**
235
+ * The resolved light/dark mode after applying the `'system'` logic.
236
+ *
237
+ * Always either `'light'` or `'dark'` — never `'system'`. Use this value
238
+ * for icon toggling, conditional rendering, and `aria-*` attributes.
239
+ */
71
240
  this.resolvedMode = $state('light');
241
+ /**
242
+ * The currently active 27-role color scheme, derived from `settings.seedColor`,
243
+ * `resolvedMode`, and `settings.contrast`.
244
+ *
245
+ * Reactive: re-assigned every time {@link apply} runs.
246
+ */
72
247
  this.scheme = $state(generateScheme(defaults.seedColor, 'light', defaults.contrast));
248
+ /**
249
+ * The OS `prefers-color-scheme` media query list.
250
+ * Used to listen for system-level dark mode changes when mode is `'system'`.
251
+ * `null` in SSR or when `window` is unavailable.
252
+ */
73
253
  this.mediaQuery = null;
254
+ /**
255
+ * Guard flag to prevent attaching duplicate `'change'` listeners to
256
+ * {@link mediaQuery} if `bindSystem` is called more than once.
257
+ */
74
258
  this.bound = false;
75
259
  if (typeof window !== 'undefined') {
76
260
  this.settings = parseSettings(localStorage.getItem(STORAGE_KEY));
@@ -79,17 +263,49 @@ export class ThemeEngine {
79
263
  this.apply();
80
264
  }
81
265
  }
266
+ /**
267
+ * Attaches a listener to the OS color-scheme media query.
268
+ *
269
+ * Calls {@link apply} whenever the OS switches between light and dark mode,
270
+ * but only when `settings.mode === 'system'` — the effective mode check
271
+ * inside `apply` handles the conditional logic.
272
+ *
273
+ * Idempotent: calling this method multiple times is safe; the `bound` flag
274
+ * ensures only one listener is ever attached.
275
+ */
82
276
  bindSystem() {
83
277
  if (this.bound || !this.mediaQuery)
84
278
  return;
85
279
  this.bound = true;
86
280
  this.mediaQuery.addEventListener('change', () => this.apply());
87
281
  }
282
+ /**
283
+ * Resolves the effective polarity (`'light'` or `'dark'`) from `settings.mode`.
284
+ *
285
+ * When mode is `'system'`, defers to {@link getSystemMode} which reads the
286
+ * OS media query. Otherwise returns the explicit mode directly.
287
+ *
288
+ * @returns `'light'` or `'dark'`.
289
+ */
88
290
  getEffectiveMode() {
89
291
  if (this.settings.mode === 'system')
90
292
  return getSystemMode();
91
293
  return this.settings.mode;
92
294
  }
295
+ /**
296
+ * Regenerates the color scheme and applies all theme tokens to the document.
297
+ *
298
+ * This is the central "render" method of the engine. It:
299
+ * 1. Resolves the effective mode (`'light'` | `'dark'`).
300
+ * 2. Generates a fresh {@link ColorScheme} from the current seed and contrast.
301
+ * 3. Writes all 81 CSS custom properties (3 namespaces × 27 roles) to `<html>`.
302
+ * 4. Sets `--moni-spacing-density`, `--moni-radius-base`, `--moni-font-sans`,
303
+ * `--moni-font-title`, and `--moni-grain-opacity`.
304
+ * 5. Toggles the `moni-reduce-motion` class on `<html>`.
305
+ *
306
+ * **Side effects:** Mutates `document.documentElement.style` and `classList`.
307
+ * No-op in SSR (`typeof document === 'undefined'`).
308
+ */
93
309
  apply() {
94
310
  if (typeof document === 'undefined')
95
311
  return;
@@ -98,11 +314,14 @@ export class ThemeEngine {
98
314
  this.scheme = generateScheme(this.settings.seedColor, mode, this.settings.contrast);
99
315
  applySchemeToDocument(this.scheme, mode, document);
100
316
  const root = document.documentElement;
317
+ // Write non-color theme tokens.
101
318
  root.style.setProperty('--moni-spacing-density', densityValue(this.settings.density).toString());
102
319
  root.style.setProperty('--moni-radius-base', radiusValue(this.settings.radius));
103
320
  root.style.setProperty('--moni-font-sans', fontFamily(this.settings.font));
104
321
  root.style.setProperty('--moni-font-title', fontFamily(this.settings.titleFont));
105
322
  root.style.setProperty('--moni-grain-opacity', this.settings.grainOpacity.toString());
323
+ // Toggle motion reduction class. CSS `@media (prefers-reduced-motion)`
324
+ // handles native OS preference; this class covers user-initiated opt-in.
106
325
  if (this.settings.reduceMotion) {
107
326
  root.classList.add('moni-reduce-motion');
108
327
  }
@@ -110,59 +329,169 @@ export class ThemeEngine {
110
329
  root.classList.remove('moni-reduce-motion');
111
330
  }
112
331
  }
332
+ /**
333
+ * Persists the current {@link settings} to `localStorage` and re-applies the theme.
334
+ *
335
+ * Called internally by all setter methods after mutating `settings`.
336
+ * No-op when `localStorage` is unavailable (SSR, private browsing, quota exceeded).
337
+ */
113
338
  persist() {
114
339
  if (typeof localStorage !== 'undefined') {
115
340
  localStorage.setItem(STORAGE_KEY, JSON.stringify(this.settings));
116
341
  }
117
342
  this.apply();
118
343
  }
344
+ // ── Public setters ──────────────────────────────────────────────────────
345
+ /**
346
+ * Updates the color scheme polarity.
347
+ *
348
+ * @param mode - `'light'`, `'dark'`, or `'system'` (follows OS preference).
349
+ */
119
350
  setMode(mode) {
120
351
  this.settings.mode = mode;
121
352
  this.persist();
122
353
  }
354
+ /**
355
+ * Updates the seed color used to generate the full color scheme.
356
+ *
357
+ * Automatically prepends `#` if the value doesn't already have one,
358
+ * ensuring the stored value is always a valid 7-character hex string.
359
+ *
360
+ * @param color - A hex color string, with or without the `#` prefix
361
+ * (e.g. `'#4f46e5'` or `'4f46e5'`).
362
+ */
123
363
  setSeedColor(color) {
124
364
  this.settings.seedColor = color.startsWith('#') ? color : `#${color}`;
125
365
  this.persist();
126
366
  }
367
+ /**
368
+ * Updates the WCAG contrast enhancement level for the generated palette.
369
+ *
370
+ * @param contrast - `'standard'` (AA), `'medium'` (enhanced), or `'high'` (AAA).
371
+ */
127
372
  setContrast(contrast) {
128
373
  this.settings.contrast = contrast;
129
374
  this.persist();
130
375
  }
376
+ /**
377
+ * Updates the spacing density multiplier.
378
+ *
379
+ * @param density - `'compact'`, `'default'`, `'comfortable'`, or `'spacious'`.
380
+ */
131
381
  setDensity(density) {
132
382
  this.settings.density = density;
133
383
  this.persist();
134
384
  }
385
+ /**
386
+ * Updates the global border-radius style.
387
+ *
388
+ * @param radius - `'sharp'` (0px), `'default'` (12px), or `'rounded'` (20px).
389
+ */
135
390
  setRadius(radius) {
136
391
  this.settings.radius = radius;
137
392
  this.persist();
138
393
  }
394
+ /**
395
+ * Updates the body/UI typeface.
396
+ *
397
+ * @param font - One of `'geist'` | `'inter'` | `'roboto'` | `'instrument'`.
398
+ */
139
399
  setFont(font) {
140
400
  this.settings.font = font;
141
401
  this.persist();
142
402
  }
403
+ /**
404
+ * Updates the display/title typeface.
405
+ *
406
+ * @param font - One of `'geist'` | `'inter'` | `'roboto'` | `'instrument'`.
407
+ */
143
408
  setTitleFont(font) {
144
409
  this.settings.titleFont = font;
145
410
  this.persist();
146
411
  }
412
+ /**
413
+ * Updates the grain texture opacity.
414
+ *
415
+ * The value is clamped to [0, 1] before storing. Setting to `0` effectively
416
+ * disables the grain overlay without removing the element from the DOM.
417
+ *
418
+ * @param opacity - A number in the range [0, 1].
419
+ */
147
420
  setGrainOpacity(opacity) {
148
421
  this.settings.grainOpacity = Math.max(0, Math.min(1, opacity));
149
422
  this.persist();
150
423
  }
424
+ /**
425
+ * Enables or disables user-initiated motion reduction.
426
+ *
427
+ * When `true`, the `moni-reduce-motion` class is added to `<html>`, which
428
+ * CSS components use to disable non-essential transitions and animations.
429
+ * This is separate from `prefers-reduced-motion` (OS-level) and allows
430
+ * users to opt in without changing their OS settings.
431
+ *
432
+ * @param reduce - `true` to disable motion, `false` to restore it.
433
+ */
151
434
  setReduceMotion(reduce) {
152
435
  this.settings.reduceMotion = reduce;
153
436
  this.persist();
154
437
  }
438
+ /**
439
+ * Resets all settings to factory defaults and re-applies the theme.
440
+ *
441
+ * The reset is also persisted to `localStorage` so subsequent page loads
442
+ * start from defaults rather than the old stored values.
443
+ */
155
444
  reset() {
156
445
  this.settings = { ...defaults };
157
446
  this.persist();
158
447
  }
159
448
  }
449
+ // ─────────────────────────────────────────────────────────────────────────────
450
+ // Module-level singleton
451
+ // ─────────────────────────────────────────────────────────────────────────────
452
+ /**
453
+ * Module-level singleton instance.
454
+ *
455
+ * `null` until the first call to {@link getThemeEngine}. Using `null` (rather
456
+ * than eagerly constructing) ensures the engine is only created in browser
457
+ * contexts where DOM and `localStorage` are actually available.
458
+ */
160
459
  let engine = null;
460
+ /**
461
+ * Returns the module-level {@link ThemeEngine} singleton, creating it on first call.
462
+ *
463
+ * This is the **recommended** entry point for all consumers. Calling this
464
+ * function multiple times always returns the same instance.
465
+ *
466
+ * @returns The shared `ThemeEngine` instance.
467
+ *
468
+ * @example
469
+ * ```ts
470
+ * import { getThemeEngine } from '@moni-labs/moni-ui';
471
+ *
472
+ * const theme = getThemeEngine();
473
+ * theme.setMode('dark');
474
+ * ```
475
+ */
161
476
  export function getThemeEngine() {
162
477
  if (!engine)
163
478
  engine = new ThemeEngine();
164
479
  return engine;
165
480
  }
481
+ /**
482
+ * Destroys the module-level singleton, forcing the next call to
483
+ * {@link getThemeEngine} to create a fresh instance.
484
+ *
485
+ * **Intended for test isolation only.** Do not call this in application code,
486
+ * as it will cause components sharing the singleton to lose their reference.
487
+ *
488
+ * @example
489
+ * ```ts
490
+ * afterEach(() => {
491
+ * resetThemeEngine(); // Start each test with a clean engine.
492
+ * });
493
+ * ```
494
+ */
166
495
  export function resetThemeEngine() {
167
496
  engine = null;
168
497
  }
@@ -1,3 +1,31 @@
1
+ /**
2
+ * @file web-components.ts
3
+ * @package @moni-labs/moni-ui
4
+ * @license MIT
5
+ * @contributors Moni Labs & Contributors
6
+ */
7
+ /**
8
+ * @module web-components
9
+ *
10
+ * Lightweight entry point that registers and exports only the Moni UI Web
11
+ * Components, without importing any Svelte-specific utilities.
12
+ *
13
+ * **When to use this instead of the main `index.ts`:**
14
+ * - In non-Svelte projects (React, Vue, vanilla JS, HTML-only) where importing
15
+ * `theme.svelte.ts` would introduce an unnecessary Svelte 5 dependency.
16
+ * - When bundler tree-shaking is not sufficient to eliminate Svelte imports.
17
+ *
18
+ * This file has the same side-effect as the main entry: it calls
19
+ * `customElements.define()` for every `<moni-*>` element via the
20
+ * `./components/index.js` import.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // In a React or Vue project:
25
+ * import '@moni-labs/moni-ui/web-components';
26
+ * // All <moni-*> elements are now available globally in the DOM.
27
+ * ```
28
+ */
1
29
  import './components/index.js';
2
30
  export * from './components/index.js';
3
31
  //# sourceMappingURL=web-components.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"web-components.d.ts","sourceRoot":"","sources":["../src/web-components.ts"],"names":[],"mappings":"AAEA,OAAO,uBAAuB,CAAC;AAE/B,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"web-components.d.ts","sourceRoot":"","sources":["../src/web-components.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,uBAAuB,CAAC;AAE/B,cAAc,uBAAuB,CAAC"}
@@ -1,4 +1,31 @@
1
- // Lightweight entry point for Moni UI Web Components only.
2
- // Auto-registers every <moni-*> custom element without pulling in Svelte.
1
+ /**
2
+ * @file web-components.ts
3
+ * @package @moni-labs/moni-ui
4
+ * @license MIT
5
+ * @contributors Moni Labs & Contributors
6
+ */
7
+ /**
8
+ * @module web-components
9
+ *
10
+ * Lightweight entry point that registers and exports only the Moni UI Web
11
+ * Components, without importing any Svelte-specific utilities.
12
+ *
13
+ * **When to use this instead of the main `index.ts`:**
14
+ * - In non-Svelte projects (React, Vue, vanilla JS, HTML-only) where importing
15
+ * `theme.svelte.ts` would introduce an unnecessary Svelte 5 dependency.
16
+ * - When bundler tree-shaking is not sufficient to eliminate Svelte imports.
17
+ *
18
+ * This file has the same side-effect as the main entry: it calls
19
+ * `customElements.define()` for every `<moni-*>` element via the
20
+ * `./components/index.js` import.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // In a React or Vue project:
25
+ * import '@moni-labs/moni-ui/web-components';
26
+ * // All <moni-*> elements are now available globally in the DOM.
27
+ * ```
28
+ */
29
+ // Side-effect: auto-registers every <moni-*> custom element.
3
30
  import './components/index.js';
4
31
  export * from './components/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moni-labs/moni-ui",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Design system unificado para Moni — Material Design 3 Expressive, mobile-first.",
@@ -1,2 +1,9 @@
1
+ /**
2
+ * @file actions/index.ts
3
+ * @package @moni-labs/moni-ui
4
+ * @license MIT
5
+ * @contributors Moni Labs & Contributors
6
+ */
7
+
1
8
  // Legacy Svelte actions removed; this module is kept for backward compatibility.
2
9
  export {};