@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
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <p align="center">
2
2
  <a href="https://github.com/ecoma-io/loom/actions/workflows/ci.yml"><img src="https://github.com/ecoma-io/loom/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
3
- <a href="https://github.com/ecoma-io/loom/actions/workflows/analysis.yml"><img src="https://github.com/ecoma-io/loom/actions/workflows/analysis.yml/badge.svg" alt="Analysis" /></a>
3
+ <a href="https://github.com/ecoma-io/loom/actions/workflows/analysis.yml"><img src="https://img.shields.io/badge/analysis-semgrep-purple.svg" alt="Analysis" /></a>
4
4
  <a href="https://scorecard.dev/viewer/?uri=github.com/ecoma-io/loom"><img src="https://api.scorecard.dev/projects/github.com/ecoma-io/loom/badge" alt="OpenSSF Scorecard" /></a>
5
5
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue.svg" alt="License: Apache 2.0" /></a>
6
6
  <img src="https://img.shields.io/badge/node-%3E%3D24-brightgreen.svg" alt="Node >= 24" />
@@ -10,21 +10,20 @@
10
10
  </p>
11
11
 
12
12
  <p align="center">
13
- <img src=".github/assets/banner.png" alt="Loom — the open-source design system and Vue 3 component library of the Ecoma ecosystem" width="100%" />
13
+ <img src=".github/assets/banner.png" alt="Loom — an opinionated UI system and composition library for cross-platform web applications" width="100%" />
14
14
  </p>
15
15
 
16
16
  <h1 align="center">Loom</h1>
17
17
 
18
18
  <p align="center">
19
- <strong>Design system &amp; components for the Ecoma ecosystem.</strong><br />
19
+ <strong>Opinionated UI system &amp; composition library for cross-platform web applications.</strong><br />
20
20
  An open-source, accessibility-first component library and design-token system —
21
- Vue 3, TypeScript and Tailwind CSS — powering every human and AI-agent surface
22
- Ecoma ships.<br />
21
+ Vue&nbsp;3, TypeScript and Tailwind&nbsp;CSS — from mobile to ultrawide.<br />
23
22
  <em>Build the interface once. Ship it everywhere. Never re-decide what a button is.</em>
24
23
  </p>
25
24
 
26
25
  <p align="center">
27
- <a href="https://ecoma.io/docs/contribute/design-system"><strong>Website&nbsp;→</strong></a>
26
+ <a href="https://loom.ecoma.io"><strong>Documentation&nbsp;→</strong></a>
28
27
  </p>
29
28
 
30
29
  ---
@@ -38,43 +37,35 @@ decision to each product and it is not made once. It is made again, slightly
38
37
  differently, every sprint, by whoever is closest to the deadline.
39
38
 
40
39
  **Loom is where that decision lives.** One vocabulary of design tokens, one set
