@ecoma-io/loom 0.1.0 → 0.2.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 (495) hide show
  1. package/README.md +54 -57
  2. package/dist/blocks/AppHeader/AppHeader.js.map +1 -1
  3. package/dist/blocks/AppHeader/AppHeader.vue.d.ts +5 -6
  4. package/dist/blocks/AppHeader/AppHeader.vue.d.ts.map +1 -1
  5. package/dist/blocks/AppHeader/AppHeader.vue_vue_type_script_setup_true_lang.js +6 -7
  6. package/dist/blocks/AppHeader/AppHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/blocks/DashboardGrid/DashboardGrid.vue.d.ts +1 -1
  8. package/dist/blocks/DashboardGrid/DashboardGrid.vue.d.ts.map +1 -1
  9. package/dist/blocks/DesktopAppShell/DesktopAppShell.js +7 -0
  10. package/dist/blocks/DesktopAppShell/DesktopAppShell.js.map +1 -0
  11. package/dist/blocks/DesktopAppShell/DesktopAppShell.vue.d.ts +102 -0
  12. package/dist/blocks/DesktopAppShell/DesktopAppShell.vue.d.ts.map +1 -0
  13. package/dist/blocks/DesktopAppShell/DesktopAppShell.vue_vue_type_script_setup_true_lang.js +74 -0
  14. package/dist/blocks/DesktopAppShell/DesktopAppShell.vue_vue_type_script_setup_true_lang.js.map +1 -0
  15. package/dist/blocks/ErrorState/ErrorState.js +7 -0
  16. package/dist/blocks/ErrorState/ErrorState.js.map +1 -0
  17. package/dist/blocks/ErrorState/ErrorState.vue.d.ts +44 -0
  18. package/dist/blocks/ErrorState/ErrorState.vue.d.ts.map +1 -0
  19. package/dist/blocks/ErrorState/ErrorState.vue_vue_type_script_setup_true_lang.js +60 -0
  20. package/dist/blocks/ErrorState/ErrorState.vue_vue_type_script_setup_true_lang.js.map +1 -0
  21. package/dist/blocks/FormActions/FormActions.js +7 -0
  22. package/dist/blocks/FormActions/FormActions.js.map +1 -0
  23. package/dist/blocks/FormActions/FormActions.vue.d.ts +51 -0
  24. package/dist/blocks/FormActions/FormActions.vue.d.ts.map +1 -0
  25. package/dist/blocks/FormActions/FormActions.vue_vue_type_script_setup_true_lang.js +21 -0
  26. package/dist/blocks/FormActions/FormActions.vue_vue_type_script_setup_true_lang.js.map +1 -0
  27. package/dist/blocks/FormSection/FormSection.js +7 -0
  28. package/dist/blocks/FormSection/FormSection.js.map +1 -0
  29. package/dist/blocks/FormSection/FormSection.vue.d.ts +85 -0
  30. package/dist/blocks/FormSection/FormSection.vue.d.ts.map +1 -0
  31. package/dist/blocks/FormSection/FormSection.vue_vue_type_script_setup_true_lang.js +62 -0
  32. package/dist/blocks/FormSection/FormSection.vue_vue_type_script_setup_true_lang.js.map +1 -0
  33. package/dist/blocks/LoadingState/LoadingState.js +7 -0
  34. package/dist/blocks/LoadingState/LoadingState.js.map +1 -0
  35. package/dist/blocks/LoadingState/LoadingState.vue.d.ts +22 -0
  36. package/dist/blocks/LoadingState/LoadingState.vue.d.ts.map +1 -0
  37. package/dist/blocks/LoadingState/LoadingState.vue_vue_type_script_setup_true_lang.js +57 -0
  38. package/dist/blocks/LoadingState/LoadingState.vue_vue_type_script_setup_true_lang.js.map +1 -0
  39. package/dist/blocks/MetricCard/MetricCard.js +7 -0
  40. package/dist/blocks/MetricCard/MetricCard.js.map +1 -0
  41. package/dist/blocks/MetricCard/MetricCard.vue.d.ts +59 -0
  42. package/dist/blocks/MetricCard/MetricCard.vue.d.ts.map +1 -0
  43. package/dist/blocks/MetricCard/MetricCard.vue_vue_type_script_setup_true_lang.js +63 -0
  44. package/dist/blocks/MetricCard/MetricCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  45. package/dist/blocks/SidebarNav/SidebarNav.js.map +1 -1
  46. package/dist/blocks/SidebarNav/SidebarNav.vue_vue_type_script_setup_true_lang.js.map +1 -1
  47. package/dist/blocks/TitleBar/TitleBar.js.map +1 -1
  48. package/dist/blocks/TitleBar/TitleBar.vue.d.ts +37 -3
  49. package/dist/blocks/TitleBar/TitleBar.vue.d.ts.map +1 -1
  50. package/dist/blocks/TitleBar/TitleBar.vue_vue_type_script_setup_true_lang.js +14 -14
  51. package/dist/blocks/TitleBar/TitleBar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  52. package/dist/blocks/ToastStack/ToastStack.js.map +1 -1
  53. package/dist/blocks/ToastStack/ToastStack.vue.d.ts +20 -0
  54. package/dist/blocks/ToastStack/ToastStack.vue.d.ts.map +1 -1
  55. package/dist/blocks/ToastStack/ToastStack.vue_vue_type_script_setup_true_lang.js +16 -5
  56. package/dist/blocks/ToastStack/ToastStack.vue_vue_type_script_setup_true_lang.js.map +1 -1
  57. package/dist/composition/Center/Center.js +7 -0
  58. package/dist/composition/Center/Center.js.map +1 -0
  59. package/dist/composition/Center/Center.vue.d.ts +40 -0
  60. package/dist/composition/Center/Center.vue.d.ts.map +1 -0
  61. package/dist/composition/Center/Center.vue_vue_type_script_setup_true_lang.js +29 -0
  62. package/dist/composition/Center/Center.vue_vue_type_script_setup_true_lang.js.map +1 -0
  63. package/dist/composition/Frame/Frame.js +7 -0
  64. package/dist/composition/Frame/Frame.js.map +1 -0
  65. package/dist/composition/Frame/Frame.vue.d.ts +35 -0
  66. package/dist/composition/Frame/Frame.vue.d.ts.map +1 -0
  67. package/dist/composition/Frame/Frame.vue_vue_type_script_setup_true_lang.js +29 -0
  68. package/dist/composition/Frame/Frame.vue_vue_type_script_setup_true_lang.js.map +1 -0
  69. package/dist/composition/Grid/Grid.js +7 -0
  70. package/dist/composition/Grid/Grid.js.map +1 -0
  71. package/dist/composition/Grid/Grid.vue.d.ts +41 -0
  72. package/dist/composition/Grid/Grid.vue.d.ts.map +1 -0
  73. package/dist/composition/Grid/Grid.vue_vue_type_script_setup_true_lang.js +27 -0
  74. package/dist/composition/Grid/Grid.vue_vue_type_script_setup_true_lang.js.map +1 -0
  75. package/dist/composition/Inline/Inline.js +7 -0
  76. package/dist/composition/Inline/Inline.js.map +1 -0
  77. package/dist/composition/Inline/Inline.vue.d.ts +46 -0
  78. package/dist/composition/Inline/Inline.vue.d.ts.map +1 -0
  79. package/dist/composition/Inline/Inline.vue_vue_type_script_setup_true_lang.js +35 -0
  80. package/dist/composition/Inline/Inline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  81. package/dist/composition/ScrollReel/ScrollReel.js +7 -0
  82. package/dist/composition/ScrollReel/ScrollReel.js.map +1 -0
  83. package/dist/composition/ScrollReel/ScrollReel.vue.d.ts +42 -0
  84. package/dist/composition/ScrollReel/ScrollReel.vue.d.ts.map +1 -0
  85. package/dist/composition/ScrollReel/ScrollReel.vue_vue_type_script_setup_true_lang.js +79 -0
  86. package/dist/composition/ScrollReel/ScrollReel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  87. package/dist/composition/Sidebar/Sidebar.js +7 -0
  88. package/dist/composition/Sidebar/Sidebar.js.map +1 -0
  89. package/dist/composition/Sidebar/Sidebar.vue.d.ts +52 -0
  90. package/dist/composition/Sidebar/Sidebar.vue.d.ts.map +1 -0
  91. package/dist/composition/Sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +36 -0
  92. package/dist/composition/Sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  93. package/dist/composition/Split/Split.js +7 -0
  94. package/dist/composition/Split/Split.js.map +1 -0
  95. package/dist/composition/Split/Split.vue.d.ts +58 -0
  96. package/dist/composition/Split/Split.vue.d.ts.map +1 -0
  97. package/dist/composition/Split/Split.vue_vue_type_script_setup_true_lang.js +40 -0
  98. package/dist/composition/Split/Split.vue_vue_type_script_setup_true_lang.js.map +1 -0
  99. package/dist/composition/Stack/Stack.js +7 -0
  100. package/dist/composition/Stack/Stack.js.map +1 -0
  101. package/dist/composition/Stack/Stack.vue.d.ts +43 -0
  102. package/dist/composition/Stack/Stack.vue.d.ts.map +1 -0
  103. package/dist/composition/Stack/Stack.vue_vue_type_script_setup_true_lang.js +30 -0
  104. package/dist/composition/Stack/Stack.vue_vue_type_script_setup_true_lang.js.map +1 -0
  105. package/dist/index.d.ts +119 -11
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +83 -5
  108. package/dist/layouts/AppShell/AppShell.js +7 -0
  109. package/dist/layouts/AppShell/AppShell.js.map +1 -0
  110. package/dist/layouts/AppShell/AppShell.vue.d.ts +51 -0
  111. package/dist/layouts/AppShell/AppShell.vue.d.ts.map +1 -0
  112. package/dist/layouts/AppShell/AppShell.vue_vue_type_script_setup_true_lang.js +47 -0
  113. package/dist/layouts/AppShell/AppShell.vue_vue_type_script_setup_true_lang.js.map +1 -0
  114. package/dist/layouts/Centered/Centered.js +7 -0
  115. package/dist/layouts/Centered/Centered.js.map +1 -0
  116. package/dist/layouts/Centered/Centered.vue.d.ts +48 -0
  117. package/dist/layouts/Centered/Centered.vue.d.ts.map +1 -0
  118. package/dist/layouts/Centered/Centered.vue_vue_type_script_setup_true_lang.js +35 -0
  119. package/dist/layouts/Centered/Centered.vue_vue_type_script_setup_true_lang.js.map +1 -0
  120. package/dist/layouts/Dashboard/Dashboard.js +7 -0
  121. package/dist/layouts/Dashboard/Dashboard.js.map +1 -0
  122. package/dist/layouts/Dashboard/Dashboard.vue.d.ts +60 -0
  123. package/dist/layouts/Dashboard/Dashboard.vue.d.ts.map +1 -0
  124. package/dist/layouts/Dashboard/Dashboard.vue_vue_type_script_setup_true_lang.js +64 -0
  125. package/dist/layouts/Dashboard/Dashboard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  126. package/dist/layouts/FormLayout/FormLayout.js +7 -0
  127. package/dist/layouts/FormLayout/FormLayout.js.map +1 -0
  128. package/dist/layouts/FormLayout/FormLayout.vue.d.ts +46 -0
  129. package/dist/layouts/FormLayout/FormLayout.vue.d.ts.map +1 -0
  130. package/dist/layouts/FormLayout/FormLayout.vue_vue_type_script_setup_true_lang.js +28 -0
  131. package/dist/layouts/FormLayout/FormLayout.vue_vue_type_script_setup_true_lang.js.map +1 -0
  132. package/dist/layouts/MasterDetail/MasterDetail.js +7 -0
  133. package/dist/layouts/MasterDetail/MasterDetail.js.map +1 -0
  134. package/dist/layouts/MasterDetail/MasterDetail.vue.d.ts +49 -0
  135. package/dist/layouts/MasterDetail/MasterDetail.vue.d.ts.map +1 -0
  136. package/dist/layouts/MasterDetail/MasterDetail.vue_vue_type_script_setup_true_lang.js +42 -0
  137. package/dist/layouts/MasterDetail/MasterDetail.vue_vue_type_script_setup_true_lang.js.map +1 -0
  138. package/dist/layouts/Reading/Reading.js +7 -0
  139. package/dist/layouts/Reading/Reading.js.map +1 -0
  140. package/dist/layouts/Reading/Reading.vue.d.ts +24 -0
  141. package/dist/layouts/Reading/Reading.vue.d.ts.map +1 -0
  142. package/dist/layouts/Reading/Reading.vue_vue_type_script_setup_true_lang.js +29 -0
  143. package/dist/layouts/Reading/Reading.vue_vue_type_script_setup_true_lang.js.map +1 -0
  144. package/dist/layouts/Settings/Settings.js +7 -0
  145. package/dist/layouts/Settings/Settings.js.map +1 -0
  146. package/dist/layouts/Settings/Settings.vue.d.ts +39 -0
  147. package/dist/layouts/Settings/Settings.vue.d.ts.map +1 -0
  148. package/dist/layouts/Settings/Settings.vue_vue_type_script_setup_true_lang.js +35 -0
  149. package/dist/layouts/Settings/Settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
  150. package/dist/layouts/SplitLayout/SplitLayout.js +7 -0
  151. package/dist/layouts/SplitLayout/SplitLayout.js.map +1 -0
  152. package/dist/layouts/SplitLayout/SplitLayout.vue.d.ts +63 -0
  153. package/dist/layouts/SplitLayout/SplitLayout.vue.d.ts.map +1 -0
  154. package/dist/layouts/SplitLayout/SplitLayout.vue_vue_type_script_setup_true_lang.js +46 -0
  155. package/dist/layouts/SplitLayout/SplitLayout.vue_vue_type_script_setup_true_lang.js.map +1 -0
  156. package/dist/lib/ancestor-disabled.d.ts +35 -0
  157. package/dist/lib/ancestor-disabled.d.ts.map +1 -0
  158. package/dist/lib/ancestor-disabled.js +86 -0
  159. package/dist/lib/ancestor-disabled.js.map +1 -0
  160. package/dist/lib/cn.d.ts.map +1 -1
  161. package/dist/lib/cn.js +46 -1
  162. package/dist/lib/cn.js.map +1 -1
  163. package/dist/lib/count-labels.d.ts +78 -0
  164. package/dist/lib/count-labels.d.ts.map +1 -0
  165. package/dist/lib/count-labels.js +29 -0
  166. package/dist/lib/count-labels.js.map +1 -0
  167. package/dist/lib/date-labels.d.ts +278 -0
  168. package/dist/lib/date-labels.d.ts.map +1 -0
  169. package/dist/lib/date-labels.js +157 -0
  170. package/dist/lib/date-labels.js.map +1 -0
  171. package/dist/lib/field-context.d.ts +178 -0
  172. package/dist/lib/field-context.d.ts.map +1 -0
  173. package/dist/lib/field-context.js +106 -0
  174. package/dist/lib/field-context.js.map +1 -0
  175. package/dist/lib/label-registry.d.ts +75 -0
  176. package/dist/lib/label-registry.d.ts.map +1 -0
  177. package/dist/lib/labels.d.ts +116 -0
  178. package/dist/lib/labels.d.ts.map +1 -0
  179. package/dist/lib/labels.js +84 -0
  180. package/dist/lib/labels.js.map +1 -0
  181. package/dist/lib/theme.d.ts +68 -0
  182. package/dist/lib/theme.d.ts.map +1 -0
  183. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/CalendarDate.js +236 -0
  184. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/CalendarDate.js.map +1 -0
  185. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/calendars/GregorianCalendar.js +117 -0
  186. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/calendars/GregorianCalendar.js.map +1 -0
  187. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/conversion.js +142 -0
  188. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/conversion.js.map +1 -0
  189. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/manipulation.js +280 -0
  190. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/manipulation.js.map +1 -0
  191. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/queries.js +40 -0
  192. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/queries.js.map +1 -0
  193. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/string.js +69 -0
  194. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/string.js.map +1 -0
  195. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/utils.js +8 -0
  196. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/utils.js.map +1 -0
  197. package/dist/primitives/Accordion/Accordion.js +7 -0
  198. package/dist/primitives/Accordion/Accordion.js.map +1 -0
  199. package/dist/primitives/Accordion/Accordion.vue.d.ts +68 -0
  200. package/dist/primitives/Accordion/Accordion.vue.d.ts.map +1 -0
  201. package/dist/primitives/Accordion/Accordion.vue_vue_type_script_setup_true_lang.js +67 -0
  202. package/dist/primitives/Accordion/Accordion.vue_vue_type_script_setup_true_lang.js.map +1 -0
  203. package/dist/primitives/AlertDialog/AlertDialog.js +7 -0
  204. package/dist/primitives/AlertDialog/AlertDialog.js.map +1 -0
  205. package/dist/primitives/AlertDialog/AlertDialog.vue.d.ts +94 -0
  206. package/dist/primitives/AlertDialog/AlertDialog.vue.d.ts.map +1 -0
  207. package/dist/primitives/AlertDialog/AlertDialog.vue_vue_type_script_setup_true_lang.js +99 -0
  208. package/dist/primitives/AlertDialog/AlertDialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  209. package/dist/primitives/Avatar/Avatar.js +2 -2
  210. package/dist/primitives/Avatar/Avatar.js.map +1 -1
  211. package/dist/primitives/Avatar/Avatar.vue.d.ts +30 -3
  212. package/dist/primitives/Avatar/Avatar.vue.d.ts.map +1 -1
  213. package/dist/primitives/Avatar/Avatar.vue_vue_type_script_setup_true_lang.js +95 -14
  214. package/dist/primitives/Avatar/Avatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  215. package/dist/primitives/AvatarGroup/AvatarGroup.js +7 -0
  216. package/dist/primitives/AvatarGroup/AvatarGroup.js.map +1 -0
  217. package/dist/primitives/AvatarGroup/AvatarGroup.vue.d.ts +104 -0
  218. package/dist/primitives/AvatarGroup/AvatarGroup.vue.d.ts.map +1 -0
  219. package/dist/primitives/AvatarGroup/AvatarGroup.vue_vue_type_script_setup_true_lang.js +139 -0
  220. package/dist/primitives/AvatarGroup/AvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
  221. package/dist/primitives/Badge/Badge.js.map +1 -1
  222. package/dist/primitives/Badge/Badge.vue.d.ts +6 -6
  223. package/dist/primitives/Badge/Badge.vue.d.ts.map +1 -1
  224. package/dist/primitives/Badge/Badge.vue_vue_type_script_setup_true_lang.js +1 -1
  225. package/dist/primitives/Badge/Badge.vue_vue_type_script_setup_true_lang.js.map +1 -1
  226. package/dist/primitives/Breadcrumb/Breadcrumb.js +7 -0
  227. package/dist/primitives/Breadcrumb/Breadcrumb.js.map +1 -0
  228. package/dist/primitives/Breadcrumb/Breadcrumb.vue.d.ts +25 -0
  229. package/dist/primitives/Breadcrumb/Breadcrumb.vue.d.ts.map +1 -0
  230. package/dist/primitives/Breadcrumb/Breadcrumb.vue_vue_type_script_setup_true_lang.js +48 -0
  231. package/dist/primitives/Breadcrumb/Breadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -0
  232. package/dist/primitives/Button/Button.js +2 -2
  233. package/dist/primitives/Button/Button.js.map +1 -1
  234. package/dist/primitives/Button/Button.vue.d.ts +31 -8
  235. package/dist/primitives/Button/Button.vue.d.ts.map +1 -1
  236. package/dist/primitives/Button/Button.vue_vue_type_script_setup_true_lang.js +32 -16
  237. package/dist/primitives/Button/Button.vue_vue_type_script_setup_true_lang.js.map +1 -1
  238. package/dist/primitives/Checkbox/Checkbox.js.map +1 -1
  239. package/dist/primitives/Checkbox/Checkbox.vue.d.ts +18 -3
  240. package/dist/primitives/Checkbox/Checkbox.vue.d.ts.map +1 -1
  241. package/dist/primitives/Checkbox/Checkbox.vue_vue_type_script_setup_true_lang.js +46 -7
  242. package/dist/primitives/Checkbox/Checkbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  243. package/dist/primitives/Chip/Chip.js +7 -0
  244. package/dist/primitives/Chip/Chip.js.map +1 -0
  245. package/dist/primitives/Chip/Chip.vue.d.ts +79 -0
  246. package/dist/primitives/Chip/Chip.vue.d.ts.map +1 -0
  247. package/dist/primitives/Chip/Chip.vue_vue_type_script_setup_true_lang.js +139 -0
  248. package/dist/primitives/Chip/Chip.vue_vue_type_script_setup_true_lang.js.map +1 -0
  249. package/dist/primitives/ColorPicker/ColorPicker.js +7 -0
  250. package/dist/primitives/ColorPicker/ColorPicker.js.map +1 -0
  251. package/dist/primitives/ColorPicker/ColorPicker.vue.d.ts +125 -0
  252. package/dist/primitives/ColorPicker/ColorPicker.vue.d.ts.map +1 -0
  253. package/dist/primitives/ColorPicker/ColorPicker.vue_vue_type_script_setup_true_lang.js +301 -0
  254. package/dist/primitives/ColorPicker/ColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  255. package/dist/primitives/Combobox/Combobox.js +7 -0
  256. package/dist/primitives/Combobox/Combobox.js.map +1 -0
  257. package/dist/primitives/Combobox/Combobox.vue.d.ts +205 -0
  258. package/dist/primitives/Combobox/Combobox.vue.d.ts.map +1 -0
  259. package/dist/primitives/Combobox/Combobox.vue_vue_type_script_setup_true_lang.js +345 -0
  260. package/dist/primitives/Combobox/Combobox.vue_vue_type_script_setup_true_lang.js.map +1 -0
  261. package/dist/primitives/ContextMenu/ContextMenu.js +7 -0
  262. package/dist/primitives/ContextMenu/ContextMenu.js.map +1 -0
  263. package/dist/primitives/ContextMenu/ContextMenu.vue.d.ts +55 -0
  264. package/dist/primitives/ContextMenu/ContextMenu.vue.d.ts.map +1 -0
  265. package/dist/primitives/ContextMenu/ContextMenu.vue_vue_type_script_setup_true_lang.js +82 -0
  266. package/dist/primitives/ContextMenu/ContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -0
  267. package/dist/primitives/DatePicker/DatePicker.js +7 -0
  268. package/dist/primitives/DatePicker/DatePicker.js.map +1 -0
  269. package/dist/primitives/DatePicker/DatePicker.vue.d.ts +102 -0
  270. package/dist/primitives/DatePicker/DatePicker.vue.d.ts.map +1 -0
  271. package/dist/primitives/DatePicker/DatePicker.vue_vue_type_script_setup_true_lang.js +292 -0
  272. package/dist/primitives/DatePicker/DatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  273. package/dist/primitives/DateRangePicker/DateRangePicker.js +7 -0
  274. package/dist/primitives/DateRangePicker/DateRangePicker.js.map +1 -0
  275. package/dist/primitives/DateRangePicker/DateRangePicker.vue.d.ts +173 -0
  276. package/dist/primitives/DateRangePicker/DateRangePicker.vue.d.ts.map +1 -0
  277. package/dist/primitives/DateRangePicker/DateRangePicker.vue_vue_type_script_setup_true_lang.js +412 -0
  278. package/dist/primitives/DateRangePicker/DateRangePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  279. package/dist/primitives/DateTimePicker/DateTimePicker.js +7 -0
  280. package/dist/primitives/DateTimePicker/DateTimePicker.js.map +1 -0
  281. package/dist/primitives/DateTimePicker/DateTimePicker.vue.d.ts +113 -0
  282. package/dist/primitives/DateTimePicker/DateTimePicker.vue.d.ts.map +1 -0
  283. package/dist/primitives/DateTimePicker/DateTimePicker.vue_vue_type_script_setup_true_lang.js +358 -0
  284. package/dist/primitives/DateTimePicker/DateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  285. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.js +7 -0
  286. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.js.map +1 -0
  287. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.vue.d.ts +181 -0
  288. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.vue.d.ts.map +1 -0
  289. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.vue_vue_type_script_setup_true_lang.js +562 -0
  290. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  291. package/dist/primitives/Dialog/Dialog.js +2 -2
  292. package/dist/primitives/Dialog/Dialog.js.map +1 -1
  293. package/dist/primitives/Dialog/Dialog.vue.d.ts +39 -0
  294. package/dist/primitives/Dialog/Dialog.vue.d.ts.map +1 -1
  295. package/dist/primitives/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js +14 -5
  296. package/dist/primitives/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  297. package/dist/primitives/Drawer/Drawer.js +7 -0
  298. package/dist/primitives/Drawer/Drawer.js.map +1 -0
  299. package/dist/primitives/Drawer/Drawer.vue.d.ts +110 -0
  300. package/dist/primitives/Drawer/Drawer.vue.d.ts.map +1 -0
  301. package/dist/primitives/Drawer/Drawer.vue_vue_type_script_setup_true_lang.js +223 -0
  302. package/dist/primitives/Drawer/Drawer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  303. package/dist/primitives/DropdownMenu/DropdownMenu.js.map +1 -1
  304. package/dist/primitives/DropdownMenu/DropdownMenu.vue.d.ts.map +1 -1
  305. package/dist/primitives/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js +2 -2
  306. package/dist/primitives/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  307. package/dist/primitives/Editable/Editable.js +7 -0
  308. package/dist/primitives/Editable/Editable.js.map +1 -0
  309. package/dist/primitives/Editable/Editable.vue.d.ts +200 -0
  310. package/dist/primitives/Editable/Editable.vue.d.ts.map +1 -0
  311. package/dist/primitives/Editable/Editable.vue_vue_type_script_setup_true_lang.js +275 -0
  312. package/dist/primitives/Editable/Editable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  313. package/dist/primitives/Field/Field.js.map +1 -1
  314. package/dist/primitives/Field/Field.vue.d.ts +32 -17
  315. package/dist/primitives/Field/Field.vue.d.ts.map +1 -1
  316. package/dist/primitives/Field/Field.vue_vue_type_script_setup_true_lang.js +51 -18
  317. package/dist/primitives/Field/Field.vue_vue_type_script_setup_true_lang.js.map +1 -1
  318. package/dist/primitives/Fieldset/Fieldset.js +7 -0
  319. package/dist/primitives/Fieldset/Fieldset.js.map +1 -0
  320. package/dist/primitives/Fieldset/Fieldset.vue.d.ts +91 -0
  321. package/dist/primitives/Fieldset/Fieldset.vue.d.ts.map +1 -0
  322. package/dist/primitives/Fieldset/Fieldset.vue_vue_type_script_setup_true_lang.js +138 -0
  323. package/dist/primitives/Fieldset/Fieldset.vue_vue_type_script_setup_true_lang.js.map +1 -0
  324. package/dist/primitives/FileUpload/FileUpload.js +7 -0
  325. package/dist/primitives/FileUpload/FileUpload.js.map +1 -0
  326. package/dist/primitives/FileUpload/FileUpload.vue.d.ts +132 -0
  327. package/dist/primitives/FileUpload/FileUpload.vue.d.ts.map +1 -0
  328. package/dist/primitives/FileUpload/FileUpload.vue_vue_type_script_setup_true_lang.js +359 -0
  329. package/dist/primitives/FileUpload/FileUpload.vue_vue_type_script_setup_true_lang.js.map +1 -0
  330. package/dist/primitives/HoverCard/HoverCard.js +7 -0
  331. package/dist/primitives/HoverCard/HoverCard.js.map +1 -0
  332. package/dist/primitives/HoverCard/HoverCard.vue.d.ts +68 -0
  333. package/dist/primitives/HoverCard/HoverCard.vue.d.ts.map +1 -0
  334. package/dist/primitives/HoverCard/HoverCard.vue_vue_type_script_setup_true_lang.js +62 -0
  335. package/dist/primitives/HoverCard/HoverCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  336. package/dist/primitives/IconButton/IconButton.js +7 -0
  337. package/dist/primitives/IconButton/IconButton.js.map +1 -0
  338. package/dist/primitives/IconButton/IconButton.vue.d.ts +45 -0
  339. package/dist/primitives/IconButton/IconButton.vue.d.ts.map +1 -0
  340. package/dist/primitives/IconButton/IconButton.vue_vue_type_script_setup_true_lang.js +58 -0
  341. package/dist/primitives/IconButton/IconButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
  342. package/dist/primitives/Indicator/Indicator.js +7 -0
  343. package/dist/primitives/Indicator/Indicator.js.map +1 -0
  344. package/dist/primitives/Indicator/Indicator.vue.d.ts +144 -0
  345. package/dist/primitives/Indicator/Indicator.vue.d.ts.map +1 -0
  346. package/dist/primitives/Indicator/Indicator.vue_vue_type_script_setup_true_lang.js +198 -0
  347. package/dist/primitives/Indicator/Indicator.vue_vue_type_script_setup_true_lang.js.map +1 -0
  348. package/dist/primitives/Link/Link.js +7 -0
  349. package/dist/primitives/Link/Link.js.map +1 -0
  350. package/dist/primitives/Link/Link.vue.d.ts +46 -0
  351. package/dist/primitives/Link/Link.vue.d.ts.map +1 -0
  352. package/dist/primitives/Link/Link.vue_vue_type_script_setup_true_lang.js +85 -0
  353. package/dist/primitives/Link/Link.vue_vue_type_script_setup_true_lang.js.map +1 -0
  354. package/dist/primitives/Menubar/Menubar.js.map +1 -1
  355. package/dist/primitives/Menubar/Menubar.vue.d.ts.map +1 -1
  356. package/dist/primitives/Menubar/Menubar.vue_vue_type_script_setup_true_lang.js +1 -1
  357. package/dist/primitives/Menubar/Menubar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  358. package/dist/primitives/NumberField/NumberField.js +2 -2
  359. package/dist/primitives/NumberField/NumberField.js.map +1 -1
  360. package/dist/primitives/NumberField/NumberField.vue.d.ts +86 -25
  361. package/dist/primitives/NumberField/NumberField.vue.d.ts.map +1 -1
  362. package/dist/primitives/NumberField/NumberField.vue_vue_type_script_setup_true_lang.js +83 -39
  363. package/dist/primitives/NumberField/NumberField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  364. package/dist/primitives/OtpInput/OtpInput.js +7 -0
  365. package/dist/primitives/OtpInput/OtpInput.js.map +1 -0
  366. package/dist/primitives/OtpInput/OtpInput.vue.d.ts +110 -0
  367. package/dist/primitives/OtpInput/OtpInput.vue.d.ts.map +1 -0
  368. package/dist/primitives/OtpInput/OtpInput.vue_vue_type_script_setup_true_lang.js +130 -0
  369. package/dist/primitives/OtpInput/OtpInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
  370. package/dist/primitives/Pagination/Pagination.js +7 -0
  371. package/dist/primitives/Pagination/Pagination.js.map +1 -0
  372. package/dist/primitives/Pagination/Pagination.vue.d.ts +143 -0
  373. package/dist/primitives/Pagination/Pagination.vue.d.ts.map +1 -0
  374. package/dist/primitives/Pagination/Pagination.vue_vue_type_script_setup_true_lang.js +231 -0
  375. package/dist/primitives/Pagination/Pagination.vue_vue_type_script_setup_true_lang.js.map +1 -0
  376. package/dist/primitives/Progress/Progress.js +2 -2
  377. package/dist/primitives/Progress/Progress.js.map +1 -1
  378. package/dist/primitives/Progress/Progress.vue.d.ts +81 -15
  379. package/dist/primitives/Progress/Progress.vue.d.ts.map +1 -1
  380. package/dist/primitives/Progress/Progress.vue_vue_type_script_setup_true_lang.js +88 -22
  381. package/dist/primitives/Progress/Progress.vue_vue_type_script_setup_true_lang.js.map +1 -1
  382. package/dist/primitives/RadialProgress/RadialProgress.js +7 -0
  383. package/dist/primitives/RadialProgress/RadialProgress.js.map +1 -0
  384. package/dist/primitives/RadialProgress/RadialProgress.vue.d.ts +96 -0
  385. package/dist/primitives/RadialProgress/RadialProgress.vue.d.ts.map +1 -0
  386. package/dist/primitives/RadialProgress/RadialProgress.vue_vue_type_script_setup_true_lang.js +189 -0
  387. package/dist/primitives/RadialProgress/RadialProgress.vue_vue_type_script_setup_true_lang.js.map +1 -0
  388. package/dist/primitives/RadioGroup/RadioGroup.js.map +1 -1
  389. package/dist/primitives/RadioGroup/RadioGroup.vue.d.ts +7 -7
  390. package/dist/primitives/RadioGroup/RadioGroup.vue.d.ts.map +1 -1
  391. package/dist/primitives/RadioGroup/RadioGroup.vue_vue_type_script_setup_true_lang.js +26 -9
  392. package/dist/primitives/RadioGroup/RadioGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  393. package/dist/primitives/Rating/Rating.js +7 -0
  394. package/dist/primitives/Rating/Rating.js.map +1 -0
  395. package/dist/primitives/Rating/Rating.vue.d.ts +113 -0
  396. package/dist/primitives/Rating/Rating.vue.d.ts.map +1 -0
  397. package/dist/primitives/Rating/Rating.vue_vue_type_script_setup_true_lang.js +282 -0
  398. package/dist/primitives/Rating/Rating.vue_vue_type_script_setup_true_lang.js.map +1 -0
  399. package/dist/primitives/ScrollArea/ScrollArea.js +7 -0
  400. package/dist/primitives/ScrollArea/ScrollArea.js.map +1 -0
  401. package/dist/primitives/ScrollArea/ScrollArea.vue.d.ts +25 -0
  402. package/dist/primitives/ScrollArea/ScrollArea.vue.d.ts.map +1 -0
  403. package/dist/primitives/ScrollArea/ScrollArea.vue_vue_type_script_setup_true_lang.js +45 -0
  404. package/dist/primitives/ScrollArea/ScrollArea.vue_vue_type_script_setup_true_lang.js.map +1 -0
  405. package/dist/primitives/SegmentedControl/SegmentedControl.js.map +1 -1
  406. package/dist/primitives/SegmentedControl/SegmentedControl.vue.d.ts +5 -5
  407. package/dist/primitives/SegmentedControl/SegmentedControl.vue.d.ts.map +1 -1
  408. package/dist/primitives/SegmentedControl/SegmentedControl.vue_vue_type_script_setup_true_lang.js +51 -8
  409. package/dist/primitives/SegmentedControl/SegmentedControl.vue_vue_type_script_setup_true_lang.js.map +1 -1
  410. package/dist/primitives/Select/Select.js.map +1 -1
  411. package/dist/primitives/Select/Select.vue.d.ts +10 -10
  412. package/dist/primitives/Select/Select.vue.d.ts.map +1 -1
  413. package/dist/primitives/Select/Select.vue_vue_type_script_setup_true_lang.js +105 -52
  414. package/dist/primitives/Select/Select.vue_vue_type_script_setup_true_lang.js.map +1 -1
  415. package/dist/primitives/Skeleton/Skeleton.vue.d.ts +1 -1
  416. package/dist/primitives/Slider/Slider.js.map +1 -1
  417. package/dist/primitives/Slider/Slider.vue.d.ts +24 -4
  418. package/dist/primitives/Slider/Slider.vue.d.ts.map +1 -1
  419. package/dist/primitives/Slider/Slider.vue_vue_type_script_setup_true_lang.js +79 -9
  420. package/dist/primitives/Slider/Slider.vue_vue_type_script_setup_true_lang.js.map +1 -1
  421. package/dist/primitives/SpeedDial/SpeedDial.js +7 -0
  422. package/dist/primitives/SpeedDial/SpeedDial.js.map +1 -0
  423. package/dist/primitives/SpeedDial/SpeedDial.vue.d.ts +58 -0
  424. package/dist/primitives/SpeedDial/SpeedDial.vue.d.ts.map +1 -0
  425. package/dist/primitives/SpeedDial/SpeedDial.vue_vue_type_script_setup_true_lang.js +175 -0
  426. package/dist/primitives/SpeedDial/SpeedDial.vue_vue_type_script_setup_true_lang.js.map +1 -0
  427. package/dist/primitives/Stepper/Stepper.js +7 -0
  428. package/dist/primitives/Stepper/Stepper.js.map +1 -0
  429. package/dist/primitives/Stepper/Stepper.vue.d.ts +119 -0
  430. package/dist/primitives/Stepper/Stepper.vue.d.ts.map +1 -0
  431. package/dist/primitives/Stepper/Stepper.vue_vue_type_script_setup_true_lang.js +202 -0
  432. package/dist/primitives/Stepper/Stepper.vue_vue_type_script_setup_true_lang.js.map +1 -0
  433. package/dist/primitives/Switch/Switch.js.map +1 -1
  434. package/dist/primitives/Switch/Switch.vue.d.ts +13 -3
  435. package/dist/primitives/Switch/Switch.vue.d.ts.map +1 -1
  436. package/dist/primitives/Switch/Switch.vue_vue_type_script_setup_true_lang.js +34 -5
  437. package/dist/primitives/Switch/Switch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  438. package/dist/primitives/Tabs/Tabs.js.map +1 -1
  439. package/dist/primitives/Tabs/Tabs.vue.d.ts.map +1 -1
  440. package/dist/primitives/Tabs/Tabs.vue_vue_type_script_setup_true_lang.js +1 -1
  441. package/dist/primitives/Tabs/Tabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  442. package/dist/primitives/TagsInput/TagsInput.js +7 -0
  443. package/dist/primitives/TagsInput/TagsInput.js.map +1 -0
  444. package/dist/primitives/TagsInput/TagsInput.vue.d.ts +156 -0
  445. package/dist/primitives/TagsInput/TagsInput.vue.d.ts.map +1 -0
  446. package/dist/primitives/TagsInput/TagsInput.vue_vue_type_script_setup_true_lang.js +387 -0
  447. package/dist/primitives/TagsInput/TagsInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
  448. package/dist/primitives/TextField/TextField.js +2 -2
  449. package/dist/primitives/TextField/TextField.js.map +1 -1
  450. package/dist/primitives/TextField/TextField.vue.d.ts +119 -10
  451. package/dist/primitives/TextField/TextField.vue.d.ts.map +1 -1
  452. package/dist/primitives/TextField/TextField.vue_vue_type_script_setup_true_lang.js +270 -21
  453. package/dist/primitives/TextField/TextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  454. package/dist/primitives/Textarea/Textarea.js +2 -2
  455. package/dist/primitives/Textarea/Textarea.js.map +1 -1
  456. package/dist/primitives/Textarea/Textarea.vue.d.ts +114 -14
  457. package/dist/primitives/Textarea/Textarea.vue.d.ts.map +1 -1
  458. package/dist/primitives/Textarea/Textarea.vue_vue_type_script_setup_true_lang.js +216 -20
  459. package/dist/primitives/Textarea/Textarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  460. package/dist/primitives/TimePicker/TimePicker.js +7 -0
  461. package/dist/primitives/TimePicker/TimePicker.js.map +1 -0
  462. package/dist/primitives/TimePicker/TimePicker.vue.d.ts +111 -0
  463. package/dist/primitives/TimePicker/TimePicker.vue.d.ts.map +1 -0
  464. package/dist/primitives/TimePicker/TimePicker.vue_vue_type_script_setup_true_lang.js +185 -0
  465. package/dist/primitives/TimePicker/TimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  466. package/dist/primitives/Toast/Toast.js +2 -1
  467. package/dist/primitives/Toast/Toast.js.map +1 -1
  468. package/dist/primitives/Toast/Toast.vue.d.ts +29 -3
  469. package/dist/primitives/Toast/Toast.vue.d.ts.map +1 -1
  470. package/dist/primitives/Toast/Toast.vue_vue_type_script_setup_true_lang.js +17 -7
  471. package/dist/primitives/Toast/Toast.vue_vue_type_script_setup_true_lang.js.map +1 -1
  472. package/dist/primitives/Toast/ToastItem.js +2 -2
  473. package/dist/primitives/Toast/ToastItem.js.map +1 -1
  474. package/dist/primitives/Toast/ToastItem.vue.d.ts +69 -12
  475. package/dist/primitives/Toast/ToastItem.vue.d.ts.map +1 -1
  476. package/dist/primitives/Toast/ToastItem.vue_vue_type_script_setup_true_lang.js +23 -23
  477. package/dist/primitives/Toast/ToastItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  478. package/dist/primitives/Tooltip/Tooltip.vue.d.ts +1 -1
  479. package/dist/primitives/Tooltip/Tooltip.vue.d.ts.map +1 -1
  480. package/dist/primitives/WindowControls/WindowControls.js +2 -2
  481. package/dist/primitives/WindowControls/WindowControls.js.map +1 -1
  482. package/dist/primitives/WindowControls/WindowControls.vue.d.ts +66 -10
  483. package/dist/primitives/WindowControls/WindowControls.vue.d.ts.map +1 -1
  484. package/dist/primitives/WindowControls/WindowControls.vue_vue_type_script_setup_true_lang.js +23 -13
  485. package/dist/primitives/WindowControls/WindowControls.vue_vue_type_script_setup_true_lang.js.map +1 -1
  486. package/dist/styles/global.css +116 -17
  487. package/dist/styles/theme.contrast.test.ts +460 -0
  488. package/dist/styles/theme.css +239 -41
  489. package/dist/theme.js +171 -0
  490. package/dist/theme.js.map +1 -0
  491. package/package.json +14 -4
  492. package/dist/icons/BrandMark.d.ts +0 -18
  493. package/dist/icons/BrandMark.d.ts.map +0 -1
  494. package/dist/icons/BrandMark.js +0 -47
  495. package/dist/icons/BrandMark.js.map +0 -1
@@ -5,26 +5,21 @@
5
5
  * can theme lives here and nowhere else: no colour, duration, easing, radius
6
6
  * or shadow is written literally in a component.
7
7
  *
8
- * Positioning it encodes. Ecoma is a platform where an organization digitizes
9
- * its own operations and AI agents are a first-class workforce, so the form
10
- * language is dual-force:
8
+ * Positioning it encodes. Loom is a UI system for cross-platform web
9
+ * applications browser, PWA, Electron, Tauri so the form language is
10
+ * purposeful and opinionated:
11
11
  *
12
- * - Human (warp) — the threads strung and held under tension: what people
13
- * author and decide. Doubles as the default action colour, because a
14
- * person drives the interface.
15
- * - Agent (weft) — the thread carried across them: work an agent is running
16
- * or has produced.
17
- * - The seam a warp→weft gradient — appears ONLY where the two forces
18
- * meet: handoffs, co-authored assets, brand moments. Never under body
19
- * text, never on anything smaller than 20px, never in an interaction
20
- * state.
12
+ * - Primary (`--color-primary`) — the default action colour: what a person
13
+ * drives the interface with. The focus ring is the same hue for the same
14
+ * reason keyboard focus is the primary action.
15
+ * - Accent (`--color-accent`) — a second semantic colour for contrast or
16
+ * emphasis distinct from the primary action. Useful for signalling a
17
+ * different category, mode, or origin.
21
18
  *