41
- of accessible UI primitives, one motion language — consumed by every Ecoma
42
- surface, owned by none of them. Open source under Apache-2.0, so you can take it
43
- into your own product on the same terms.
44
-
45
- ## Built for Ecoma a labor operating system for humans and AI agents
46
-
47
- Loom is the interface layer of [**Ecoma**](https://ecoma.io), the self-hostable,
48
- fair-code **labor operating system** where people, AI agents and rules are the
49
- same kind of resource: a role, and whoever fills it. Workflows are co-designed by
50
- humans and AI inside the engine, every output crosses a checkpoint calibrated on
51
- each tenant's own data, and human attention is treated as a budget to be measured
52
- rather than a well to be drained — from a one-person company to an enterprise.
53
-
54
- That premise is unusually demanding on a UI. Most component libraries assume a
55
- person is behind every action. Ecoma's screens have to show work a person did,
56
- work an agent proposed, and the seam between the two — confidence, provenance,
57
- the moment a human has to decide without the interface picking a side.
58
-
59
- **Loom is that vocabulary, extracted and made reusable.** If you are building
60
- anything where automation and people share a workspace an internal tool, an
61
- agent console, a human-in-the-loop review queue, a workflow or BPM product — the
62
- problems it solves are already yours.
63
-
64
- ## The idea in one picture
65
-
66
- The name is the architecture:
67
-
68
- - **Warp the human thread.** Everything a person reaches for directly: the
69
- controls, the affordances, the feedback that says an action landed.
70
- - **Weft — the agent thread.** Everything the machine contributes: proposals,
71
- confidence, provenance, the state of work nobody is watching.
72
- - **The seam.** Where the two cross is the only place the system raises its
73
- voice — a checkpoint, a hand-off, a decision that needs a human. Everywhere
74
- else it stays quiet on purpose.
75
-
76
- Light-first, enterprise-toned, and dark from the same tokens rather than as a
77
- second theme bolted on afterwards.
40
+ of accessible UI primitives, one motion language — consumed by every surface,
41
+ owned by none of them. Open source under Apache-2.0, so you can take it into
42
+ your own product on the same terms.
43
+
44
+ ## Built for cross-platform web applications
45
+
46
+ Loom is designed for applications that run everywhere the web does: browsers,
47
+ progressive web apps, Electron, and Tauri (desktop and mobile). A component
48
+ library for products that need desktop window chrome, responsive layouts that
49
+ stretch from phone to ultrawide, and an opinionated visual language that is
50
+ ready to ship not a skeleton to assemble.
51
+
52
+ That premise demands more than a component dump. It demands:
53
+
54
+ - **Responsive composition**, not just responsive CSS layout primitives that
55
+ adapt to viewport and container, so a sidebar collapses at the right width
56
+ and a master-detail panel stacks on mobile without the host writing a
57
+ breakpoint.
58
+ - **Desktop awareness** title bars, window controls, safe-area insets. A
59
+ Tauri or Electron window has chrome a web page does not, and the components
60
+ that live in it need to know that.
61
+ - **Content never stretches to infinity** — on an ultrawide monitor, readable
62
+ content is bounded and the extra viewport goes to intentional whitespace,
63
+ side panels, or supplementary content. Never to stretching.
64
+ - **Same design language on every viewport** — a button is the same button at
65
+ 320px and 3440px. The layout around it changes; the button does not.
66
+
67
+ Loom originated within the [Ecoma](https://ecoma.io) ecosystem and is developed
68
+ as an independent open-source UI system.
78
69
 
79
70
  ## What Loom gives you
80
71
 
@@ -82,21 +73,23 @@ second theme bolted on afterwards.
82
73
  | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
83
74
  | **Design tokens** | Colour, spacing, radius, elevation, typography and motion — one source that light mode and dark mode both read from, so a rebrand is an edit rather than an audit. |
84
75
  | **UI primitives** | The generic controls every product needs and no product should own: buttons, inputs, selects, dialogs, menus, toasts, tooltips, skeletons, switches, progress. |
85
- | **Blocks** | Compositions worth standardising once empty states, confirmations, forms, review queues assembled from primitives, never from scratch. |
76
+ | **Composition primitives** | Layout building blocksStack, Grid, Split, Center, Sidebarthat express spatial intent and adapt to viewport without the host writing breakpoint queries. |
77
+ | **Blocks** | Compositions worth standardising once — empty states, page headers, title bars, sidebar navigation — assembled from primitives, never from scratch. |
86
78
  | **Accessibility, built in** | Keyboard paths, focus restoration, accessible names and reduced-motion behaviour ship inside the component. WCAG is the acceptance bar, not a checklist run afterwards. |
87
79
  | **Theming that survives** | Every visual decision is a token reference, so white-labelling a tenant is configuration rather than a fork. |
88
80
  | **Typed and tree-shakeable** | Ships ES modules with TypeScript types. Consumers bundle what they import and nothing more. |
89
81
 
90
82
  ## Who this is for
91
83
 
92
- - **Teams building on Ecoma** — this is the interface layer; consume it rather
93
- than re-deriving it.
94
- - **Anyone shipping human-in-the-loop or AI-agent products** the hard part is
95
- showing machine work to a person honestly, and that is what these components
96
- were shaped around.
84
+ - **Teams building cross-platform web applications** — especially those
85
+ targeting desktop (Electron, Tauri) alongside browser and mobile, where
86
+ existing component libraries assume a web page, not an application window.
97
87
  - **Design-system maintainers** — the token model, the artifact-per-primitive
98
88
  convention and the accessibility bar are all readable in the open, Apache-2.0,
99
89
  and free to borrow.
90
+ - **Anyone tired of re-deciding what a button is** — Loom is opinionated so
91
+ you don't have to be. Ship the defaults, override the tokens that don't fit,
92
+ and leave the rest alone.
100
93
 
101
94
  ## Getting started
102
95
 
@@ -131,16 +124,13 @@ the same way. That single rule decides most questions about what belongs here,
131
124
  and [CONTRIBUTING.md](CONTRIBUTING.md) covers the rest: the commit format, the
132
125
  tiers of tests, and what a reviewer will look for.
133
126
 
134
- Read the wider design-system programme on the
135
- [**website**](https://ecoma.io/docs/contribute/design-system).
136
-
137
127
  Everyone taking part is held to the [Code of Conduct](CODE_OF_CONDUCT.md).
138
128
  Security issues go through [SECURITY.md](SECURITY.md) — never a public issue.
139
129
 
140
130
  ## Frequently asked
141
131
 
142
132
  **Can I use Loom outside Ecoma?**
143
- Yes. It is Apache-2.0, has no runtime dependency on the Ecoma platform, and is
133
+ Yes. It is Apache-2.0, has no runtime dependency on any Ecoma platform, and is
144
134
  designed to be consumed as an ordinary npm package.
145
135
 
146
136
  **Why Apache-2.0 and not MIT?**
@@ -154,13 +144,20 @@ are framework-neutral CSS custom properties, so they are usable anywhere.
154
144
 
155
145
  **Does it support dark mode?**
156
146
  Dark is derived from the same token set as light rather than maintained as a
157
- second theme, which is why the two cannot drift apart.
147
+ second theme, which is why the two cannot drift apart. A `useTheme` composable
148
+ switches between light, dark, and system preference.
158
149
 
159
150
  **How is accessibility verified?**
160
151
  Keyboard operation, focus restoration and accessible naming are pinned by tests
161
152
  and reviewed on every pull request — see the accessibility section of
162
153
  [CONTRIBUTING.md](CONTRIBUTING.md).
163
154
 
155
+ **What about responsive layouts?**
156
+ Loom provides composition primitives (Stack, Grid, Split, Center, Sidebar) that
157
+ express layout intent and adapt to viewport width. Content is bounded at
158
+ readable widths on ultrawide screens — extra viewport goes to whitespace, not
159
+ stretching.
160
+
164
161
  ## License
165
162
 
166
163
  [Apache License 2.0](LICENSE) © Ecoma.
@@ -172,9 +169,9 @@ Use it, ship it, fork it, sell what you build with it.
172
169
  <p align="center">
173
170
  <img src=".github/assets/logo.png" alt="" width="56" /><br />
174
171
  <sub>
175
- Part of the <a href="https://ecoma.io">Ecoma</a> ecosystem ·
176
- <a href="https://ecoma.io">Website</a> ·
172
+ An <a href="https://ecoma.io">Ecoma</a> open-source project ·
173
+ <a href="https://loom.ecoma.io">Documentation</a> ·
177
174
  <a href="https://github.com/ecoma-io">Organisation</a> ·
178
- <a href="https://ecoma.io/docs/contribute/design-system">Contribute</a>
175
+ <a href="CONTRIBUTING.md">Contribute</a>
179
176
  </sub>
180
177
  </p>
@@ -1 +1 @@
1
- {"version":3,"file":"AppHeader.js","names":[],"sources":["../../../src/blocks/AppHeader/AppHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * AppHeader — the web app's TOP BAR: the shell-level strip that stays on\n * screen above every surface, distinct from two components it is easy to\n * confuse with:\n *\n * - **`PageHeader`** — a surface's own pinned title band, sitting *inside*\n * the content area this bar sits above.\n * - **`TitleBar`** — the desktop window's native chrome (drag region, window\n * controls). This bar is browser content, not window furniture.\n *\n * Layout is three regions, so callers never hand-tune widths: brand (left) ·\n * optional search · a trailing cluster for org-switcher, notifications, and\n * the user menu, pushed right by `ml-auto`. Every region is a named slot —\n * this block owns the strip's geometry and elevation, never its content or\n * behavior.\n *\n * The trailing cluster is pushed right by its own `ml-auto`, not by a spacer\n * element. A spacer works, but it is a second `flex-1` beside the search\n * field, so the two end up splitting the free space instead of the field\n * taking what is actually left; `ml-auto` costs no element and no width, and\n * keeps the cluster flush right even when no search is slotted at all.\n *\n * **Below `sm` the bar is two rows, and that is the point of this block's\n * responsive behavior.** A brand, a real search field, and an org-switcher +\n * notifications + account cluster do not fit across a 390px viewport: on\n * that width the search field is left about 60px and renders as a magnifier\n * glyph pressed against the org name — a control that is technically present\n * and practically unusable. So the search takes a full-width second row\n * (`basis-full` + `order-last`), the header height goes from fixed to\n * `min-h-14`, and from `sm` up it snaps back to the single `flex-nowrap` row.\n * Wrapping rather than hiding is deliberate: the host slotted a search\n * because its users need one, and a block does not get to decide they need\n * it less on a phone.\n *\n * The `order-last` is the one thing to keep in mind if this changes: it\n * moves the search visually below the cluster while leaving it before the\n * cluster in the DOM, so on a phone the tab order reaches search first. That\n * is the better of the two mismatches — search is the more-used control —\n * but it is a mismatch, so do not extend `order-*` to the other regions.\n *\n * **Pinned, and separated by a hairline — never a shadow.** It sits on\n * `bg-card` (the raised plane), one step above the content it sits over,\n * unlike `PageHeader` which shares the content's own `bg-background` plane.\n * Because content scrolls *under* it, the surface is translucent + blurred\n * so the motion beneath stays legible as depth — the opaque `bg-card` is\n * declared first and stays the fallback wherever `backdrop-filter` is\n * unsupported, so the bar is never a see-through smear.\n *\n * Widths step rather than hold one value: gutters open up from `sm` and\n * again on wide desktops (`3xl`, 1920px), where a 16px gutter beside a\n * 1920px canvas reads as an accident.\n *\n * Deliberately neutral: this is shell chrome shared by every user and every\n * agent action alike, so it never wears `--primary`/`--agent` — the\n * dual-force law only paints a surface once a specific force is doing\n * something on it.\n */\ndefineProps<{\n /** Accessible name for the `<header>` landmark, for a page with more than one header-like region. */\n ariaLabel?: string;\n}>();\n</script>\n\n<template>\n <header\n :aria-label=\"ariaLabel\"\n class=\"sticky top-0 z-30 flex min-h-14 flex-wrap items-center gap-x-2 gap-y-2 border-b border-border bg-card px-3 py-2 text-card-foreground backdrop-blur-md supports-[backdrop-filter]:bg-card/80 sm:h-14 sm:flex-nowrap sm:gap-x-3 sm:px-4 sm:py-0 lg:px-6 3xl:h-16 3xl:px-8\"\n >\n <div v-if=\"$slots.brand\" class=\"flex shrink-0 items-center gap-2\">\n <!-- @slot The product mark and name, leftmost. -->\n <slot name=\"brand\" />\n </div>\n\n <!-- Own full-width row below `sm` (see the doc header on `order-last`);\n from `sm` up it rejoins the row and takes a cap so it never stretches\n into a banner on a wide canvas. -->\n <div\n v-if=\"$slots.search\"\n class=\"order-last min-w-0 basis-full sm:order-none sm:max-w-sm sm:flex-1 sm:basis-auto lg:max-w-md\"\n >\n <!-- @slot The app's global search field. Exactly one control — a filter belongs to `PageHeader` or the content area, not here. -->\n <slot name=\"search\" />\n </div>\n\n <div\n v-if=\"$slots.orgSwitcher || $slots.notifications || $slots.userMenu\"\n class=\"ml-auto flex shrink-0 items-center gap-1 sm:gap-2\"\n >\n <!-- @slot The organization switcher, leading the trailing cluster. -->\n <slot name=\"orgSwitcher\" />\n <!-- @slot The notifications trigger, between the org switcher and the account menu. -->\n <slot name=\"notifications\" />\n <!-- @slot The account menu, trailing the cluster. -->\n <slot name=\"userMenu\" />\n </div>\n </header>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"AppHeader.js","names":[],"sources":["../../../src/blocks/AppHeader/AppHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * AppHeader — the web app's TOP BAR: the shell-level strip that stays on\n * screen above every surface, distinct from two components it is easy to\n * confuse with:\n *\n * - **`PageHeader`** — a surface's own pinned title band, sitting *inside*\n * the content area this bar sits above.\n * - **`TitleBar`** — the desktop window's native chrome (drag region, window\n * controls). This bar is browser content, not window furniture.\n *\n * Layout is three regions, so callers never hand-tune widths: brand (left) ·\n * optional search · a trailing cluster for a leading control, notifications, and\n * the user menu, pushed right by `ml-auto`. Every region is a named slot —\n * this block owns the strip's geometry and elevation, never its content or\n * behavior.\n *\n * The trailing cluster is pushed right by its own `ml-auto`, not by a spacer\n * element. A spacer works, but it is a second `flex-1` beside the search\n * field, so the two end up splitting the free space instead of the field\n * taking what is actually left; `ml-auto` costs no element and no width, and\n * keeps the cluster flush right even when no search is slotted at all.\n *\n * **Below `sm` the bar is two rows, and that is the point of this block's\n * responsive behavior.** A brand, a real search field, and a leading control +\n * notifications + account cluster do not fit across a 390px viewport: on\n * that width the search field is left about 60px and renders as a magnifier\n * glyph pressed against the org name — a control that is technically present\n * and practically unusable. So the search takes a full-width second row\n * (`basis-full` + `order-last`), the header height goes from fixed to\n * `min-h-14`, and from `sm` up it snaps back to the single `flex-nowrap` row.\n * Wrapping rather than hiding is deliberate: the host slotted a search\n * because its users need one, and a block does not get to decide they need\n * it less on a phone.\n *\n * The `order-last` is the one thing to keep in mind if this changes: it\n * moves the search visually below the cluster while leaving it before the\n * cluster in the DOM, so on a phone the tab order reaches search first. That\n * is the better of the two mismatches — search is the more-used control —\n * but it is a mismatch, so do not extend `order-*` to the other regions.\n *\n * **Pinned, and separated by a hairline — never a shadow.** It sits on\n * `bg-card` (the raised plane), one step above the content it sits over,\n * unlike `PageHeader` which shares the content's own `bg-background` plane.\n * Because content scrolls *under* it, the surface is translucent + blurred\n * so the motion beneath stays legible as depth — the opaque `bg-card` is\n * declared first and stays the fallback wherever `backdrop-filter` is\n * unsupported, so the bar is never a see-through smear.\n *\n * Widths step rather than hold one value: gutters open up from `sm` and\n * again on wide desktops (`3xl`, 1920px), where a 16px gutter beside a\n * 1920px canvas reads as an accident.\n *\n * Deliberately neutral: this is shell chrome shared by every user and every\n * action alike, so it never wears `--primary`/`--accent` — the bar stays\n * uncommitted until a specific action is happening on the surface below.\n */\ndefineProps<{\n /** Accessible name for the `<header>` landmark, for a page with more than one header-like region. */\n ariaLabel?: string;\n}>();\n</script>\n\n<template>\n <header\n :aria-label=\"ariaLabel\"\n class=\"sticky top-0 z-30 flex min-h-14 flex-wrap items-center gap-x-2 gap-y-2 border-b border-border bg-card px-3 py-2 text-card-foreground backdrop-blur-md supports-[backdrop-filter]:bg-card/80 sm:h-14 sm:flex-nowrap sm:gap-x-3 sm:px-4 sm:py-0 lg:px-6 3xl:h-16 3xl:px-8\"\n >\n <div v-if=\"$slots.brand\" class=\"flex shrink-0 items-center gap-2\">\n <!-- @slot The product mark and name, leftmost. -->\n <slot name=\"brand\" />\n </div>\n\n <!-- Own full-width row below `sm` (see the doc header on `order-last`);\n from `sm` up it rejoins the row and takes a cap so it never stretches\n into a banner on a wide canvas. -->\n <div\n v-if=\"$slots.search\"\n class=\"order-last min-w-0 basis-full sm:order-none sm:max-w-sm sm:flex-1 sm:basis-auto lg:max-w-md\"\n >\n <!-- @slot The app's global search field. Exactly one control — a filter belongs to `PageHeader` or the content area, not here. -->\n <slot name=\"search\" />\n </div>\n\n <div\n v-if=\"$slots.leading || $slots.notifications || $slots.userMenu\"\n class=\"ml-auto flex shrink-0 items-center gap-1 sm:gap-2\"\n >\n <!-- @slot A leading control in the trailing cluster — workspace switcher, org selector, breadcrumb, etc. -->\n <slot name=\"leading\" />\n <!-- @slot The notifications trigger, between the leading control and the account menu. -->\n <slot name=\"notifications\" />\n <!-- @slot The account menu, trailing the cluster. -->\n <slot name=\"userMenu\" />\n </div>\n </header>\n</template>\n"],"mappings":""}
@@ -9,7 +9,7 @@
9
9
  * controls). This bar is browser content, not window furniture.
10
10
  *
11
11
  * Layout is three regions, so callers never hand-tune widths: brand (left) ·
12
- * optional search · a trailing cluster for org-switcher, notifications, and
12
+ * optional search · a trailing cluster for a leading control, notifications, and
13
13
  * the user menu, pushed right by `ml-auto`. Every region is a named slot —
14
14
  * this block owns the strip's geometry and elevation, never its content or
15
15
  * behavior.
@@ -21,7 +21,7 @@
21
21
  * keeps the cluster flush right even when no search is slotted at all.
22
22
  *
23
23
  * **Below `sm` the bar is two rows, and that is the point of this block's
24
- * responsive behavior.** A brand, a real search field, and an org-switcher +
24
+ * responsive behavior.** A brand, a real search field, and a leading control +
25
25
  * notifications + account cluster do not fit across a 390px viewport: on
26
26
  * that width the search field is left about 60px and renders as a magnifier
27
27
  * glyph pressed against the org name — a control that is technically present
@@ -51,9 +51,8 @@
51
51
  * 1920px canvas reads as an accident.
52
52
  *
53
53
  * Deliberately neutral: this is shell chrome shared by every user and every
54
- * agent action alike, so it never wears `--primary`/`--agent` — the
55
- * dual-force law only paints a surface once a specific force is doing
56
- * something on it.
54
+ * action alike, so it never wears `--primary`/`--accent` — the bar stays
55
+ * uncommitted until a specific action is happening on the surface below.
57
56
  */
58
57
  type __VLS_Props = {
59
58
  /** Accessible name for the `<header>` landmark, for a page with more than one header-like region. */
@@ -65,7 +64,7 @@ type __VLS_Slots = {} & {
65
64
  } & {
66
65
  search?: (props: typeof __VLS_3) => any;
67
66
  } & {
68
- orgSwitcher?: (props: typeof __VLS_5) => any;
67
+ leading?: (props: typeof __VLS_5) => any;
69
68
  } & {
70
69
  notifications?: (props: typeof __VLS_7) => any;
71
70
  } & {
@@ -1 +1 @@
1
- {"version":3,"file":"AppHeader.vue.d.ts","sourceRoot":"","sources":["../../../src/blocks/AppHeader/AppHeader.vue"],"names":[],"mappings":"AAqGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,KAAK,WAAW,GAAG;IACjB,qGAAqG;IACrG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAyFF,QAAA,IAAI,OAAO,IAAU,EAAE,OAAO,IAAU,EAAE,OAAO,IAAU,EAAE,OAAO,IAAU,EAAE,OAAO,IAAW,CAAE;AACpG,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC1C;IAAE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC3C;IAAE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAChD;IAAE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AAKhD,QAAA,MAAM,UAAU,kSAEd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"AppHeader.vue.d.ts","sourceRoot":"","sources":["../../../src/blocks/AppHeader/AppHeader.vue"],"names":[],"mappings":"AAoGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,KAAK,WAAW,GAAG;IACjB,qGAAqG;IACrG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAyFF,QAAA,IAAI,OAAO,IAAU,EAAE,OAAO,IAAU,EAAE,OAAO,IAAU,EAAE,OAAO,IAAU,EAAE,OAAO,IAAW,CAAE;AACpG,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC1C;IAAE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC3C;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAC5C;IAAE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AAKhD,QAAA,MAAM,UAAU,kSAEd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
@@ -28,7 +28,7 @@ var AppHeader_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
28
28
  * controls). This bar is browser content, not window furniture.
29
29
  *
30
30
  * Layout is three regions, so callers never hand-tune widths: brand (left) ·
31
- * optional search · a trailing cluster for org-switcher, notifications, and
31
+ * optional search · a trailing cluster for a leading control, notifications, and
32
32
  * the user menu, pushed right by `ml-auto`. Every region is a named slot —
33
33
  * this block owns the strip's geometry and elevation, never its content or
34
34
  * behavior.
@@ -40,7 +40,7 @@ var AppHeader_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
40
40
  * keeps the cluster flush right even when no search is slotted at all.
41
41
  *
42
42
  * **Below `sm` the bar is two rows, and that is the point of this block's
43
- * responsive behavior.** A brand, a real search field, and an org-switcher +
43
+ * responsive behavior.** A brand, a real search field, and a leading control +
44
44
  * notifications + account cluster do not fit across a 390px viewport: on
45
45
  * that width the search field is left about 60px and renders as a magnifier
46
46
  * glyph pressed against the org name — a control that is technically present
@@ -70,9 +70,8 @@ var AppHeader_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
70
70
  * 1920px canvas reads as an accident.
71
71
  *
72
72
  * Deliberately neutral: this is shell chrome shared by every user and every
73
- * agent action alike, so it never wears `--primary`/`--agent` — the
74
- * dual-force law only paints a surface once a specific force is doing
75
- * something on it.
73
+ * action alike, so it never wears `--primary`/`--accent` — the bar stays
74
+ * uncommitted until a specific action is happening on the surface below.
76
75
  */
77
76
  return (_ctx, _cache) => {
78
77
  return openBlock(), createElementBlock("header", {
@@ -81,8 +80,8 @@ var AppHeader_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
81
80
  }, [
82
81
  _ctx.$slots.brand ? (openBlock(), createElementBlock("div", _hoisted_2, [renderSlot(_ctx.$slots, "brand")])) : createCommentVNode("", true),
83
82
  _ctx.$slots.search ? (openBlock(), createElementBlock("div", _hoisted_3, [renderSlot(_ctx.$slots, "search")])) : createCommentVNode("", true),
84
- _ctx.$slots.orgSwitcher || _ctx.$slots.notifications || _ctx.$slots.userMenu ? (openBlock(), createElementBlock("div", _hoisted_4, [
85
- renderSlot(_ctx.$slots, "orgSwitcher"),
83
+ _ctx.$slots.leading || _ctx.$slots.notifications || _ctx.$slots.userMenu ? (openBlock(), createElementBlock("div", _hoisted_4, [
84
+ renderSlot(_ctx.$slots, "leading"),
86
85
  renderSlot(_ctx.$slots, "notifications"),
87
86
  renderSlot(_ctx.$slots, "userMenu")
88
87
  ])) : createCommentVNode("", true)
@@ -1 +1 @@
1
- {"version":3,"file":"AppHeader.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/blocks/AppHeader/AppHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * AppHeader — the web app's TOP BAR: the shell-level strip that stays on\n * screen above every surface, distinct from two components it is easy to\n * confuse with:\n *\n * - **`PageHeader`** — a surface's own pinned title band, sitting *inside*\n * the content area this bar sits above.\n * - **`TitleBar`** — the desktop window's native chrome (drag region, window\n * controls). This bar is browser content, not window furniture.\n *\n * Layout is three regions, so callers never hand-tune widths: brand (left) ·\n * optional search · a trailing cluster for org-switcher, notifications, and\n * the user menu, pushed right by `ml-auto`. Every region is a named slot —\n * this block owns the strip's geometry and elevation, never its content or\n * behavior.\n *\n * The trailing cluster is pushed right by its own `ml-auto`, not by a spacer\n * element. A spacer works, but it is a second `flex-1` beside the search\n * field, so the two end up splitting the free space instead of the field\n * taking what is actually left; `ml-auto` costs no element and no width, and\n * keeps the cluster flush right even when no search is slotted at all.\n *\n * **Below `sm` the bar is two rows, and that is the point of this block's\n * responsive behavior.** A brand, a real search field, and an org-switcher +\n * notifications + account cluster do not fit across a 390px viewport: on\n * that width the search field is left about 60px and renders as a magnifier\n * glyph pressed against the org name — a control that is technically present\n * and practically unusable. So the search takes a full-width second row\n * (`basis-full` + `order-last`), the header height goes from fixed to\n * `min-h-14`, and from `sm` up it snaps back to the single `flex-nowrap` row.\n * Wrapping rather than hiding is deliberate: the host slotted a search\n * because its users need one, and a block does not get to decide they need\n * it less on a phone.\n *\n * The `order-last` is the one thing to keep in mind if this changes: it\n * moves the search visually below the cluster while leaving it before the\n * cluster in the DOM, so on a phone the tab order reaches search first. That\n * is the better of the two mismatches — search is the more-used control —\n * but it is a mismatch, so do not extend `order-*` to the other regions.\n *\n * **Pinned, and separated by a hairline — never a shadow.** It sits on\n * `bg-card` (the raised plane), one step above the content it sits over,\n * unlike `PageHeader` which shares the content's own `bg-background` plane.\n * Because content scrolls *under* it, the surface is translucent + blurred\n * so the motion beneath stays legible as depth — the opaque `bg-card` is\n * declared first and stays the fallback wherever `backdrop-filter` is\n * unsupported, so the bar is never a see-through smear.\n *\n * Widths step rather than hold one value: gutters open up from `sm` and\n * again on wide desktops (`3xl`, 1920px), where a 16px gutter beside a\n * 1920px canvas reads as an accident.\n *\n * Deliberately neutral: this is shell chrome shared by every user and every\n * agent action alike, so it never wears `--primary`/`--agent` — the\n * dual-force law only paints a surface once a specific force is doing\n * something on it.\n */\ndefineProps<{\n /** Accessible name for the `<header>` landmark, for a page with more than one header-like region. */\n ariaLabel?: string;\n}>();\n</script>\n\n<template>\n <header\n :aria-label=\"ariaLabel\"\n class=\"sticky top-0 z-30 flex min-h-14 flex-wrap items-center gap-x-2 gap-y-2 border-b border-border bg-card px-3 py-2 text-card-foreground backdrop-blur-md supports-[backdrop-filter]:bg-card/80 sm:h-14 sm:flex-nowrap sm:gap-x-3 sm:px-4 sm:py-0 lg:px-6 3xl:h-16 3xl:px-8\"\n >\n <div v-if=\"$slots.brand\" class=\"flex shrink-0 items-center gap-2\">\n <!-- @slot The product mark and name, leftmost. -->\n <slot name=\"brand\" />\n </div>\n\n <!-- Own full-width row below `sm` (see the doc header on `order-last`);\n from `sm` up it rejoins the row and takes a cap so it never stretches\n into a banner on a wide canvas. -->\n <div\n v-if=\"$slots.search\"\n class=\"order-last min-w-0 basis-full sm:order-none sm:max-w-sm sm:flex-1 sm:basis-auto lg:max-w-md\"\n >\n <!-- @slot The app's global search field. Exactly one control — a filter belongs to `PageHeader` or the content area, not here. -->\n <slot name=\"search\" />\n </div>\n\n <div\n v-if=\"$slots.orgSwitcher || $slots.notifications || $slots.userMenu\"\n class=\"ml-auto flex shrink-0 items-center gap-1 sm:gap-2\"\n >\n <!-- @slot The organization switcher, leading the trailing cluster. -->\n <slot name=\"orgSwitcher\" />\n <!-- @slot The notifications trigger, between the org switcher and the account menu. -->\n <slot name=\"notifications\" />\n <!-- @slot The account menu, trailing the cluster. -->\n <slot name=\"userMenu\" />\n </div>\n </header>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEE,OAAA,UAAA,GAAA,mBA+BS,UAAA;IA9BN,cAAY,QAAA;IACb,OAAM;;IAEKA,KAAAA,OAAO,SAAlB,UAAA,GAAA,mBAGM,OAHN,YAGM,CADJ,WAAqB,KAAA,QAAA,OAAA,CAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;IAOfA,KAAAA,OAAO,UADf,UAAA,GAAA,mBAMM,OANN,YAMM,CADJ,WAAsB,KAAA,QAAA,QAAA,CAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;IAIhBA,KAAAA,OAAO,eAAeA,KAAAA,OAAO,iBAAiBA,KAAAA,OAAO,YAD7D,UAAA,GAAA,mBAUM,OAVN,YAUM;KALJ,WAA2B,KAAA,QAAA,aAAA;KAE3B,WAA6B,KAAA,QAAA,eAAA;KAE7B,WAAwB,KAAA,QAAA,UAAA"}
1
+ {"version":3,"file":"AppHeader.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/blocks/AppHeader/AppHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * AppHeader — the web app's TOP BAR: the shell-level strip that stays on\n * screen above every surface, distinct from two components it is easy to\n * confuse with:\n *\n * - **`PageHeader`** — a surface's own pinned title band, sitting *inside*\n * the content area this bar sits above.\n * - **`TitleBar`** — the desktop window's native chrome (drag region, window\n * controls). This bar is browser content, not window furniture.\n *\n * Layout is three regions, so callers never hand-tune widths: brand (left) ·\n * optional search · a trailing cluster for a leading control, notifications, and\n * the user menu, pushed right by `ml-auto`. Every region is a named slot —\n * this block owns the strip's geometry and elevation, never its content or\n * behavior.\n *\n * The trailing cluster is pushed right by its own `ml-auto`, not by a spacer\n * element. A spacer works, but it is a second `flex-1` beside the search\n * field, so the two end up splitting the free space instead of the field\n * taking what is actually left; `ml-auto` costs no element and no width, and\n * keeps the cluster flush right even when no search is slotted at all.\n *\n * **Below `sm` the bar is two rows, and that is the point of this block's\n * responsive behavior.** A brand, a real search field, and a leading control +\n * notifications + account cluster do not fit across a 390px viewport: on\n * that width the search field is left about 60px and renders as a magnifier\n * glyph pressed against the org name — a control that is technically present\n * and practically unusable. So the search takes a full-width second row\n * (`basis-full` + `order-last`), the header height goes from fixed to\n * `min-h-14`, and from `sm` up it snaps back to the single `flex-nowrap` row.\n * Wrapping rather than hiding is deliberate: the host slotted a search\n * because its users need one, and a block does not get to decide they need\n * it less on a phone.\n *\n * The `order-last` is the one thing to keep in mind if this changes: it\n * moves the search visually below the cluster while leaving it before the\n * cluster in the DOM, so on a phone the tab order reaches search first. That\n * is the better of the two mismatches — search is the more-used control —\n * but it is a mismatch, so do not extend `order-*` to the other regions.\n *\n * **Pinned, and separated by a hairline — never a shadow.** It sits on\n * `bg-card` (the raised plane), one step above the content it sits over,\n * unlike `PageHeader` which shares the content's own `bg-background` plane.\n * Because content scrolls *under* it, the surface is translucent + blurred\n * so the motion beneath stays legible as depth — the opaque `bg-card` is\n * declared first and stays the fallback wherever `backdrop-filter` is\n * unsupported, so the bar is never a see-through smear.\n *\n * Widths step rather than hold one value: gutters open up from `sm` and\n * again on wide desktops (`3xl`, 1920px), where a 16px gutter beside a\n * 1920px canvas reads as an accident.\n *\n * Deliberately neutral: this is shell chrome shared by every user and every\n * action alike, so it never wears `--primary`/`--accent` — the bar stays\n * uncommitted until a specific action is happening on the surface below.\n */\ndefineProps<{\n /** Accessible name for the `<header>` landmark, for a page with more than one header-like region. */\n ariaLabel?: string;\n}>();\n</script>\n\n<template>\n <header\n :aria-label=\"ariaLabel\"\n class=\"sticky top-0 z-30 flex min-h-14 flex-wrap items-center gap-x-2 gap-y-2 border-b border-border bg-card px-3 py-2 text-card-foreground backdrop-blur-md supports-[backdrop-filter]:bg-card/80 sm:h-14 sm:flex-nowrap sm:gap-x-3 sm:px-4 sm:py-0 lg:px-6 3xl:h-16 3xl:px-8\"\n >\n <div v-if=\"$slots.brand\" class=\"flex shrink-0 items-center gap-2\">\n <!-- @slot The product mark and name, leftmost. -->\n <slot name=\"brand\" />\n </div>\n\n <!-- Own full-width row below `sm` (see the doc header on `order-last`);\n from `sm` up it rejoins the row and takes a cap so it never stretches\n into a banner on a wide canvas. -->\n <div\n v-if=\"$slots.search\"\n class=\"order-last min-w-0 basis-full sm:order-none sm:max-w-sm sm:flex-1 sm:basis-auto lg:max-w-md\"\n >\n <!-- @slot The app's global search field. Exactly one control — a filter belongs to `PageHeader` or the content area, not here. -->\n <slot name=\"search\" />\n </div>\n\n <div\n v-if=\"$slots.leading || $slots.notifications || $slots.userMenu\"\n class=\"ml-auto flex shrink-0 items-center gap-1 sm:gap-2\"\n >\n <!-- @slot A leading control in the trailing cluster — workspace switcher, org selector, breadcrumb, etc. -->\n <slot name=\"leading\" />\n <!-- @slot The notifications trigger, between the leading control and the account menu. -->\n <slot name=\"notifications\" />\n <!-- @slot The account menu, trailing the cluster. -->\n <slot name=\"userMenu\" />\n </div>\n </header>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEE,OAAA,UAAA,GAAA,mBA+BS,UAAA;IA9BN,cAAY,QAAA;IACb,OAAM;;IAEKA,KAAAA,OAAO,SAAlB,UAAA,GAAA,mBAGM,OAHN,YAGM,CADJ,WAAqB,KAAA,QAAA,OAAA,CAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;IAOfA,KAAAA,OAAO,UADf,UAAA,GAAA,mBAMM,OANN,YAMM,CADJ,WAAsB,KAAA,QAAA,QAAA,CAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;IAIhBA,KAAAA,OAAO,WAAWA,KAAAA,OAAO,iBAAiBA,KAAAA,OAAO,YADzD,UAAA,GAAA,mBAUM,OAVN,YAUM;KALJ,WAAuB,KAAA,QAAA,SAAA;KAEvB,WAA6B,KAAA,QAAA,eAAA;KAE7B,WAAwB,KAAA,QAAA,UAAA"}
@@ -28,8 +28,8 @@ type __VLS_Slots = {} & {
28
28
  default?: (props: typeof __VLS_1) => any;
29
29
  };
30
30
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
31
- minTileWidth: string;
32
31
  gap: "sm" | "md" | "lg";
32
+ minTileWidth: string;
33
33
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
34
34
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
35
35
  declare const _default: typeof __VLS_export;
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardGrid.vue.d.ts","sourceRoot":"","sources":["../../../src/blocks/DashboardGrid/DashboardGrid.vue"],"names":[],"mappings":"AAsDA;;;;;;;;;;;;;;;;;;GAkBG;AACH,KAAK,WAAW,GAAG;IACf,4GAA4G;IAC5G,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8IAA8I;IAC9I,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CAC1B,CAAC;AA4CJ,QAAA,IAAI,OAAO,IAAW,CAAE;AACxB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AAK/C,QAAA,MAAM,UAAU;kBAtDG,MAAM;SAEf,IAAI,GAAG,IAAI,GAAG,IAAI;6EAuD1B,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"DashboardGrid.vue.d.ts","sourceRoot":"","sources":["../../../src/blocks/DashboardGrid/DashboardGrid.vue"],"names":[],"mappings":"AAsDA;;;;;;;;;;;;;;;;;;GAkBG;AACH,KAAK,WAAW,GAAG;IACf,4GAA4G;IAC5G,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8IAA8I;IAC9I,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CAC1B,CAAC;AA4CJ,QAAA,IAAI,OAAO,IAAW,CAAE;AACxB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AAK/C,QAAA,MAAM,UAAU;SApDN,IAAI,GAAG,IAAI,GAAG,IAAI;kBAFT,MAAM;6EAyDvB,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import DesktopAppShell_vue_vue_type_script_setup_true_lang_default from "./DesktopAppShell.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/blocks/DesktopAppShell/DesktopAppShell.vue
3
+ var DesktopAppShell_default = DesktopAppShell_vue_vue_type_script_setup_true_lang_default;
4
+ //#endregion
5
+ export { DesktopAppShell_default as default };
6
+
7
+ //# sourceMappingURL=DesktopAppShell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DesktopAppShell.js","names":[],"sources":["../../../src/blocks/DesktopAppShell/DesktopAppShell.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * DesktopAppShell — the ready-made layout a desktop (Electron/Tauri) app\n * reaches for. It composes TitleBar, a sidebar, and a content area into a\n * single root so the host never hand-tunes the flex relationship between\n * window chrome and application body.\n *\n * The sidebar sits on the sunken plane (`bg-sunken`) and collapses below\n * tablet width, stacking above the content area instead of sitting beside it.\n * That mirrors SidebarNav's own intrinsic collapse: the nav drops to icon-only\n * at narrow widths, and the shell narrows its rail to match. Below tablet the\n * rail needs no width at all — the nav items stack vertically over the\n * content, which is the same thing a mobile user sees in any desktop app that\n * has a sidebar.\n *\n * Content sits on `bg-background` with gutters that step open at `sm` and\n * `3xl`, matching the same step scale AppHeader uses — a 16px gutter beside a\n * 1920px canvas reads as an accident.\n *\n * Every TitleBar event is re-emitted so the host wires its own window bridge;\n * the shell itself owns no IPC.\n */\nimport type { MenubarMenu } from \"../../primitives/Menubar/Menubar.vue\";\nimport type { WindowPlatform } from \"../../primitives/WindowControls/WindowControls.vue\";\n</script>\n\n<script setup lang=\"ts\">\nimport TitleBar from \"../TitleBar/TitleBar.vue\";\nimport { type WindowControlsLabels } from \"../../primitives/WindowControls/WindowControls.vue\";\nimport { optional } from \"../../lib/props\";\n\nwithDefaults(\n defineProps<{\n /** The host app's brand name — passed through to TitleBar, which has no identity of its own. */\n appName: string;\n /** Centered subtitle — usually the open project / composition. Passed through to TitleBar. */\n title?: string;\n /** Top-level menus for the TitleBar's Menubar. Omit for a menu-less app. */\n menus?: MenubarMenu[];\n /** Whether the window is maximized — controls the TitleBar's middle window-control glyph. */\n isMaximized?: boolean;\n /**\n * The desktop platform the window runs on. Passed through to TitleBar, which\n * adjusts layout for native traffic-lights on macOS. The host decides —\n * Loom never sniffs the OS at runtime.\n */\n platform?: WindowPlatform;\n /** Names for the window-control buttons, as any subset of `WindowControlsLabels`. */\n windowControlsLabels?: WindowControlsLabels;\n /** Sidebar rail width. Maps to 12/16/20 rem — the three widths SidebarNav's label/labelless\n * modes were measured against. */\n sidebarWidth?: \"sm\" | \"md\" | \"lg\";\n /** Accessible name for the sidebar's `<aside>` landmark. */\n sidebarAriaLabel?: string;\n }>(),\n {\n title: \"\",\n menus: () => [],\n isMaximized: false,\n platform: \"windows\",\n sidebarWidth: \"md\",\n sidebarAriaLabel: \"Sidebar\",\n },\n);\n\nconst emit = defineEmits<{\n (e: \"select\", command: string): void;\n (e: \"minimize\"): void;\n (e: \"maximize\"): void;\n (e: \"close\"): void;\n}>();\n\nconst SIDEBAR_WIDTH = {\n sm: \"12rem\",\n md: \"16rem\",\n lg: \"20rem\",\n} as const;\n</script>\n\n<template>\n <div class=\"flex h-dvh flex-col\">\n <TitleBar\n :app-name=\"appName\"\n :title=\"title\"\n :menus=\"menus\"\n :is-maximized=\"isMaximized\"\n :platform=\"platform\"\n v-bind=\"optional({ windowControlsLabels })\"\n @select=\"emit('select', $event)\"\n @minimize=\"emit('minimize')\"\n @maximize=\"emit('maximize')\"\n @close=\"emit('close')\"\n >\n <template v-if=\"$slots.brandIcon\" #brandIcon>\n <!-- @slot Brand icon — forwarded to TitleBar's own brandIcon slot. -->\n <slot name=\"brandIcon\" />\n </template>\n <template v-if=\"$slots.brandMark\" #brandMark>\n <!-- @slot Brand mark — forwarded to TitleBar's own brandMark slot. -->\n <slot name=\"brandMark\" />\n </template>\n </TitleBar>\n\n <div class=\"flex min-h-0 flex-1 flex-col md:flex-row\">\n <aside\n :aria-label=\"sidebarAriaLabel\"\n class=\"shrink-1 bg-sunken md:shrink-0 md:grow-0\"\n :style=\"{ flexBasis: SIDEBAR_WIDTH[sidebarWidth] }\"\n >\n <!-- @slot Sidebar navigation content — typically SidebarNav. Sits on the sunken plane. -->\n <slot name=\"sidebar\" />\n </aside>\n\n <main class=\"min-w-1/2 grow-[999] overflow-y-auto bg-background px-4 sm:px-6 3xl:px-8\">\n <!-- @slot Main content area. Sits on the background plane with stepped gutters. -->\n <slot />\n </main>\n </div>\n </div>\n</template>\n"],"mappings":""}
@@ -0,0 +1,102 @@
1
+ import { type WindowControlsLabels } from "../../primitives/WindowControls/WindowControls.vue";
2
+ /**
3
+ * DesktopAppShell — the ready-made layout a desktop (Electron/Tauri) app
4
+ * reaches for. It composes TitleBar, a sidebar, and a content area into a
5
+ * single root so the host never hand-tunes the flex relationship between
6
+ * window chrome and application body.
7
+ *
8
+ * The sidebar sits on the sunken plane (`bg-sunken`) and collapses below
9
+ * tablet width, stacking above the content area instead of sitting beside it.
10
+ * That mirrors SidebarNav's own intrinsic collapse: the nav drops to icon-only
11
+ * at narrow widths, and the shell narrows its rail to match. Below tablet the
12
+ * rail needs no width at all — the nav items stack vertically over the
13
+ * content, which is the same thing a mobile user sees in any desktop app that
14
+ * has a sidebar.
15
+ *
16
+ * Content sits on `bg-background` with gutters that step open at `sm` and
17
+ * `3xl`, matching the same step scale AppHeader uses — a 16px gutter beside a
18
+ * 1920px canvas reads as an accident.
19
+ *
20
+ * Every TitleBar event is re-emitted so the host wires its own window bridge;
21
+ * the shell itself owns no IPC.
22
+ */
23
+ import type { MenubarMenu } from "../../primitives/Menubar/Menubar.vue";
24
+ import type { WindowPlatform } from "../../primitives/WindowControls/WindowControls.vue";
25
+ declare const _default: typeof __VLS_export;
26
+ export default _default;
27
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
28
+ /** The host app's brand name — passed through to TitleBar, which has no identity of its own. */
29
+ appName: string;
30
+ /** Centered subtitle — usually the open project / composition. Passed through to TitleBar. */
31
+ title?: string;
32
+ /** Top-level menus for the TitleBar's Menubar. Omit for a menu-less app. */
33
+ menus?: MenubarMenu[];
34
+ /** Whether the window is maximized — controls the TitleBar's middle window-control glyph. */
35
+ isMaximized?: boolean;
36
+ /**
37
+ * The desktop platform the window runs on. Passed through to TitleBar, which
38
+ * adjusts layout for native traffic-lights on macOS. The host decides —
39
+ * Loom never sniffs the OS at runtime.
40
+ */
41
+ platform?: WindowPlatform;
42
+ /** Names for the window-control buttons, as any subset of `WindowControlsLabels`. */
43
+ windowControlsLabels?: WindowControlsLabels;
44
+ /** Sidebar rail width. Maps to 12/16/20 rem — the three widths SidebarNav's label/labelless
45
+ * modes were measured against. */
46
+ sidebarWidth?: "sm" | "md" | "lg";
47
+ /** Accessible name for the sidebar's `<aside>` landmark. */
48
+ sidebarAriaLabel?: string;
49
+ }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
50
+ select: (command: string) => any;
51
+ close: () => any;
52
+ minimize: () => any;
53
+ maximize: () => any;
54
+ }, string, import("vue").PublicProps, Readonly<{
55
+ /** The host app's brand name — passed through to TitleBar, which has no identity of its own. */
56
+ appName: string;
57
+ /** Centered subtitle — usually the open project / composition. Passed through to TitleBar. */
58
+ title?: string;
59
+ /** Top-level menus for the TitleBar's Menubar. Omit for a menu-less app. */
60
+ menus?: MenubarMenu[];
61
+ /** Whether the window is maximized — controls the TitleBar's middle window-control glyph. */
62
+ isMaximized?: boolean;
63
+ /**
64
+ * The desktop platform the window runs on. Passed through to TitleBar, which
65
+ * adjusts layout for native traffic-lights on macOS. The host decides —
66
+ * Loom never sniffs the OS at runtime.
67
+ */
68
+ platform?: WindowPlatform;
69
+ /** Names for the window-control buttons, as any subset of `WindowControlsLabels`. */
70
+ windowControlsLabels?: WindowControlsLabels;
71
+ /** Sidebar rail width. Maps to 12/16/20 rem — the three widths SidebarNav's label/labelless
72
+ * modes were measured against. */
73
+ sidebarWidth?: "sm" | "md" | "lg";
74
+ /** Accessible name for the sidebar's `<aside>` landmark. */
75
+ sidebarAriaLabel?: string;
76
+ }> & Readonly<{
77
+ onSelect?: (command: string) => any;
78
+ onClose?: () => any;
79
+ onMinimize?: () => any;
80
+ onMaximize?: () => any;
81
+ }>, {
82
+ title: string;
83
+ platform: WindowPlatform;
84
+ isMaximized: boolean;
85
+ menus: MenubarMenu[];
86
+ sidebarWidth: "sm" | "md" | "lg";
87
+ sidebarAriaLabel: string;
88
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
89
+ brandIcon?: (props: {}) => any;
90
+ } & {
91
+ brandMark?: (props: {}) => any;
92
+ } & {
93
+ sidebar?: (props: {}) => any;
94
+ } & {
95
+ default?: (props: {}) => any;
96
+ }>;
97
+ type __VLS_WithSlots<T, S> = T & {
98
+ new (): {
99
+ $slots: S;
100
+ };
101
+ };
102
+ //# sourceMappingURL=DesktopAppShell.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DesktopAppShell.vue.d.ts","sourceRoot":"","sources":["../../../src/blocks/DesktopAppShell/DesktopAppShell.vue"],"names":[],"mappings":"AA4HA,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,oDAAoD,CAAC;AAI/F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oDAAoD,CAAC;wBACpE,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAEd,gGAAgG;aACvF,MAAM;IACf,8FAA8F;YACtF,MAAM;IACd,4EAA4E;YACpE,WAAW,EAAE;IACrB,6FAA6F;kBAC/E,OAAO;IACrB;;;;OAIG;eACQ,cAAc;IACzB,qFAAqF;2BAC9D,oBAAoB;IAC3C;uCACmC;mBACpB,IAAI,GAAG,IAAI,GAAG,IAAI;IACjC,4DAA4D;uBACzC,MAAM;;;;;;;IApBzB,gGAAgG;aACvF,MAAM;IACf,8FAA8F;YACtF,MAAM;IACd,4EAA4E;YACpE,WAAW,EAAE;IACrB,6FAA6F;kBAC/E,OAAO;IACrB;;;;OAIG;eACQ,cAAc;IACzB,qFAAqF;2BAC9D,oBAAoB;IAC3C;uCACmC;mBACpB,IAAI,GAAG,IAAI,GAAG,IAAI;IACjC,4DAA4D;uBACzC,MAAM;;;;;;;WAjBjB,MAAM;cAUH,cAAc;iBANX,OAAO;WAFb,WAAW,EAAE;kBAaN,IAAI,GAAG,IAAI,GAAG,IAAI;sBAEd,MAAM;;gBAmLb,CAAC,KAAK,IAAiB,KAAK,GAAG;;gBAC/B,CAAC,KAAK,IAAiB,KAAK,GAAG;;cACjC,CAAC,KAAK,IAAiB,KAAK,GAAG;;cAC/B,CAAC,KAAK,IAAiB,KAAK,GAAG;EAWzC,CAAC;AAWL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { optional } from "../../lib/props.js";
2
+ import TitleBar_default from "../TitleBar/TitleBar.js";
3
+ import { createElementBlock, createElementVNode, createSlots, createVNode, defineComponent, mergeProps, normalizeStyle, openBlock, renderSlot, unref, withCtx } from "vue";
4
+ //#region src/blocks/DesktopAppShell/DesktopAppShell.vue?vue&type=script&setup=true&lang.ts
5
+ var _hoisted_1 = { class: "flex h-dvh flex-col" };
6
+ var _hoisted_2 = { class: "flex min-h-0 flex-1 flex-col md:flex-row" };
7
+ var _hoisted_3 = ["aria-label"];
8
+ var _hoisted_4 = { class: "min-w-1/2 grow-[999] overflow-y-auto bg-background px-4 sm:px-6 3xl:px-8" };
9
+ var DesktopAppShell_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
10
+ __name: "DesktopAppShell",
11
+ props: {
12
+ appName: {},
13
+ title: { default: "" },
14
+ menus: { default: () => [] },
15
+ isMaximized: {
16
+ type: Boolean,
17
+ default: false
18
+ },
19
+ platform: { default: "windows" },
20
+ windowControlsLabels: {},
21
+ sidebarWidth: { default: "md" },
22
+ sidebarAriaLabel: { default: "Sidebar" }
23
+ },
24
+ emits: [
25
+ "select",
26
+ "minimize",
27
+ "maximize",
28
+ "close"
29
+ ],
30
+ setup(__props, { emit: __emit }) {
31
+ const emit = __emit;
32
+ const SIDEBAR_WIDTH = {
33
+ sm: "12rem",
34
+ md: "16rem",
35
+ lg: "20rem"
36
+ };
37
+ return (_ctx, _cache) => {
38
+ return openBlock(), createElementBlock("div", _hoisted_1, [createVNode(TitleBar_default, mergeProps({
39
+ "app-name": __props.appName,
40
+ title: __props.title,
41
+ menus: __props.menus,
42
+ "is-maximized": __props.isMaximized,
43
+ platform: __props.platform
44
+ }, unref(optional)({ windowControlsLabels: __props.windowControlsLabels }), {
45
+ onSelect: _cache[0] || (_cache[0] = ($event) => emit("select", $event)),
46
+ onMinimize: _cache[1] || (_cache[1] = ($event) => emit("minimize")),
47
+ onMaximize: _cache[2] || (_cache[2] = ($event) => emit("maximize")),
48
+ onClose: _cache[3] || (_cache[3] = ($event) => emit("close"))
49
+ }), createSlots({ _: 2 }, [_ctx.$slots.brandIcon ? {
50
+ name: "brandIcon",
51
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "brandIcon")]),
52
+ key: "0"
53
+ } : void 0, _ctx.$slots.brandMark ? {
54
+ name: "brandMark",
55
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "brandMark")]),
56
+ key: "1"
57
+ } : void 0]), 1040, [
58
+ "app-name",
59
+ "title",
60
+ "menus",
61
+ "is-maximized",
62
+ "platform"
63
+ ]), createElementVNode("div", _hoisted_2, [createElementVNode("aside", {
64
+ "aria-label": __props.sidebarAriaLabel,
65
+ class: "shrink-1 bg-sunken md:shrink-0 md:grow-0",
66
+ style: normalizeStyle({ flexBasis: SIDEBAR_WIDTH[__props.sidebarWidth] })
67
+ }, [renderSlot(_ctx.$slots, "sidebar")], 12, _hoisted_3), createElementVNode("main", _hoisted_4, [renderSlot(_ctx.$slots, "default")])])]);
68
+ };
69
+ }
70
+ });
71
+ //#endregion
72
+ export { DesktopAppShell_vue_vue_type_script_setup_true_lang_default as default };
73
+
74
+ //# sourceMappingURL=DesktopAppShell.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DesktopAppShell.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/blocks/DesktopAppShell/DesktopAppShell.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * DesktopAppShell — the ready-made layout a desktop (Electron/Tauri) app\n * reaches for. It composes TitleBar, a sidebar, and a content area into a\n * single root so the host never hand-tunes the flex relationship between\n * window chrome and application body.\n *\n * The sidebar sits on the sunken plane (`bg-sunken`) and collapses below\n * tablet width, stacking above the content area instead of sitting beside it.\n * That mirrors SidebarNav's own intrinsic collapse: the nav drops to icon-only\n * at narrow widths, and the shell narrows its rail to match. Below tablet the\n * rail needs no width at all — the nav items stack vertically over the\n * content, which is the same thing a mobile user sees in any desktop app that\n * has a sidebar.\n *\n * Content sits on `bg-background` with gutters that step open at `sm` and\n * `3xl`, matching the same step scale AppHeader uses — a 16px gutter beside a\n * 1920px canvas reads as an accident.\n *\n * Every TitleBar event is re-emitted so the host wires its own window bridge;\n * the shell itself owns no IPC.\n */\nimport type { MenubarMenu } from \"../../primitives/Menubar/Menubar.vue\";\nimport type { WindowPlatform } from \"../../primitives/WindowControls/WindowControls.vue\";\n</script>\n\n<script setup lang=\"ts\">\nimport TitleBar from \"../TitleBar/TitleBar.vue\";\nimport { type WindowControlsLabels } from \"../../primitives/WindowControls/WindowControls.vue\";\nimport { optional } from \"../../lib/props\";\n\nwithDefaults(\n defineProps<{\n /** The host app's brand name — passed through to TitleBar, which has no identity of its own. */\n appName: string;\n /** Centered subtitle — usually the open project / composition. Passed through to TitleBar. */\n title?: string;\n /** Top-level menus for the TitleBar's Menubar. Omit for a menu-less app. */\n menus?: MenubarMenu[];\n /** Whether the window is maximized — controls the TitleBar's middle window-control glyph. */\n isMaximized?: boolean;\n /**\n * The desktop platform the window runs on. Passed through to TitleBar, which\n * adjusts layout for native traffic-lights on macOS. The host decides —\n * Loom never sniffs the OS at runtime.\n */\n platform?: WindowPlatform;\n /** Names for the window-control buttons, as any subset of `WindowControlsLabels`. */\n windowControlsLabels?: WindowControlsLabels;\n /** Sidebar rail width. Maps to 12/16/20 rem — the three widths SidebarNav's label/labelless\n * modes were measured against. */\n sidebarWidth?: \"sm\" | \"md\" | \"lg\";\n /** Accessible name for the sidebar's `<aside>` landmark. */\n sidebarAriaLabel?: string;\n }>(),\n {\n title: \"\",\n menus: () => [],\n isMaximized: false,\n platform: \"windows\",\n sidebarWidth: \"md\",\n sidebarAriaLabel: \"Sidebar\",\n },\n);\n\nconst emit = defineEmits<{\n (e: \"select\", command: string): void;\n (e: \"minimize\"): void;\n (e: \"maximize\"): void;\n (e: \"close\"): void;\n}>();\n\nconst SIDEBAR_WIDTH = {\n sm: \"12rem\",\n md: \"16rem\",\n lg: \"20rem\",\n} as const;\n</script>\n\n<template>\n <div class=\"flex h-dvh flex-col\">\n <TitleBar\n :app-name=\"appName\"\n :title=\"title\"\n :menus=\"menus\"\n :is-maximized=\"isMaximized\"\n :platform=\"platform\"\n v-bind=\"optional({ windowControlsLabels })\"\n @select=\"emit('select', $event)\"\n @minimize=\"emit('minimize')\"\n @maximize=\"emit('maximize')\"\n @close=\"emit('close')\"\n >\n <template v-if=\"$slots.brandIcon\" #brandIcon>\n <!-- @slot Brand icon — forwarded to TitleBar's own brandIcon slot. -->\n <slot name=\"brandIcon\" />\n </template>\n <template v-if=\"$slots.brandMark\" #brandMark>\n <!-- @slot Brand mark — forwarded to TitleBar's own brandMark slot. -->\n <slot name=\"brandMark\" />\n </template>\n </TitleBar>\n\n <div class=\"flex min-h-0 flex-1 flex-col md:flex-row\">\n <aside\n :aria-label=\"sidebarAriaLabel\"\n class=\"shrink-1 bg-sunken md:shrink-0 md:grow-0\"\n :style=\"{ flexBasis: SIDEBAR_WIDTH[sidebarWidth] }\"\n >\n <!-- @slot Sidebar navigation content — typically SidebarNav. Sits on the sunken plane. -->\n <slot name=\"sidebar\" />\n </aside>\n\n <main class=\"min-w-1/2 grow-[999] overflow-y-auto bg-background px-4 sm:px-6 3xl:px-8\">\n <!-- @slot Main content area. Sits on the background plane with stepped gutters. -->\n <slot />\n </main>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiEA,MAAM,OAAO;EAOb,MAAM,gBAAgB;GACpB,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;;GAIE,OAAA,UAAA,GAAA,mBAsCM,OAtCN,YAsCM,CArCJ,YAoBW,kBApBX,WAoBW;IAnBR,YAAU,QAAA;IACV,OAAO,QAAA;IACP,OAAO,QAAA;IACP,gBAAc,QAAA;IACd,UAAU,QAAA;GACH,GAAA,MAAA,QAAA,CAAQ,CAAA,EAAA,sBAAG,QAAA,qBAAoB,CAAA,GAAA;IACtC,UAAM,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,UAAW,MAAM;IAC7B,YAAQ,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,UAAA;IACd,YAAQ,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,UAAA;IACd,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,OAAA;GAEIA,CAAAA,GAAAA,YAAAA,EAAAA,GAAAA,EAAAA,GAAAA,CAAAA,KAAAA,OAAO,YAAA;IAAY,MAAA;IAEjC,IAAA,cAAyB,CAAzB,WAAyB,KAAA,QAAA,WAAA,CAAA,CAAA;;GAEXA,IAAAA,KAAAA,GAAAA,KAAAA,OAAO,YAAA;IAAY,MAAA;IAEjC,IAAA,cAAyB,CAAzB,WAAyB,KAAA,QAAA,WAAA,CAAA,CAAA;;;;;;;;GAI7B,CAAA,GAAA,mBAcM,OAdN,YAcM,CAbJ,mBAOQ,SAAA;IANL,cAAY,QAAA;IACb,OAAM;IACL,OAAK,eAAA,EAAA,WAAe,cAAc,QAAA,cAAY,CAAA;GAG/C,GAAA,CAAA,WAAuB,KAAA,QAAA,SAAA,CAAA,GAAA,IAAA,UAAA,GAGzB,mBAGO,QAHP,YAGO,CADL,WAAQ,KAAA,QAAA,SAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA"}
@@ -0,0 +1,7 @@
1
+ import ErrorState_vue_vue_type_script_setup_true_lang_default from "./ErrorState.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/blocks/ErrorState/ErrorState.vue
3
+ var ErrorState_default = ErrorState_vue_vue_type_script_setup_true_lang_default;
4
+ //#endregion
5
+ export { ErrorState_default as default };
6
+
7
+ //# sourceMappingURL=ErrorState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorState.js","names":[],"sources":["../../../src/blocks/ErrorState/ErrorState.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * ErrorState — the shape of \"something went wrong\": icon → title → optional\n * description → optional retry action, centered in the error region. This is\n * EmptyState's mirror: where that block says \"nothing here yet\" and invites\n * the next step, this one says \"something broke\" and offers a retry.\n *\n * No staggered entrance. EmptyState is content appearing — a welcome, budgeted\n * like a panel reveal. An error is not content; it is a problem that needs\n * attention now, and a fade-rise film that delays the message reads as\n * indifference. Everything renders at once.\n *\n * The icon sits in a hairline medallion — the same shape as EmptyState's, but\n * tinted `bg-destructive/10` with a `border-destructive/30` ring — because a\n * bare glyph in a region that already signals alarm has no anchor and the\n * colour alone does the work that EmptyState's neutral medallion needed\n * `bg-subtle` for. The icon is decorative and `aria-hidden`; the title already\n * carries the meaning.\n *\n * The action slot is semantically a retry affordance but remains a generic\n * slot — the host owns the wording and behaviour, and no fallback copy ships\n * with the component.\n */\ndefineProps<{\n /** What went wrong, stated plainly — always shown. */\n title: string;\n /** More context about the error. Omit rather than pad the region with filler copy. */\n description?: string;\n}>();\n</script>\n\n<template>\n <div class=\"flex flex-col items-center justify-center gap-1.5 px-6 py-10 text-center sm:py-14\">\n <div\n v-if=\"$slots.icon\"\n aria-hidden=\"true\"\n class=\"grid h-12 w-12 place-items-center rounded-full border border-destructive/30 bg-destructive/10 text-destructive [&_svg]:h-5 [&_svg]:w-5\"\n >\n <slot name=\"icon\" />\n </div>\n <p class=\"text-title text-foreground\">\n {{ title }}\n </p>\n <p v-if=\"description\" class=\"max-w-sm text-balance text-small text-muted-foreground\">\n {{ description }}\n </p>\n <div v-if=\"$slots.action\" class=\"mt-4\">\n <slot name=\"action\" />\n </div>\n </div>\n</template>\n"],"mappings":""}