22
- * Two threads, one cloth: the forces are one piece of work, not two systems.
23
- *
24
- * Light-first. This is a daytime operations tool, so the paper-light theme is
25
- * the single default and there is no runtime light/dark switch. A symmetric
26
- * dark theme is a reserved seam that returns with the first surface that
27
- * needs it.
19
+ * Dual-theme. The light tokens are the default; the dark block below
20
+ * overrides every semantic token under `:root[data-theme="dark"]`. Switching
21
+ * replaces the entire set, so the two cannot drift apart. The `useTheme`
22
+ * composable and `themeScript` flash-prevention snippet manage the attribute.
28
23
  *
29
24
  * `static` rather than plain `@theme`: Tailwind emits only the variables its
30
25
  * generated utilities reference, and several tokens here are read by an
@@ -33,7 +28,7 @@
33
28
  * `var(--duration-fast)` resolve inside a component's style attribute.
34
29
  */
35
30
  @theme static {
36
- /* ---- Neutrals: technical paper, cooled slightly toward the warp ------- */
31
+ /* ---- Neutrals: technical paper, cooled slightly toward the primary hue --- */
37
32
  --color-background: hsl(213 25% 96%);
38
33
  --color-foreground: hsl(213 29% 15%);
39
34
 
@@ -51,6 +46,17 @@
51
46
  --color-muted: hsl(213 18% 91%);
52
47
  --color-muted-foreground: hsl(213 14% 41%);
53
48
 
49
+ /* The lighter step of the same ladder, and it is reserved for a *graphical
50
+ * object*, never for text: a glyph that must keep clearing the 3:1 floor
51
+ * while receding behind `muted-foreground` — the disabled Rating's unfilled
52
+ * stars, which carry the maximum. Text is held to 4.5:1, which is what
53
+ * `muted-foreground` is measured to; the 3:1 floor of WCAG 1.4.11 leaves
54
+ * room for one more step, and taking it as a token rather than as an alpha
55
+ * over the darker grey is the whole point: composited at half alpha,
56
+ * `muted-foreground` lands at 2.05:1 on the page ground, short of even
57
+ * that floor. */
58
+ --color-muted-foreground-soft: hsl(213 12% 50%);
59
+
54
60
  /* Two border weights: the default hairline recedes; strong is for the few
55
61
  * blocks that must assert their edge — an active panel, a keyboard target
56
62
  * zone. */
@@ -63,23 +69,25 @@
63
69
  --color-subtle: hsl(213 20% 94%);
64
70
  --color-subtle-foreground: hsl(213 29% 18%);
65
71
 
66
- /* ---- Force 1 · Humanwarp: default action, structure, decisions ----- */
72
+ /* ---- Force 1 · Primary — default action, structure, decisions --------- */
67
73
  --color-primary: hsl(211 37% 32%);
68
74
  --color-primary-foreground: hsl(0 0% 100%);
69
- --color-primary-muted: hsl(211 35% 92%); /* warp wash: selected/active fills */
75
+ --color-primary-muted: hsl(211 35% 92%); /* wash: selected/active fills */
70
76
 
71
- /* ---- Force 2 · Agentweft: automated work running or produced ------- */
72
- --color-agent: hsl(18 56% 39%);
73
- --color-agent-foreground: hsl(0 0% 100%);
74
- --color-agent-muted: hsl(18 50% 93%); /* weft wash: agent-driven surfaces */
77
+ /* ---- Force 2 · Accenta second semantic colour for contrast or
78
+ * emphasis distinct from the primary action. Useful for signalling a
79
+ * different category, mode, or origin. ------------------------------- */
80
+ --color-accent: hsl(18 56% 39%);
81
+ --color-accent-foreground: hsl(0 0% 100%);
82
+ --color-accent-muted: hsl(18 50% 93%); /* wash: accent-driven surfaces */
75
83
 
76
84
  --color-secondary: hsl(213 18% 91%);
77
85
  --color-secondary-foreground: hsl(213 29% 18%);
78
86
 
79
- /* Focus ring is the Human warp: keyboard focus is a person acting. */
87
+ /* Focus ring is the primary colour: keyboard focus is the primary action. */
80
88
  --color-ring: hsl(211 37% 32%);
81
89
 
82
- /* ---- Functional — hues kept distinct from both forces ----------------- */
90
+ /* ---- Functional — hues kept distinct from both action colours ------------ */
83
91
  --color-destructive: hsl(356 65% 41%);
84
92
  --color-destructive-foreground: hsl(0 0% 100%);
85
93
  --color-success: hsl(152 45% 30%);
@@ -89,10 +97,50 @@
89
97
  --color-info: hsl(202 65% 35%);
90
98
  --color-info-foreground: hsl(0 0% 100%);
91
99
 
92
- /* ---- The seam: the two forces meeting. Interpolated in OKLCH so the
93
- * midpoint never turns muddy. Reach for it through the `bg-seam` utility
94
- * below, at handoff points and brand moments only. ---------------------- */
95
- --seam: linear-gradient(90deg in oklch, hsl(211 37% 32%), hsl(18 56% 39%));
100
+ /* Each functional hue's wash, completing the pattern the action colours above
101
+ * already set. These are opaque rather than an alpha of the base hue, and
102
+ * that is the whole reason they exist: a `bg-destructive/12` fill composites
103
+ * against whatever is behind it, so the same badge renders as one colour on
104
+ * `bg-card` and another on `bg-sunken`. A status tint that shifts with its
105
+ * container is a status tint a reader cannot learn. Each is mixed to hold at
106
+ * least 4.5:1 against its own base hue, which is what sits on top of it as
107
+ * text or as a hairline. */
108
+ --color-destructive-muted: hsl(356 55% 94%); /* error wash: a failed or blocking surface */
109
+ --color-success-muted: hsl(152 40% 93%); /* success wash: a settled, completed surface */
110
+ --color-warning-muted: hsl(38 70% 92%); /* warning wash: a surface needing attention */
111
+ --color-info-muted: hsl(202 55% 93%); /* info wash: a neutral advisory surface */
112
+
113
+ /* ---- Scrim weight, as modifiers on `foreground`: `bg-foreground/scrim`.
114
+ * Two weights, because how much of the page a surface hides is a statement
115
+ * about what that surface is. A dialog interrupts, so the page behind it
116
+ * drops to context. A drawer is worked alongside its page — you tune a
117
+ * filter and watch the rows change — so the page stays legible and stays
118
+ * the subject. That rule lived in a comment inside `Drawer.vue`, which is
119
+ * the one place a person building a third overlay would never look. ------ */
120
+ --opacity-scrim: 70%; /* a surface that interrupts: the page behind is context */
121
+ --opacity-scrim-light: 40%; /* a surface worked alongside: the page behind is still the subject */
122
+
123
+ /* One weight for "unavailable", because two menu rows ten points apart is
124
+ * not a decision anyone made — `opacity-40` had appeared twice against
125
+ * `opacity-50` forty-five times, and nothing in any check can see a
126
+ * difference that small. */
127
+ --opacity-disabled: 50%;
128
+
129
+ /* ---- Stacking. Five rungs, named, because the ladder was real before it
130
+ * was written down: seventeen overlays at `z-50` and two toasts at
131
+ * `z-[100]`, an arbitrary value of exactly the kind this file exists to
132
+ * prevent. Ordering *within* a rung is the portal's job — Reka appends in
133
+ * open order, so the last dialog opened is the one on top without anyone
134
+ * numbering them. --------------------------------------------------------- */
135
+ --z-index-raised: 10; /* lifted above its own siblings: an Indicator's marker, a SegmentedControl thumb */
136
+ --z-index-sticky: 20; /* page furniture that pins while content scrolls under it */
137
+ --z-index-chrome: 30; /* application chrome: the header and rails that outlive the page */
138
+ --z-index-overlay: 50; /* anything portalled over the page — dialogs, popovers, menus, drawers */
139
+ --z-index-toast: 100; /* above every overlay, because a toast reports on the thing the overlay is doing */
140
+
141
+ /* The press. One value, reached through `active:scale-press`, replacing six
142
+ * `scale-[0.97]` and three `scale-95` that meant the same thing. */
143
+ --scale-press: 0.97;
96
144
 
97
145
  /* ---- Shape: small, even fillets — milled, never blobby.
98
146
  * Nesting law: inner radius = outer radius − padding, floor 2px. Pick the
@@ -125,7 +173,7 @@
125
173
  --shadow-md: 0 4px 12px -2px hsl(213 30% 12% / 0.1), 0 2px 6px -2px hsl(213 30% 12% / 0.07);
126
174
  --shadow-lg: 0 12px 32px -6px hsl(213 30% 12% / 0.14), 0 4px 10px -4px hsl(213 30% 12% / 0.08);
127
175
 
128
- /* Focus halo — a warp haze AROUND the crisp ring outline, added on top of
176
+ /* Focus halo — a primary haze AROUND the crisp ring outline, added on top of
129
177
  * it and never replacing it, so the outline still shows under
130
178
  * forced-colors. */
131
179
  --shadow-halo: 0 0 0 4px hsl(211 37% 32% / 0.15);
@@ -173,19 +221,65 @@
173
221
  --breakpoint-4xl: 2560px; /* QHD */
174
222
  --breakpoint-5xl: 3440px; /* 21:9 ultra-wide */
175
223
 
224
+ /* ---- Safe areas. Mobile webviews (notch, home indicator) and PWA title-bar
225
+ * overlays both reserve space the layout must not paint into. The fallback is
226
+ * 0 so these tokens are always safe to read — a viewport without a safe area
227
+ * simply contributes no inset. A host that needs the raw value for
228
+ * `padding-top: env(safe-area-inset-top)` can use it directly, but a host
229
+ * that wants Loom's opinion uses the token instead and lets the theme layer
230
+ * decide what the inset is. ---------------------------------------------- */
231
+ --safe-area-top: env(safe-area-inset-top, 0px);
232
+ --safe-area-bottom: env(safe-area-inset-bottom, 0px);
233
+ --safe-area-left: env(safe-area-inset-left, 0px);
234
+ --safe-area-right: env(safe-area-inset-right, 0px);
235
+
176
236
  /* ---- The animation vocabulary. Keyframes live in global.css; these are
177
237
  * the named utilities that play them. ---------------------------------- */
178
238
  --animate-fade: fade var(--duration-normal) var(--ease-out) both;
179
239
  --animate-fade-rise: fade-rise var(--duration-normal) var(--ease-out) both;
180
240
  --animate-scale-in: scale-in var(--duration-fast) var(--ease-spring) both;
181
241
  --animate-shimmer: shimmer 1.6s linear infinite;
182
- /* Agent at work — the weft's shuttle beat. */
183
- --animate-conduct: conduct 1.8s var(--ease-in-out) infinite;
184
- /* A live seam: the warp↔weft boundary drifts while the collaboration runs,
185
- * and goes static once the work settles. */
186
- --animate-seam-flow: seam-flow 3.2s linear infinite;
187
242
  --animate-progress-indeterminate: progress-indeterminate 1.3s var(--ease-in-out) infinite;
188
243
  --animate-toast-in: toast-in var(--duration-normal) var(--ease-spring) both;
244
+
245
+ /* ---- Motion that leaves. Every animation above is an entrance, so until
246
+ * these existed an overlay that faded in over 200ms was simply gone between
247
+ * two frames, and the page behind it appeared to jump rather than to be
248
+ * revealed. `--ease-in` was declared with the rest of the easings and used by
249
+ * nothing at all, which is the tell: the accelerate curve has one job and it
250
+ * is this one.
251
+ *
252
+ * Exits run shorter than the entrance they mirror and on `--ease-in`, because
253
+ * the two directions are not the same event. A surface arriving is
254
+ * decelerating into place and is worth watching; a surface leaving has
255
+ * already done its job and should clear the eye rather than hold it.
256
+ *
257
+ * These are load-bearing beyond taste. Reka's `Presence` keeps closed content
258
+ * mounted until an `animationend` arrives — that is why every entrance here
259
+ * is scoped `data-[state=open]:` — and a closed element with no animation at
260
+ * all unmounts on the spot. A `data-[state=closed]:` animation is what turns
261
+ * that all-or-nothing into an ordinary timed exit, and it stays safe under
262
+ * `prefers-reduced-motion`: `global.css` collapses the duration to 0.01ms,
263
+ * which still fires `animationend`, so the overlay still unmounts. --------- */
264
+ --animate-fade-out: fade-out var(--duration-fast) var(--ease-in) both; /* the exit answering `fade` */
265
+ --animate-fade-fall: fade-fall var(--duration-fast) var(--ease-in) both; /* the exit answering `fade-rise` */
266
+ --animate-scale-out: scale-out var(--duration-instant) var(--ease-in) both; /* the exit answering `scale-in` */
267
+
268
+ /* An edge-anchored panel leaving the way it came. `--duration-normal` against
269
+ * the `slow` entrance a drawer uses: 320ms is what stops a full-height panel
270
+ * arriving like a flinch, and none of that reasoning applies to a panel on
271
+ * its way out.
272
+ *
273
+ * There is no matching `slide-in` family, and that is a decision rather than
274
+ * an omission — see `Drawer.vue`, which enters on `@starting-style` because a
275
+ * transition composes with a live swipe gesture where a keyframe would fight
276
+ * it. The exit has no such conflict and cannot be a transition at all:
277
+ * `Presence` observes `animationend` and never `transitionend`, so a
278
+ * transition-based exit is unmounted before it can run. --------------------- */
279
+ --animate-slide-out-to-left: slide-out-to-left var(--duration-normal) var(--ease-in) both; /* a panel leaving past the left edge */
280
+ --animate-slide-out-to-right: slide-out-to-right var(--duration-normal) var(--ease-in) both; /* a panel leaving past the right edge */
281
+ --animate-slide-out-to-top: slide-out-to-top var(--duration-normal) var(--ease-in) both; /* a panel leaving past the top edge */
282
+ --animate-slide-out-to-bottom: slide-out-to-bottom var(--duration-normal) var(--ease-in) both; /* a panel leaving past the bottom edge */
189
283
  }
190
284
 
191
285
  /* Tailwind has no `--duration-*` theme namespace — `duration-*` takes a bare
@@ -205,8 +299,112 @@
205
299
  transition-duration: var(--duration-slower);
206
300
  }
207
301
 
208
- /* The seam, as a background. A gradient is not a colour, so it has no colour
209
- * namespace to live in; this is the only sanctioned way to paint one. */
210
- @utility bg-seam {
211
- background-image: var(--seam);
302
+ /* ---- Dark theme overrides ------------------------------------------------
303
+ * Every semantic token overridden; no "fallback to light". Switching replaces
304
+ * the entire set, so the two cannot drift apart and contrast is verified for
305
+ * each independently. `data-theme` on `<html>` is the single source of truth.
306
+ *
307
+ * Design principles:
308
+ * - Same hue family, adjusted lightness — dark is the mirror, not a new palette
309
+ * - Functional tokens slightly desaturated — bright saturated colours on dark
310
+ * backgrounds cause eye strain and fail contrast against dark surfaces
311
+ * - Elevation = lighter background, not shadow — shadows are invisible on dark
312
+ * - Borders brighten — the hairline that recedes on light must be visible on dark
313
+ * - `muted-foreground-soft` stays above 3:1 (graphical-object floor)
314
+ * - Focus ring stays primary — halo shifts to a lighter shade for visibility
315
+ *
316
+ * Contrast is verified: all text pairings clear 4.5:1; all graphical-object
317
+ * pairings clear 3:1. See the contrast verification table in the repository
318
+ * for the full audit. ----------------------------------------------------- */
319
+ :root[data-theme="dark"] {
320
+ /* ---- Neutrals: same hue family, inverted lightness ---- */
321
+
322
+ /* Elevation in dark = lighter: sunken(7%) < background(10%) < card(14%) < popover(17%).
323
+ * Light: sunken(93%) < background(96%) < card(100%) = popover(100%).
324
+ * Dark mirrors the order with the 4-7% steps that keep surfaces distinct
325
+ * while staying dark enough for high foreground contrast. */
326
+ --color-background: hsl(213 25% 10%);
327
+ --color-foreground: hsl(
328
+ 213 20% 92%
329
+ ); /* S narrowed 29→20 for softer read; 14.68:1 on background */
330
+
331
+ --color-card: hsl(213 20% 14%);
332
+ --color-card-foreground: hsl(213 20% 92%);
333
+
334
+ --color-sunken: hsl(213 24% 7%);
335
+
336
+ --color-popover: hsl(213 18% 17%);
337
+ --color-popover-foreground: hsl(213 20% 92%);
338
+
339
+ --color-muted: hsl(213 16% 13%);
340
+ --color-muted-foreground: hsl(213 10% 60%); /* S 14→10%; 6.06:1 on background */
341
+
342
+ /* Graphical-object token: clears 3:1 (4.03:1 on background). In light the
343
+ * gap is 9pp (41→50); in dark it widens to 12pp (60→48) because the 3:1
344
+ * floor binds tighter on dark. */
345
+ --color-muted-foreground-soft: hsl(213 8% 48%);
346
+
347
+ /* Borders brighten — the hairline that recedes on light must be visible on
348
+ * dark. Input and border-strong carry additional indicators (background fill,
349
+ * label) beyond the border alone. */
350
+ --color-border: hsl(213 14% 22%);
351
+ --color-border-strong: hsl(213 10% 36%);
352
+ --color-input: hsl(213 12% 28%);
353
+
354
+ --color-subtle: hsl(213 20% 13%);
355
+ --color-subtle-foreground: hsl(213 20% 86%);
356
+
357
+ /* ---- Primary — lightened (32→45%) and desaturated (37→33%) so the colour
358
+ * is visible on dark without eye strain. White foreground still clears 4.5:1
359
+ * (5.05:1) because blue's low luminance-per-lightness keeps the base dark. - */
360
+ --color-primary: hsl(211 33% 45%);
361
+ --color-primary-foreground: hsl(0 0% 100%);
362
+ --color-primary-muted: hsl(211 28% 13%);
363
+
364
+ /* ---- Accent — lightened (39→44%) and desaturated (56→48%). -------------- */
365
+ --color-accent: hsl(18 48% 44%);
366
+ --color-accent-foreground: hsl(0 0% 100%);
367
+ --color-accent-muted: hsl(18 35% 13%);
368
+
369
+ --color-secondary: hsl(213 16% 14%);
370
+ --color-secondary-foreground: hsl(213 20% 88%);
371
+
372
+ --color-ring: hsl(211 33% 45%); /* matches primary; 3.50:1 on background */
373
+
374
+ /* ---- Functional — each lightened and desaturated for dark ---- */
375
+
376
+ --color-destructive: hsl(356 55% 48%);
377
+ --color-destructive-foreground: hsl(0 0% 100%);
378
+ --color-success: hsl(152 38% 36%);
379
+ --color-success-foreground: hsl(0 0% 100%);
380
+ /* Amber has very high luminance-per-lightness; white text fails, so the
381
+ * foreground is near-black. Dark text on amber is the universal pattern. */
382
+ --color-warning: hsl(38 80% 50%);
383
+ --color-warning-foreground: hsl(0 0% 5%);
384
+ --color-info: hsl(202 55% 40%);
385
+ --color-info-foreground: hsl(0 0% 100%);
386
+
387
+ /* Functional-muted surfaces. In light each wash holds 4.5:1 against its base
388
+ * hue (dark text on light wash). In dark the luminance range of dark surfaces
389
+ * is too compressed for that — a surface dark enough for 4.5:1 base-as-text
390
+ * would be indistinguishable from the background. Each base hue instead
391
+ * clears the 3:1 graphical-object floor on its muted surface (icons,
392
+ * indicators), and text uses the foreground token (12-14:1 on every surface). */
393
+ --color-destructive-muted: hsl(356 40% 13%);
394
+ --color-success-muted: hsl(152 28% 13%);
395
+ --color-warning-muted: hsl(38 45% 13%);
396
+ --color-info-muted: hsl(202 35% 13%);
397
+
398
+ /* ---- Elevation: shadow recedes, background lightness ascends ----
399
+ * Shadows are nearly invisible on dark; elevation is communicated through
400
+ * the background lightness gradient (sunken through popover). The shadow
401
+ * tokens use a near-black colour with raised opacity so they remain faintly
402
+ * perceptible on the lightest dark surfaces (card, popover). */
403
+ --shadow-sm: 0 1px 2px 0 hsl(213 30% 2% / 0.18);
404
+ --shadow-md: 0 4px 12px -2px hsl(213 30% 2% / 0.22), 0 2px 6px -2px hsl(213 30% 2% / 0.16);
405
+ --shadow-lg: 0 12px 32px -6px hsl(213 30% 2% / 0.28), 0 4px 10px -4px hsl(213 30% 2% / 0.18);
406
+
407
+ /* Focus halo — shifts to the lighter dark-primary and raises opacity for
408
+ * visibility on dark surfaces. */
409
+ --shadow-halo: 0 0 0 4px hsl(211 33% 45% / 0.35);
212
410
  }
package/dist/theme.js ADDED
@@ -0,0 +1,171 @@
1
+ import { computed, onScopeDispose, ref, watch } from "vue";
2
+ //#region src/lib/theme.ts
3
+ /**
4
+ * Theme switching for Loom.
5
+ *
6
+ * The single source of truth is the `data-theme` attribute on `<html>`.
7
+ * This composable reads and writes it, persists the preference to
8
+ * `localStorage`, and resolves `"system"` mode from the OS preference.
9
+ *
10
+ * SSR-safe: every DOM access is guarded. On the server, `theme` returns
11
+ * the persisted or default preference, `resolvedTheme` resolves `"system"`
12
+ * to `"light"` (the only safe default without a DOM), and the setter and
13
+ * toggler are no-ops.
14
+ *
15
+ * Flash prevention: `themeScript` is a string of inline JavaScript that
16
+ * reads `localStorage` and sets `data-theme` before the first paint.
17
+ * Consumers rendering SSR inject it into `<head>`:
18
+ *
19
+ * <script>${themeScript}<\/script>
20
+ */
21
+ var STORAGE_KEY = "loom:theme";
22
+ var DATA_ATTR = "data-theme";
23
+ var MEDIA_QUERY = "(prefers-color-scheme: dark)";
24
+ /** Default preference when nothing is stored and no OS signal exists. */
25
+ var DEFAULT_PREFERENCE = "system";
26
+ /**
27
+ * Reactive shared state, lazily initialised on the first `useTheme()` call
28
+ * and torn down with the effect scope that owns it. Multiple components
29
+ * calling `useTheme()` in the same app share the same refs and the same
30
+ * `matchMedia` listener.
31
+ */
32
+ var sharedState = null;
33
+ /**
34
+ * Reset the shared state. Intended for test isolation only — a real app
35
+ * never needs this because the state lives for the app's lifetime.
36
+ */
37
+ function _resetThemeState() {
38
+ if (sharedState?.mediaQuery && sharedState.listener) sharedState.mediaQuery.removeEventListener("change", sharedState.listener);
39
+ sharedState = null;
40
+ }
41
+ function getSharedState() {
42
+ if (sharedState) {
43
+ sharedState.scopeCount++;
44
+ return sharedState;
45
+ }
46
+ let stored = DEFAULT_PREFERENCE;
47
+ try {
48
+ const raw = localStorage.getItem(STORAGE_KEY);
49
+ if (raw === "light" || raw === "dark" || raw === "system") stored = raw;
50
+ } catch {}
51
+ applyToDOM(resolveTheme(stored, getSystemIsDark()));
52
+ const preference = ref(stored);
53
+ const systemIsDark = ref(getSystemIsDark());
54
+ let mediaQuery = null;
55
+ let listener = null;
56
+ try {
57
+ mediaQuery = window.matchMedia(MEDIA_QUERY);
58
+ listener = (e) => {
59
+ systemIsDark.value = e.matches;
60
+ };
61
+ mediaQuery.addEventListener("change", listener);
62
+ } catch {}
63
+ sharedState = {
64
+ preference,
65
+ systemIsDark,
66
+ mediaQuery,
67
+ listener,
68
+ scopeCount: 1
69
+ };
70
+ return sharedState;
71
+ }
72
+ function releaseSharedState() {
73
+ if (!sharedState) return;
74
+ sharedState.scopeCount--;
75
+ if (sharedState.scopeCount > 0) return;
76
+ if (sharedState.mediaQuery && sharedState.listener) sharedState.mediaQuery.removeEventListener("change", sharedState.listener);
77
+ sharedState = null;
78
+ }
79
+ function getSystemIsDark() {
80
+ try {
81
+ return window.matchMedia(MEDIA_QUERY).matches;
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+ function resolveTheme(pref, systemDark) {
87
+ return pref === "system" ? systemDark ? "dark" : "light" : pref;
88
+ }
89
+ function applyToDOM(theme) {
90
+ try {
91
+ document.documentElement.setAttribute(DATA_ATTR, theme);
92
+ } catch {}
93
+ }
94
+ function persist(preference) {
95
+ try {
96
+ localStorage.setItem(STORAGE_KEY, preference);
97
+ } catch {}
98
+ }
99
+ /**
100
+ * Read and control the active Loom theme.
101
+ *
102
+ * @example
103
+ * ```vue
104
+ * <script setup>
105
+ * import { useTheme } from "@ecoma-io/loom/theme"
106
+ * const { theme, resolvedTheme, setTheme, toggleTheme } = useTheme()
107
+ * <\/script>
108
+ *
109
+ * <template>
110
+ * <button @click="toggleTheme">
111
+ * {{ resolvedTheme === "dark" ? "☀️" : "🌙" }}
112
+ * </button>
113
+ * </template>
114
+ * ```
115
+ */
116
+ function useTheme() {
117
+ const state = getSharedState();
118
+ onScopeDispose(releaseSharedState);
119
+ /** The user's preference — `"system"` defers to the OS. */
120
+ const theme = computed({
121
+ get: () => state.preference.value,
122
+ set: (value) => {
123
+ state.preference.value = value;
124
+ }
125
+ });
126
+ /** The actual active theme, with `"system"` resolved to `"light"` or `"dark"`. */
127
+ const resolvedTheme = computed(() => resolveTheme(state.preference.value, state.systemIsDark.value));
128
+ watch([() => state.preference.value, () => state.systemIsDark.value], () => {
129
+ applyToDOM(resolvedTheme.value);
130
+ persist(state.preference.value);
131
+ });
132
+ /** Set the theme preference explicitly. */
133
+ function setTheme(preference) {
134
+ state.preference.value = preference;
135
+ }
136
+ /** Toggle between light and dark. System preference stays system. */
137
+ function toggleTheme() {
138
+ if (state.preference.value === "system") state.preference.value = resolvedTheme.value === "dark" ? "light" : "dark";
139
+ else state.preference.value = state.preference.value === "dark" ? "light" : "dark";
140
+ }
141
+ return {
142
+ theme,
143
+ resolvedTheme,
144
+ setTheme,
145
+ toggleTheme
146
+ };
147
+ }
148
+ /**
149
+ * Inline script to prevent flash-of-wrong-theme on SSR pages.
150
+ *
151
+ * Paste it into `<head>` before any stylesheet links:
152
+ *
153
+ * ```html
154
+ * <script><%= themeScript %><\/script>
155
+ * ```
156
+ *
157
+ * It reads `localStorage` and sets `data-theme` on `<html>` synchronously,
158
+ * before the browser paints, so the first frame is already in the right
159
+ * theme. When no preference is stored, it follows the OS preference.
160
+ *
161
+ * The script is deliberately tiny and has no dependencies.
162
+ */
163
+ var themeScript = `(() => {
164
+ const t = localStorage.getItem("${STORAGE_KEY}");
165
+ const d = window.matchMedia("${MEDIA_QUERY}").matches;
166
+ document.documentElement.setAttribute("${DATA_ATTR}", (t === "dark" || (!t && d)) ? "dark" : "light");
167
+ })()`;
168
+ //#endregion
169
+ export { _resetThemeState, themeScript, useTheme };
170
+
171
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","names":[],"sources":["../src/lib/theme.ts"],"sourcesContent":["/**\n * Theme switching for Loom.\n *\n * The single source of truth is the `data-theme` attribute on `<html>`.\n * This composable reads and writes it, persists the preference to\n * `localStorage`, and resolves `\"system\"` mode from the OS preference.\n *\n * SSR-safe: every DOM access is guarded. On the server, `theme` returns\n * the persisted or default preference, `resolvedTheme` resolves `\"system\"`\n * to `\"light\"` (the only safe default without a DOM), and the setter and\n * toggler are no-ops.\n *\n * Flash prevention: `themeScript` is a string of inline JavaScript that\n * reads `localStorage` and sets `data-theme` before the first paint.\n * Consumers rendering SSR inject it into `<head>`:\n *\n * <script>${themeScript}</script>\n */\n\nimport { type Ref, computed, onScopeDispose, ref, watch } from \"vue\";\n\n/** The preference a user expresses — `\"system\"` defers to the OS. */\nexport type ThemePreference = \"light\" | \"dark\" | \"system\";\n\n/** The actual theme applied — `\"system\"` is resolved away. */\nexport type ResolvedTheme = \"light\" | \"dark\";\n\nconst STORAGE_KEY = \"loom:theme\";\nconst DATA_ATTR = \"data-theme\";\nconst MEDIA_QUERY = \"(prefers-color-scheme: dark)\";\n\n/** Default preference when nothing is stored and no OS signal exists. */\nconst DEFAULT_PREFERENCE: ThemePreference = \"system\";\n\n// --- Shared state (one per Vue app, not one per composable call) ---------\n\ninterface ThemeState {\n preference: Ref<ThemePreference>;\n systemIsDark: Ref<boolean>;\n mediaQuery: MediaQueryList | null;\n listener: ((e: MediaQueryListEvent) => void) | null;\n scopeCount: number;\n}\n\n/**\n * Reactive shared state, lazily initialised on the first `useTheme()` call\n * and torn down with the effect scope that owns it. Multiple components\n * calling `useTheme()` in the same app share the same refs and the same\n * `matchMedia` listener.\n */\nlet sharedState: ThemeState | null = null;\n\n/**\n * Reset the shared state. Intended for test isolation only — a real app\n * never needs this because the state lives for the app's lifetime.\n */\nexport function _resetThemeState(): void {\n if (sharedState?.mediaQuery && sharedState.listener) {\n sharedState.mediaQuery.removeEventListener(\"change\", sharedState.listener);\n }\n sharedState = null;\n}\n\nfunction getSharedState(): ThemeState {\n if (sharedState) {\n sharedState.scopeCount++;\n return sharedState;\n }\n\n // Read the stored preference, defaulting to \"system\".\n let stored: ThemePreference = DEFAULT_PREFERENCE;\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (raw === \"light\" || raw === \"dark\" || raw === \"system\") {\n stored = raw;\n }\n } catch {\n // localStorage may be unavailable (SSR, private browsing).\n }\n\n // Apply the initial theme to the DOM so the very first render is correct.\n const initial = resolveTheme(stored, getSystemIsDark());\n applyToDOM(initial);\n\n const preference = ref<ThemePreference>(stored);\n const systemIsDark = ref<boolean>(getSystemIsDark());\n\n // Listen for OS dark-mode changes.\n let mediaQuery: MediaQueryList | null = null;\n let listener: ((e: MediaQueryListEvent) => void) | null = null;\n\n try {\n mediaQuery = window.matchMedia(MEDIA_QUERY);\n listener = (e: MediaQueryListEvent) => {\n systemIsDark.value = e.matches;\n };\n mediaQuery.addEventListener(\"change\", listener);\n } catch {\n // matchMedia may be unavailable.\n }\n\n sharedState = {\n preference,\n systemIsDark,\n mediaQuery,\n listener,\n scopeCount: 1,\n };\n\n return sharedState;\n}\n\nfunction releaseSharedState(): void {\n if (!sharedState) return;\n sharedState.scopeCount--;\n if (sharedState.scopeCount > 0) return;\n\n // Last consumer gone — tear down the listener.\n if (sharedState.mediaQuery && sharedState.listener) {\n sharedState.mediaQuery.removeEventListener(\"change\", sharedState.listener);\n }\n sharedState = null;\n}\n\n// --- DOM helpers --------------------------------------------------------\n\nfunction getSystemIsDark(): boolean {\n try {\n return window.matchMedia(MEDIA_QUERY).matches;\n } catch {\n return false;\n }\n}\n\nfunction resolveTheme(pref: ThemePreference, systemDark: boolean): ResolvedTheme {\n return pref === \"system\" ? (systemDark ? \"dark\" : \"light\") : pref;\n}\n\nfunction applyToDOM(theme: ResolvedTheme): void {\n try {\n document.documentElement.setAttribute(DATA_ATTR, theme);\n } catch {\n // document may be unavailable (SSR).\n }\n}\n\nfunction persist(preference: ThemePreference): void {\n try {\n localStorage.setItem(STORAGE_KEY, preference);\n } catch {\n // localStorage may be unavailable.\n }\n}\n\n// --- Public API ---------------------------------------------------------\n\n/**\n * Read and control the active Loom theme.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useTheme } from \"@ecoma-io/loom/theme\"\n * const { theme, resolvedTheme, setTheme, toggleTheme } = useTheme()\n * </script>\n *\n * <template>\n * <button @click=\"toggleTheme\">\n * {{ resolvedTheme === \"dark\" ? \"☀️\" : \"🌙\" }}\n * </button>\n * </template>\n * ```\n */\nexport function useTheme(): {\n readonly theme: Ref<ThemePreference>;\n readonly resolvedTheme: Readonly<Ref<ResolvedTheme>>;\n readonly setTheme: (preference: ThemePreference) => void;\n readonly toggleTheme: () => void;\n} {\n const state = getSharedState();\n\n // Clean up the shared listener when the consuming scope disposes.\n onScopeDispose(releaseSharedState);\n\n /** The user's preference — `\"system\"` defers to the OS. */\n const theme = computed<ThemePreference>({\n get: () => state.preference.value,\n set: (value: ThemePreference) => {\n state.preference.value = value;\n },\n });\n\n /** The actual active theme, with `\"system\"` resolved to `\"light\"` or `\"dark\"`. */\n const resolvedTheme = computed<ResolvedTheme>(() =>\n resolveTheme(state.preference.value, state.systemIsDark.value),\n );\n\n // Whenever the preference or the OS signal changes, apply the resolved\n // theme to the DOM and persist the preference.\n watch([() => state.preference.value, () => state.systemIsDark.value], () => {\n applyToDOM(resolvedTheme.value);\n persist(state.preference.value);\n });\n\n /** Set the theme preference explicitly. */\n function setTheme(preference: ThemePreference): void {\n state.preference.value = preference;\n }\n\n /** Toggle between light and dark. System preference stays system. */\n function toggleTheme(): void {\n if (state.preference.value === \"system\") {\n // Toggle the resolved theme and lock to it, so the user can override\n // the OS preference with one click.\n state.preference.value = resolvedTheme.value === \"dark\" ? \"light\" : \"dark\";\n } else {\n state.preference.value = state.preference.value === \"dark\" ? \"light\" : \"dark\";\n }\n }\n\n return { theme, resolvedTheme, setTheme, toggleTheme } as const;\n}\n\n/**\n * Inline script to prevent flash-of-wrong-theme on SSR pages.\n *\n * Paste it into `<head>` before any stylesheet links:\n *\n * ```html\n * <script><%= themeScript %></script>\n * ```\n *\n * It reads `localStorage` and sets `data-theme` on `<html>` synchronously,\n * before the browser paints, so the first frame is already in the right\n * theme. When no preference is stored, it follows the OS preference.\n *\n * The script is deliberately tiny and has no dependencies.\n */\nexport const themeScript = `(() => {\n const t = localStorage.getItem(\"${STORAGE_KEY}\");\n const d = window.matchMedia(\"${MEDIA_QUERY}\").matches;\n document.documentElement.setAttribute(\"${DATA_ATTR}\", (t === \"dark\" || (!t && d)) ? \"dark\" : \"light\");\n})()`;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA2BA,IAAM,cAAc;AACpB,IAAM,YAAY;AAClB,IAAM,cAAc;;AAGpB,IAAM,qBAAsC;;;;;;;AAkB5C,IAAI,cAAiC;;;;;AAMrC,SAAgB,mBAAyB;CACvC,IAAI,aAAa,cAAc,YAAY,UACzC,YAAY,WAAW,oBAAoB,UAAU,YAAY,QAAQ;CAE3E,cAAc;AAChB;AAEA,SAAS,iBAA6B;CACpC,IAAI,aAAa;EACf,YAAY;EACZ,OAAO;CACT;CAGA,IAAI,SAA0B;CAC9B,IAAI;EACF,MAAM,MAAM,aAAa,QAAQ,WAAW;EAC5C,IAAI,QAAQ,WAAW,QAAQ,UAAU,QAAQ,UAC/C,SAAS;CAEb,QAAQ,CAER;CAIA,WADgB,aAAa,QAAQ,gBAAgB,CAC1C,CAAO;CAElB,MAAM,aAAa,IAAqB,MAAM;CAC9C,MAAM,eAAe,IAAa,gBAAgB,CAAC;CAGnD,IAAI,aAAoC;CACxC,IAAI,WAAsD;CAE1D,IAAI;EACF,aAAa,OAAO,WAAW,WAAW;EAC1C,YAAY,MAA2B;GACrC,aAAa,QAAQ,EAAE;EACzB;EACA,WAAW,iBAAiB,UAAU,QAAQ;CAChD,QAAQ,CAER;CAEA,cAAc;EACZ;EACA;EACA;EACA;EACA,YAAY;CACd;CAEA,OAAO;AACT;AAEA,SAAS,qBAA2B;CAClC,IAAI,CAAC,aAAa;CAClB,YAAY;CACZ,IAAI,YAAY,aAAa,GAAG;CAGhC,IAAI,YAAY,cAAc,YAAY,UACxC,YAAY,WAAW,oBAAoB,UAAU,YAAY,QAAQ;CAE3E,cAAc;AAChB;AAIA,SAAS,kBAA2B;CAClC,IAAI;EACF,OAAO,OAAO,WAAW,WAAW,CAAC,CAAC;CACxC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,aAAa,MAAuB,YAAoC;CAC/E,OAAO,SAAS,WAAY,aAAa,SAAS,UAAW;AAC/D;AAEA,SAAS,WAAW,OAA4B;CAC9C,IAAI;EACF,SAAS,gBAAgB,aAAa,WAAW,KAAK;CACxD,QAAQ,CAER;AACF;AAEA,SAAS,QAAQ,YAAmC;CAClD,IAAI;EACF,aAAa,QAAQ,aAAa,UAAU;CAC9C,QAAQ,CAER;AACF;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,WAKd;CACA,MAAM,QAAQ,eAAe;CAG7B,eAAe,kBAAkB;;CAGjC,MAAM,QAAQ,SAA0B;EACtC,WAAW,MAAM,WAAW;EAC5B,MAAM,UAA2B;GAC/B,MAAM,WAAW,QAAQ;EAC3B;CACF,CAAC;;CAGD,MAAM,gBAAgB,eACpB,aAAa,MAAM,WAAW,OAAO,MAAM,aAAa,KAAK,CAC/D;CAIA,MAAM,OAAO,MAAM,WAAW,aAAa,MAAM,aAAa,KAAK,SAAS;EAC1E,WAAW,cAAc,KAAK;EAC9B,QAAQ,MAAM,WAAW,KAAK;CAChC,CAAC;;CAGD,SAAS,SAAS,YAAmC;EACnD,MAAM,WAAW,QAAQ;CAC3B;;CAGA,SAAS,cAAoB;EAC3B,IAAI,MAAM,WAAW,UAAU,UAG7B,MAAM,WAAW,QAAQ,cAAc,UAAU,SAAS,UAAU;OAEpE,MAAM,WAAW,QAAQ,MAAM,WAAW,UAAU,SAAS,UAAU;CAE3E;CAEA,OAAO;EAAE;EAAO;EAAe;EAAU;CAAY;AACvD;;;;;;;;;;;;;;;;AAiBA,IAAa,cAAc;oCACS,YAAY;iCACf,YAAY;2CACF,UAAU"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ecoma-io/loom",
3
- "version": "0.1.0",
4
- "description": "Design system & components for the Ecoma ecosystem.",
3
+ "version": "0.2.0",
4
+ "description": "Opinionated UI system and composition library for cross-platform web applications.",
5
5
  "keywords": [
6
6
  "design-system",
7
7
  "component-library",
@@ -16,7 +16,10 @@
16
16
  "wcag",
17
17
  "theming",
18
18
  "dark-mode",
19
- "ecoma"
19
+ "cross-platform",
20
+ "desktop",
21
+ "responsive",
22
+ "composition"
20
23
  ],
21
24
  "homepage": "https://github.com/ecoma-io/loom#readme",
22
25
  "repository": {
@@ -47,6 +50,10 @@
47
50
  "types": "./dist/a11y.d.ts",
48
51
  "default": "./dist/a11y.js"
49
52
  },
53
+ "./theme": {
54
+ "types": "./dist/lib/theme.d.ts",
55
+ "default": "./dist/theme.js"
56
+ },
50
57
  "./styles/global.css": "./dist/styles/global.css",
51
58
  "./styles/theme.css": "./dist/styles/theme.css",
52
59
  "./styles/fonts.css": "./dist/styles/fonts.css",
@@ -64,7 +71,7 @@
64
71
  "prepare": "lefthook install",
65
72
  "format": "prettier --write .",
66
73
  "format:check": "prettier --check .",
67
- "lint": "eslint . --max-warnings 0 && node tools/check-component-artifacts.ts",
74
+ "lint": "eslint . --cache --cache-strategy content --cache-location node_modules/.cache/eslint --max-warnings 0 && node tools/check-component-artifacts.ts",
68
75
  "typecheck": "vue-tsc --noEmit",
69
76
  "test": "vitest run",
70
77
  "test:watch": "vitest",
@@ -73,6 +80,7 @@
73
80
  "docs:dev": "vitepress dev docs",
74
81
  "docs:build": "vitepress build docs",
75
82
  "docs:stage": "node tools/stage-docs.ts",
83
+ "docs:check-route": "node tools/stage-docs.ts --check",
76
84
  "docs:preview": "vitepress preview docs"
77
85
  },
78
86
  "devDependencies": {
@@ -87,6 +95,7 @@
87
95
  "@vitest/coverage-v8": "^4.1.10",
88
96
  "@vitest/eslint-plugin": "^1.6.26",
89
97
  "@vue/test-utils": "^2.4.11",
98
+ "@vue/typescript-plugin": "3.3.9",
90
99
  "eslint": "^10.8.0",
91
100
  "eslint-config-prettier": "^10.1.8",
92
101
  "eslint-plugin-playwright": "^2.11.0",
@@ -111,6 +120,7 @@
111
120
  "wrangler": "^4.118.0"
112
121
  },
113
122
  "dependencies": {
123
+ "@internationalized/date": "^3.12.3",
114
124
  "@lucide/vue": "^1.28.0",
115
125
  "class-variance-authority": "^0.7.1",
116
126
  "clsx": "^2.1.1",
@@ -1,18 +0,0 @@
1
- /**
2
- * BrandMark — one face, two forces. The left half is human (an almond eye),
3
- * the right half is the agent (a rectangular eye), and the dividing line is a
4
- * nose bridge: both halves belong to the same face, which is the
5
- * organization.
6
- *
7
- * Built with `createLucideIcon` so it takes exactly the props any Lucide icon
8
- * takes — size, strokeWidth, color — and a consumer cannot tell a custom icon
9
- * from a stock one. Custom icons live in this folder and follow the same
10
- * recipe: 24-unit grid geometry, stroke through `currentColor`.
11
- *
12
- * The duotone treatment, where the warp and weft halves carry their own
13
- * colours, is a brand asset rather than an icon. An icon stays monochrome so
14
- * it can inherit whatever colour it is dropped into.
15
- */
16
- declare const BrandMark: import("@lucide/vue").LucideIcon;
17
- export default BrandMark;
18
- //# sourceMappingURL=BrandMark.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BrandMark.d.ts","sourceRoot":"","sources":["../../src/icons/BrandMark.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,SAAS,kCAgBb,CAAC;AAEH,eAAe,SAAS,CAAC"}