@threadlabs/looma 0.32.1 → 0.33.1

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 (366) hide show
  1. package/README.md +15 -0
  2. package/bin/looma-docs.mjs +3 -0
  3. package/components/shared/icons.js +1 -0
  4. package/components/shared/overlay.js +1 -1
  5. package/components/ui-action-bar/ui-action-bar.html +11 -11
  6. package/components/ui-affordance-scope/ui-affordance-scope.html +2 -2
  7. package/components/ui-avatar/ui-avatar.html +8 -8
  8. package/components/ui-avatar-group/ui-avatar-group.html +14 -14
  9. package/components/ui-avatar-group/ui-avatar-group.js +3 -2
  10. package/components/ui-badge/ui-badge.html +43 -43
  11. package/components/ui-breadcrumb-item/ui-breadcrumb-item.html +13 -13
  12. package/components/ui-breadcrumbs/ui-breadcrumbs.html +8 -8
  13. package/components/ui-button/ui-button.html +32 -29
  14. package/components/ui-callout/ui-callout.html +9 -9
  15. package/components/ui-card/ui-card.html +11 -11
  16. package/components/ui-checkbox/ui-checkbox.html +52 -33
  17. package/components/ui-cluster/ui-cluster.html +21 -21
  18. package/components/ui-color-picker/ui-color-picker.html +135 -0
  19. package/components/ui-color-picker/ui-color-picker.js +76 -0
  20. package/components/ui-combobox/ui-combobox.html +43 -43
  21. package/components/ui-container/ui-container.html +7 -7
  22. package/components/ui-context-menu/ui-context-menu.html +9 -9
  23. package/components/ui-cover/ui-cover.html +8 -8
  24. package/components/ui-description-item/ui-description-item.html +7 -7
  25. package/components/ui-description-list/ui-description-list.html +4 -4
  26. package/components/ui-dialog/ui-dialog.html +26 -26
  27. package/components/ui-disclosure/ui-disclosure.html +23 -23
  28. package/components/ui-editable/ui-editable.html +16 -16
  29. package/components/ui-editor-insert-table-grid/ui-editor-insert-table-grid.html +9 -9
  30. package/components/ui-editor-link-form/ui-editor-link-form.html +1 -2
  31. package/components/ui-editor-mention-menu/ui-editor-mention-menu.html +23 -23
  32. package/components/ui-editor-mention-menu-item/ui-editor-mention-menu-item.html +10 -10
  33. package/components/ui-editor-slash-menu/ui-editor-slash-menu.html +29 -29
  34. package/components/ui-editor-slash-menu-group/ui-editor-slash-menu-group.html +5 -5
  35. package/components/ui-editor-slash-menu-item/ui-editor-slash-menu-item.html +11 -11
  36. package/components/ui-editor-surface/ui-editor-surface.html +2 -2
  37. package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.html +25 -25
  38. package/components/ui-editor-table-overlay/ui-editor-table-overlay.html +13 -13
  39. package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.html +31 -31
  40. package/components/ui-editor-toolbar/ui-editor-toolbar.html +13 -13
  41. package/components/ui-floating-action-button/ui-floating-action-button.html +8 -8
  42. package/components/ui-form-field/ui-form-field.html +15 -15
  43. package/components/ui-form-field/ui-form-field.js +12 -4
  44. package/components/ui-grid/ui-grid.html +4 -4
  45. package/components/ui-icon/ui-icon.html +3 -2
  46. package/components/ui-icon-button/ui-icon-button.html +15 -14
  47. package/components/ui-image/ui-image.html +14 -14
  48. package/components/ui-input/ui-input.html +8 -8
  49. package/components/ui-input-group/ui-input-group.html +18 -18
  50. package/components/ui-list/ui-list.html +11 -11
  51. package/components/ui-list-item/ui-list-item.html +18 -18
  52. package/components/ui-listbox/ui-listbox.html +10 -10
  53. package/components/ui-menu/ui-menu.html +18 -17
  54. package/components/ui-menu-group/ui-menu-group.html +4 -4
  55. package/components/ui-menu-item/ui-menu-item.html +20 -20
  56. package/components/ui-meter/ui-meter.html +5 -5
  57. package/components/ui-nav-item/ui-nav-item.html +20 -20
  58. package/components/ui-page-header/ui-page-header.html +18 -17
  59. package/components/ui-popover/ui-popover.html +8 -8
  60. package/components/ui-radio/ui-radio.html +25 -17
  61. package/components/ui-radio-group/ui-radio-group.html +10 -10
  62. package/components/ui-reel/ui-reel.html +5 -5
  63. package/components/ui-scroll-area/ui-scroll-area.html +10 -10
  64. package/components/ui-search-result-row/ui-search-result-row.html +19 -19
  65. package/components/ui-search-shell/ui-search-shell.html +22 -22
  66. package/components/ui-section/ui-section.html +24 -23
  67. package/components/ui-select/ui-select.html +10 -10
  68. package/components/ui-separator/ui-separator.html +2 -2
  69. package/components/ui-sidebar/ui-sidebar.html +8 -8
  70. package/components/ui-spinner/ui-spinner.html +6 -6
  71. package/components/ui-stack/ui-stack.html +12 -12
  72. package/components/ui-status-message/ui-status-message.html +17 -17
  73. package/components/ui-swatch/ui-swatch.html +2 -2
  74. package/components/ui-switch/ui-switch.html +36 -26
  75. package/components/ui-switcher/ui-switcher.html +7 -7
  76. package/components/ui-table/ui-table.html +6 -6
  77. package/components/ui-tabs/ui-tabs.html +16 -15
  78. package/components/ui-text/ui-text.html +3 -2
  79. package/components/ui-textarea/ui-textarea.html +10 -10
  80. package/components/ui-toast/ui-toast.html +9 -9
  81. package/components/ui-toast-region/ui-toast-region.html +12 -12
  82. package/components/ui-tooltip/ui-tooltip.html +15 -15
  83. package/components/ui-top-bar/ui-top-bar.html +11 -11
  84. package/components/ui-tree/ui-tree.html +5 -5
  85. package/components/ui-tree-item/ui-tree-item.html +36 -36
  86. package/dist/index.js +46 -45
  87. package/docs/README.md +116 -0
  88. package/docs/card.html +63 -0
  89. package/docs/card.js +32 -0
  90. package/docs/catalog-view.js +18 -0
  91. package/docs/catalog-view.mjs +11 -0
  92. package/docs/catalog.json +22974 -0
  93. package/docs/catalog.mjs +131 -0
  94. package/docs/cli.mjs +26 -0
  95. package/docs/commands.mjs +94 -0
  96. package/docs/customizer-render.mjs +40 -0
  97. package/docs/customizer.js +118 -0
  98. package/docs/documentation.css +8 -0
  99. package/docs/examples/ui-action-bar/examples/01-form-footer.behavior.js +7 -0
  100. package/docs/examples/ui-button/examples/08-loading.behavior.js +21 -0
  101. package/docs/examples/ui-checkbox/examples/02-checked-indeterminate-and-disabled.behavior.js +30 -0
  102. package/docs/examples/ui-combobox/examples/06-selected-values.behavior.js +11 -0
  103. package/docs/examples/ui-search-shell/examples/02-label-dismissible-status-and-footer.behavior.js +34 -0
  104. package/docs/examples/ui-toast/examples/01-authored.behavior.js +15 -0
  105. package/docs/examples/ui-toast/examples/02-danger.behavior.js +2 -0
  106. package/docs/examples/ui-tree/examples/03-max-depth-2-and-hover-expand-delay-300.behavior.js +30 -0
  107. package/docs/examples/ui-tree/examples/06-move-without-dragging.behavior.js +2 -0
  108. package/docs/examples/ui-tree/examples/07-multiple-selection.behavior.js +16 -0
  109. package/docs/examples/ui-tree-item/examples/02-container.behavior.js +1 -0
  110. package/docs/index.d.ts +54 -0
  111. package/docs/index.mjs +4 -0
  112. package/docs/local-server.mjs +68 -0
  113. package/docs/preview.js +20 -0
  114. package/docs/reference.html +1 -0
  115. package/docs/reference.js +36 -0
  116. package/docs/render.mjs +84 -0
  117. package/docs/site.mjs +198 -0
  118. package/docs/store.mjs +92 -0
  119. package/docs/theme.mjs +100 -0
  120. package/docs/workspace.mjs +32 -0
  121. package/package.json +28 -3
  122. package/styles/ui-action-bar.css +11 -11
  123. package/styles/ui-affordance-scope.css +2 -2
  124. package/styles/ui-avatar-group.css +14 -14
  125. package/styles/ui-avatar.css +8 -8
  126. package/styles/ui-badge.css +41 -41
  127. package/styles/ui-breadcrumb-item.css +13 -13
  128. package/styles/ui-breadcrumbs.css +8 -8
  129. package/styles/ui-button.css +30 -28
  130. package/styles/ui-callout.css +9 -9
  131. package/styles/ui-card.css +11 -11
  132. package/styles/ui-checkbox.css +52 -33
  133. package/styles/ui-cluster.css +21 -21
  134. package/styles/ui-color-picker.css +120 -0
  135. package/styles/ui-combobox.css +86 -86
  136. package/styles/ui-container.css +7 -7
  137. package/styles/ui-context-menu.css +9 -9
  138. package/styles/ui-cover.css +8 -8
  139. package/styles/ui-description-item.css +7 -7
  140. package/styles/ui-description-list.css +4 -4
  141. package/styles/ui-dialog.css +52 -52
  142. package/styles/ui-disclosure.css +23 -23
  143. package/styles/ui-editable.css +16 -16
  144. package/styles/ui-editor-insert-table-grid.css +9 -9
  145. package/styles/ui-editor-mention-menu-item.css +10 -10
  146. package/styles/ui-editor-mention-menu.css +23 -23
  147. package/styles/ui-editor-slash-menu-group.css +5 -5
  148. package/styles/ui-editor-slash-menu-item.css +11 -11
  149. package/styles/ui-editor-slash-menu.css +29 -29
  150. package/styles/ui-editor-surface.css +2 -2
  151. package/styles/ui-editor-table-context-menu.css +25 -25
  152. package/styles/ui-editor-table-overlay.css +13 -13
  153. package/styles/ui-editor-table-toolbar.css +31 -31
  154. package/styles/ui-editor-toolbar.css +13 -13
  155. package/styles/ui-floating-action-button.css +8 -8
  156. package/styles/ui-form-field.css +13 -13
  157. package/styles/ui-grid.css +4 -4
  158. package/styles/ui-icon-button.css +13 -13
  159. package/styles/ui-icon.css +2 -2
  160. package/styles/ui-image.css +14 -14
  161. package/styles/ui-input-group.css +18 -18
  162. package/styles/ui-input.css +8 -8
  163. package/styles/ui-list-item.css +18 -18
  164. package/styles/ui-list.css +11 -11
  165. package/styles/ui-listbox.css +20 -20
  166. package/styles/ui-menu-group.css +4 -4
  167. package/styles/ui-menu-item.css +20 -20
  168. package/styles/ui-menu.css +16 -16
  169. package/styles/ui-meter.css +5 -5
  170. package/styles/ui-nav-item.css +20 -20
  171. package/styles/ui-page-header.css +18 -17
  172. package/styles/ui-popover.css +8 -8
  173. package/styles/ui-radio-group.css +10 -10
  174. package/styles/ui-radio.css +26 -18
  175. package/styles/ui-reel.css +5 -5
  176. package/styles/ui-scroll-area.css +10 -10
  177. package/styles/ui-search-result-row.css +19 -19
  178. package/styles/ui-search-shell.css +22 -22
  179. package/styles/ui-section.css +24 -23
  180. package/styles/ui-select.css +10 -10
  181. package/styles/ui-separator.css +2 -2
  182. package/styles/ui-sidebar.css +8 -8
  183. package/styles/ui-spinner.css +6 -6
  184. package/styles/ui-stack.css +12 -12
  185. package/styles/ui-status-message.css +17 -17
  186. package/styles/ui-swatch.css +2 -2
  187. package/styles/ui-switch.css +36 -28
  188. package/styles/ui-switcher.css +7 -7
  189. package/styles/ui-table.css +6 -6
  190. package/styles/ui-tabs.css +11 -11
  191. package/styles/ui-text.css +3 -2
  192. package/styles/ui-textarea.css +10 -10
  193. package/styles/ui-toast-region.css +24 -24
  194. package/styles/ui-toast.css +18 -18
  195. package/styles/ui-tooltip.css +15 -15
  196. package/styles/ui-top-bar.css +11 -11
  197. package/styles/ui-tree-item.css +71 -71
  198. package/styles/ui-tree.css +5 -5
  199. package/theme-system.css +80 -0
  200. package/tokens.css +14 -3
  201. package/vanilla/UiColorPicker.d.ts +30 -0
  202. package/vanilla/UiColorPicker.js +77 -0
  203. package/vanilla/UiIcon.js +1 -1
  204. package/vanilla/index.js +1 -0
  205. package/vue/UiActionBar.vue +11 -11
  206. package/vue/UiAffordanceScope.vue +2 -2
  207. package/vue/UiAvatar.vue +8 -8
  208. package/vue/UiAvatarGroup.vue +14 -14
  209. package/vue/UiBadge.vue +43 -42
  210. package/vue/UiBreadcrumbItem.vue +13 -13
  211. package/vue/UiBreadcrumbs.vue +8 -8
  212. package/vue/UiButton.vue +34 -29
  213. package/vue/UiCallout.vue +9 -9
  214. package/vue/UiCard.vue +11 -11
  215. package/vue/UiCheckbox.vue +57 -34
  216. package/vue/UiCluster.vue +21 -21
  217. package/vue/UiColorPicker.d.ts +65 -0
  218. package/vue/UiColorPicker.js +2 -0
  219. package/vue/UiColorPicker.vue +422 -0
  220. package/vue/UiCombobox.vue +86 -86
  221. package/vue/UiContainer.vue +7 -7
  222. package/vue/UiContextMenu.vue +9 -9
  223. package/vue/UiCover.vue +8 -8
  224. package/vue/UiDescriptionItem.vue +7 -7
  225. package/vue/UiDescriptionList.vue +4 -4
  226. package/vue/UiDialog.vue +52 -52
  227. package/vue/UiDisclosure.vue +23 -23
  228. package/vue/UiEditable.vue +16 -16
  229. package/vue/UiEditorInsertTableGrid.vue +9 -9
  230. package/vue/UiEditorMentionMenu.vue +23 -23
  231. package/vue/UiEditorMentionMenuItem.vue +10 -10
  232. package/vue/UiEditorSlashMenu.vue +29 -29
  233. package/vue/UiEditorSlashMenuGroup.vue +5 -5
  234. package/vue/UiEditorSlashMenuItem.vue +11 -11
  235. package/vue/UiEditorSurface.vue +2 -2
  236. package/vue/UiEditorTableContextMenu.vue +25 -25
  237. package/vue/UiEditorTableOverlay.vue +13 -13
  238. package/vue/UiEditorTableToolbar.vue +31 -31
  239. package/vue/UiEditorToolbar.vue +13 -13
  240. package/vue/UiFloatingActionButton.vue +8 -8
  241. package/vue/UiFormField.vue +14 -14
  242. package/vue/UiGrid.vue +4 -4
  243. package/vue/UiIcon.vue +6 -2
  244. package/vue/UiIconButton.vue +14 -14
  245. package/vue/UiImage.vue +14 -14
  246. package/vue/UiInput.vue +9 -8
  247. package/vue/UiInputGroup.vue +18 -18
  248. package/vue/UiList.vue +11 -11
  249. package/vue/UiListItem.vue +18 -18
  250. package/vue/UiListbox.vue +20 -20
  251. package/vue/UiMenu.vue +16 -16
  252. package/vue/UiMenuGroup.vue +4 -4
  253. package/vue/UiMenuItem.vue +20 -20
  254. package/vue/UiMeter.vue +5 -5
  255. package/vue/UiNavItem.vue +20 -20
  256. package/vue/UiPageHeader.vue +18 -17
  257. package/vue/UiPopover.vue +8 -8
  258. package/vue/UiRadio.vue +28 -17
  259. package/vue/UiRadioGroup.vue +10 -10
  260. package/vue/UiReel.vue +5 -5
  261. package/vue/UiScrollArea.vue +10 -10
  262. package/vue/UiSearchResultRow.vue +19 -19
  263. package/vue/UiSearchShell.vue +22 -22
  264. package/vue/UiSection.vue +24 -23
  265. package/vue/UiSelect.vue +11 -10
  266. package/vue/UiSeparator.vue +2 -2
  267. package/vue/UiSidebar.vue +8 -8
  268. package/vue/UiSpinner.vue +6 -6
  269. package/vue/UiStack.vue +12 -12
  270. package/vue/UiStatusMessage.vue +17 -17
  271. package/vue/UiSwatch.vue +2 -2
  272. package/vue/UiSwitch.vue +38 -25
  273. package/vue/UiSwitcher.vue +7 -7
  274. package/vue/UiTable.vue +6 -6
  275. package/vue/UiTabs.vue +13 -13
  276. package/vue/UiText.vue +3 -2
  277. package/vue/UiTextarea.vue +10 -10
  278. package/vue/UiToast.vue +18 -18
  279. package/vue/UiToastRegion.vue +24 -24
  280. package/vue/UiTooltip.vue +15 -15
  281. package/vue/UiTopBar.vue +11 -11
  282. package/vue/UiTree.vue +5 -5
  283. package/vue/UiTreeItem.vue +73 -71
  284. package/vue/chunks/UiActionBar.js +1 -1
  285. package/vue/chunks/UiAffordanceScope.js +1 -1
  286. package/vue/chunks/UiAvatar.js +1 -1
  287. package/vue/chunks/UiAvatarGroup.js +1 -1
  288. package/vue/chunks/UiBadge.js +2 -2
  289. package/vue/chunks/UiBreadcrumbItem.js +1 -1
  290. package/vue/chunks/UiBreadcrumbs.js +1 -1
  291. package/vue/chunks/UiButton.js +2 -2
  292. package/vue/chunks/UiCallout.js +1 -1
  293. package/vue/chunks/UiCard.js +1 -1
  294. package/vue/chunks/UiCheckbox.js +1 -1
  295. package/vue/chunks/UiCluster.js +1 -1
  296. package/vue/chunks/UiColorPicker.js +326 -0
  297. package/vue/chunks/UiCombobox.js +1 -1
  298. package/vue/chunks/UiContainer.js +1 -1
  299. package/vue/chunks/UiContextMenu.js +1 -1
  300. package/vue/chunks/UiCover.js +1 -1
  301. package/vue/chunks/UiDescriptionItem.js +1 -1
  302. package/vue/chunks/UiDescriptionList.js +1 -1
  303. package/vue/chunks/UiDialog.js +1 -1
  304. package/vue/chunks/UiDisclosure.js +1 -1
  305. package/vue/chunks/UiEditable.js +1 -1
  306. package/vue/chunks/UiEditorImageToolbar.js +1 -1
  307. package/vue/chunks/UiEditorInsertTableGrid.js +1 -1
  308. package/vue/chunks/UiEditorLinkForm.js +1 -1
  309. package/vue/chunks/UiEditorMentionMenu.js +1 -1
  310. package/vue/chunks/UiEditorMentionMenuItem.js +1 -1
  311. package/vue/chunks/UiEditorSlashMenu.js +1 -1
  312. package/vue/chunks/UiEditorSlashMenuGroup.js +1 -1
  313. package/vue/chunks/UiEditorSlashMenuItem.js +1 -1
  314. package/vue/chunks/UiEditorSurface.js +1 -1
  315. package/vue/chunks/UiEditorTableContextMenu.js +1 -1
  316. package/vue/chunks/UiEditorTableOverlay.js +1 -1
  317. package/vue/chunks/UiEditorTableToolbar.js +1 -1
  318. package/vue/chunks/UiEditorToolbar.js +1 -1
  319. package/vue/chunks/UiFloatingActionButton.js +1 -1
  320. package/vue/chunks/UiFormField.js +2 -2
  321. package/vue/chunks/UiGrid.js +1 -1
  322. package/vue/chunks/UiIcon.js +5 -1
  323. package/vue/chunks/UiIconButton.js +2 -2
  324. package/vue/chunks/UiImage.js +1 -1
  325. package/vue/chunks/UiInput.js +1 -1
  326. package/vue/chunks/UiInputGroup.js +1 -1
  327. package/vue/chunks/UiList.js +1 -1
  328. package/vue/chunks/UiListItem.js +1 -1
  329. package/vue/chunks/UiListbox.js +1 -1
  330. package/vue/chunks/UiMenu.js +1 -1
  331. package/vue/chunks/UiMenuGroup.js +1 -1
  332. package/vue/chunks/UiMenuItem.js +1 -1
  333. package/vue/chunks/UiMeter.js +1 -1
  334. package/vue/chunks/UiNavItem.js +1 -1
  335. package/vue/chunks/UiPageHeader.js +1 -1
  336. package/vue/chunks/UiPopover.js +1 -1
  337. package/vue/chunks/UiRadio.js +1 -1
  338. package/vue/chunks/UiRadioGroup.js +1 -1
  339. package/vue/chunks/UiReel.js +1 -1
  340. package/vue/chunks/UiScrollArea.js +1 -1
  341. package/vue/chunks/UiSearchResultRow.js +1 -1
  342. package/vue/chunks/UiSearchShell.js +1 -1
  343. package/vue/chunks/UiSection.js +1 -1
  344. package/vue/chunks/UiSelect.js +1 -1
  345. package/vue/chunks/UiSeparator.js +1 -1
  346. package/vue/chunks/UiSidebar.js +1 -1
  347. package/vue/chunks/UiSpinner.js +1 -1
  348. package/vue/chunks/UiStack.js +1 -1
  349. package/vue/chunks/UiStatusMessage.js +1 -1
  350. package/vue/chunks/UiSwatch.js +1 -1
  351. package/vue/chunks/UiSwitch.js +1 -1
  352. package/vue/chunks/UiSwitcher.js +1 -1
  353. package/vue/chunks/UiTable.js +1 -1
  354. package/vue/chunks/UiTabs.js +3 -3
  355. package/vue/chunks/UiText.js +1 -1
  356. package/vue/chunks/UiTextarea.js +1 -1
  357. package/vue/chunks/UiToast.js +1 -1
  358. package/vue/chunks/UiToastRegion.js +1 -1
  359. package/vue/chunks/UiTooltip.js +1 -1
  360. package/vue/chunks/UiTopBar.js +1 -1
  361. package/vue/chunks/UiTree.js +1 -1
  362. package/vue/chunks/UiTreeItem.js +1 -1
  363. package/vue/components.css +1857 -1654
  364. package/vue/editor/index.js +28 -11
  365. package/vue/index.d.ts +1 -0
  366. package/vue/index.js +3 -2
package/docs/theme.mjs ADDED
@@ -0,0 +1,100 @@
1
+ /** The shared authoring schema; ids remain stable in saved recipes. */
2
+ export const themeFields = [
3
+ ['Colour', 'action', 'Action', '--ui-accent', 'colour', '#5b55d6', 'Primary commands and selected controls.'],
4
+ ['Colour', 'canvas', 'Canvas', '--ui-surface', 'colour', '#f6f6f8', 'The ground behind surfaces.'],
5
+ ['Colour', 'surface', 'Surface', '--ui-surface-raised', 'colour', '#ffffff', 'Fields, cards and floating surfaces.'],
6
+ ['Colour', 'text', 'Text', '--ui-text', 'colour', '#1a1a1a', 'Readable content; supporting text follows this and Surface.'],
7
+ ['Type', 'body-font', 'Body font', '--ui-font-sans', 'font', 'system-ui, sans-serif', 'The shared interface typeface.'],
8
+ ['Type', 'display-font', 'Display font', '--ui-font-display', 'font', 'system-ui, sans-serif', 'The heading typeface.'],
9
+ ['Type', 'text-size', 'Text size', '--ui-font-size', 'positive-length', '16px', 'Base type and choice-mark size. Accepts native CSS lengths, such as 1rem.'],
10
+ ['Type', 'text-weight', 'Emphasis weight', '--ui-font-medium', 'weight', '500', 'Control-label emphasis; body and headings keep their roles.'],
11
+ ['Size & spacing', 'control-size', 'Control size', '--ui-control-size', 'positive-length', '40px', 'One shared height for buttons, fields and swatches.'],
12
+ ['Size & spacing', 'density', 'Density', '--ui-density', 'positive', '1', 'More or less breathing room throughout the interface.'],
13
+ ['Size & spacing', 'scale-contrast', 'Size ratio', '--ui-scale-ratio', 'ratio', '1.2', 'The multiplier between small, medium and large controls.'],
14
+ ['Size & spacing', 'space-curve', 'Spacing curve', '--ui-space-curve', 'nonnegative', '1', 'Spacing growth: 1 is linear, 2 is quadratic. Independent of control sizes.'],
15
+ ['Size & spacing', 'corner-roundness', 'Corner roundness', '--ui-radius-md', 'length', '8px', 'One corner family across controls and surfaces.'],
16
+ ['Size & spacing', 'line-weight', 'Line weight', '--ui-border-width', 'length', '1px', 'Shared edge weight; focus stays independently visible.'],
17
+ ['Material', 'outer-depth', 'Outer depth', '--ui-outer-depth', 'nonnegative', '0.6', 'How strongly controls and floating surfaces rise above the page.'],
18
+ ['Material', 'inner-depth', 'Inner depth', '--ui-inner-depth', 'nonnegative', '0.3', 'How strongly fields and pressed controls sit into their surface.'],
19
+ ['Material', 'translucency', 'Overlay translucency', '--ui-overlay-translucency', 'fraction', '0', 'How much background comes through floating surfaces.'],
20
+ ['Material', 'edge-light', 'Edge light', '--ui-edge-light', 'fraction', '0', 'Light caught by surface edges, independent of depth.'],
21
+ ['Motion', 'response-time', 'Response time', '--ui-motion-fast', 'time', '120ms', 'Shared feedback pace; floating transitions take proportionally longer.'],
22
+ ['Motion', 'response-curve', 'Response curve', '--ui-motion-ease', 'easing', 'cubic-bezier(0.2,0,0.2,1)', 'How movement accelerates and settles.'],
23
+ ].map(([family, id, label, property, type, defaultValue, description]) => Object.freeze({ family, id, label, property, type, defaultValue, description }));
24
+
25
+ export const defaultRecipe = () => ({ schemaVersion: 1, values: Object.fromEntries(themeFields.map(field => [field.id, field.defaultValue])) });
26
+ const starting = values => ({ schemaVersion: 1, values: { ...defaultRecipe().values, ...values } });
27
+ export const startingPoints = {
28
+ clear: defaultRecipe(),
29
+ library: starting({ action: '#2e1228', canvas: '#f7f7f5', surface: '#fffefd', text: '#0d0c0c', 'body-font': 'Arial, sans-serif', 'display-font': 'Georgia, serif', 'text-weight': '400', 'control-size': '42px', 'scale-contrast': '1.18', 'outer-depth': '1', 'inner-depth': '1', translucency: '0.18', 'edge-light': '1', 'response-time': '150ms', 'response-curve': 'ease' }),
30
+ editorial: starting({ action: '#182c24', canvas: '#eee9dc', surface: '#fffdf5', text: '#182c24', 'corner-roundness': '0px', 'outer-depth': '0', 'inner-depth': '0', 'body-font': 'Georgia, serif', 'display-font': 'Georgia, serif', 'text-weight': '400', 'line-weight': '2px', 'response-time': '90ms', 'response-curve': 'linear' }),
31
+ night: starting({ action: '#a7b8ff', canvas: '#11141c', surface: '#202634', text: '#edf1fb', 'corner-roundness': '12px', 'outer-depth': '1.4', 'inner-depth': '0.45', translucency: '0.2', 'edge-light': '0.65', 'response-time': '210ms', 'response-curve': 'cubic-bezier(0.2,0.8,0.2,1)' }),
32
+ garden: starting({ action: '#256342', canvas: '#eef5e7', surface: '#fcfff6', text: '#173121', 'corner-roundness': '22px', 'outer-depth': '0.35', 'inner-depth': '0', 'edge-light': '0.2', 'control-size': '46px', 'scale-contrast': '1.24', density: '1.05', 'response-time': '180ms', 'response-curve': 'cubic-bezier(0.16,1,0.3,1)' }),
33
+ };
34
+ export const startingPointLabels = { clear: 'Clear', library: 'Library', editorial: 'Editorial', night: 'Night', garden: 'Garden' };
35
+ const scalar = /^[+]?(?:\d+(?:\.\d*)?|\.\d+)$/;
36
+ const length = /^(?:0|[+]?(?:\d+(?:\.\d*)?|\.\d+)(?:px|rem|em|ex|ch|cap|ic|lh|rlh|vw|vh|vi|vb|vmin|vmax|svw|svh|lvw|lvh|dvw|dvh|cm|mm|Q|in|pt|pc))$/;
37
+ const font = /^(?:"[^"\\;{}<>@\x00-\x1f]+"|'[^'\\;{}<>@\x00-\x1f]+'|[\p{L}_-][\p{L}\p{N}_ -]*)(?:\s*,\s*(?:"[^"\\;{}<>@\x00-\x1f]+"|'[^'\\;{}<>@\x00-\x1f]+'|[\p{L}_-][\p{L}\p{N}_ -]*))*$/u;
38
+ const time = /^[+]?(?:\d+(?:\.\d*)?|\.\d+)(?:ms|s)$/;
39
+ function easing(value) {
40
+ if (/^(ease|linear|ease-in|ease-out|ease-in-out|step-start|step-end)$/.test(value)) return true;
41
+ const match = /^cubic-bezier\(\s*([\d.+-]+)\s*,\s*([\d.+-]+)\s*,\s*([\d.+-]+)\s*,\s*([\d.+-]+)\s*\)$/.exec(value);
42
+ return Boolean(match && match.slice(1).every(n => Number.isFinite(Number(n))) && [1, 3].every(i => Number(match[i]) >= 0 && Number(match[i]) <= 1));
43
+ }
44
+
45
+ /** Validate the whole recipe before previewing or writing any output. */
46
+ export function validateRecipe(input) {
47
+ if (!input || input.schemaVersion !== 1 || !input.values || typeof input.values !== 'object' || Array.isArray(input.values)) throw new Error('Unsupported theme recipe version or values.');
48
+ const known = new Set(themeFields.map(field => field.id));
49
+ for (const key of Object.keys(input.values)) if (!known.has(key)) throw new Error(`Unknown theme decision ${key}.`);
50
+ const values = { ...defaultRecipe().values, ...input.values };
51
+ for (const field of themeFields) {
52
+ const value = values[field.id];
53
+ let valid = typeof value === 'string' && value.length > 0;
54
+ if (valid) switch (field.type) {
55
+ case 'colour': valid = /^#[\da-f]{6}$/i.test(value); break;
56
+ case 'font': valid = font.test(value); break;
57
+ case 'length': valid = length.test(value) && Number.isFinite(parseFloat(value)); break;
58
+ case 'positive-length': valid = length.test(value) && Number.isFinite(parseFloat(value)) && parseFloat(value) > 0; break;
59
+ case 'time': valid = time.test(value) && Number.isFinite(parseFloat(value)); break;
60
+ case 'easing': valid = easing(value); break;
61
+ default: {
62
+ const number = Number(value); valid = scalar.test(value) && Number.isFinite(number);
63
+ if (field.type === 'positive') valid &&= number > 0;
64
+ if (field.type === 'ratio') valid &&= number >= 1;
65
+ if (field.type === 'fraction') valid &&= number >= 0 && number <= 1;
66
+ if (field.type === 'weight') valid &&= number >= 1 && number <= 1000;
67
+ }
68
+ }
69
+ if (!valid) throw new Error(`${field.label}: enter a valid ${field.type.replaceAll('-', ' ')} value.`);
70
+ }
71
+ return { schemaVersion: 1, values };
72
+ }
73
+
74
+ /** Match presets by their complete semantic recipe, including locally saved themes. */
75
+ export function startingPointFor(input) {
76
+ const recipe = JSON.stringify(validateRecipe(input));
77
+ return Object.entries(startingPoints).find(([, value]) => JSON.stringify(value) === recipe)?.[0] ?? 'custom';
78
+ }
79
+
80
+ const rgb = hex => [1, 3, 5].map(i => parseInt(hex.slice(i, i + 2), 16));
81
+ const mix = (a, b, weight) => '#' + rgb(a).map((n, i) => Math.round(n * weight + rgb(b)[i] * (1 - weight)).toString(16).padStart(2, '0')).join('');
82
+ const luminance = hex => rgb(hex).map(n => { const s = n / 255; return s <= .04045 ? s / 12.92 : ((s + .055) / 1.055) ** 2.4; }).reduce((sum, n, i) => sum + n * [.2126, .7152, .0722][i], 0);
83
+ const contrast = (a, b) => (Math.max(luminance(a), luminance(b)) + .05) / (Math.min(luminance(a), luminance(b)) + .05);
84
+ const foreground = (fill, light, dark) => [light, dark, '#ffffff', '#000000'].sort((a, b) => contrast(fill, b) - contrast(fill, a))[0];
85
+
86
+ /** Shared public seeds; combine with theme-system.css for a standalone exported theme. */
87
+ export function themeCSS(input, systemCSS = '') {
88
+ const { values } = validateRecipe(input);
89
+ const tokens = Object.fromEntries(themeFields.map(field => [field.property, values[field.id]]));
90
+ tokens['--ui-on-accent'] = foreground(values.action, values.surface, values.text);
91
+ tokens['--ui-surface-sunken'] = mix(values.surface, values.canvas, .92);
92
+ let muted = values.text;
93
+ for (let weight = .72; weight <= 1; weight += .01) { muted = mix(values.text, values.surface, weight); if (contrast(muted, values.surface) >= 4.5) break; }
94
+ tokens['--ui-text-secondary'] = muted;
95
+ let danger = '#c92d1e';
96
+ for (let weight = 0; weight <= 1; weight += .02) { danger = mix('#c92d1e', values.text, 1 - weight); if (Math.min(contrast(danger, values.surface), contrast(danger, values.canvas)) >= 4.5) break; }
97
+ tokens['--ui-danger'] = danger; tokens['--ui-on-danger'] = foreground(danger, values.surface, values.text);
98
+ tokens['--ui-focus-width'] = 'max(2px, calc(var(--ui-border-width) * 2))';
99
+ return `/* Looma shared semantic theme. */\n${systemCSS}\n:root, [data-theme], [data-contrast] {\n${Object.entries(tokens).map(([name, value]) => ` ${name}: ${value};`).join('\n')}\n}\n@media (prefers-reduced-motion: reduce) {\n :root, [data-theme], [data-contrast] { --ui-motion-fast: 0ms; --ui-motion-base: 0ms; --ui-motion-press: 0ms; --ui-press-scale: 1; }\n}\n`;
100
+ }
@@ -0,0 +1,32 @@
1
+ import { lstat, mkdir, open, realpath, unlink } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ export async function rejectSymlink(file) {
5
+ try { if ((await lstat(file)).isSymbolicLink()) throw new Error(`Looma's generated path cannot be a symlink: ${file}.`); }
6
+ catch (error) { if (error.code !== 'ENOENT') throw error; }
7
+ }
8
+
9
+ /** Generated sources and tooling wrappers stay in owned cache directories. */
10
+ export async function cacheDirectory(root, name = '') {
11
+ root = await realpath(path.resolve(root));
12
+ if (name && !/^[a-z][a-z-]*$/.test(name)) throw new Error('Invalid Looma cache directory.');
13
+ const cache = path.join(root, '.looma');
14
+ await rejectSymlink(cache); await mkdir(cache, { recursive: true });
15
+ const directory = path.join(cache, name);
16
+ await rejectSymlink(directory); await mkdir(directory, { recursive: true });
17
+ return directory;
18
+ }
19
+
20
+ /** One complete preparation/build owns the generated tree, including across CLI processes. */
21
+ export async function withBuildLock(root, action) {
22
+ const lockFile = path.join(await cacheDirectory(root), 'docs-build.lock');
23
+ await rejectSymlink(lockFile);
24
+ let lock;
25
+ try { lock = await open(lockFile, 'wx', 0o600); }
26
+ catch (error) {
27
+ if (error.code === 'EEXIST') throw new Error('Another documentation build holds .looma/docs-build.lock. Retry after it finishes. If the old process stopped, close it before removing that lock.');
28
+ throw error;
29
+ }
30
+ try { await lock.writeFile(JSON.stringify({ pid: process.pid })); return await action(); }
31
+ finally { try { await lock.close(); } finally { await unlink(lockFile); } }
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadlabs/looma",
3
- "version": "0.32.1",
3
+ "version": "0.33.1",
4
4
  "type": "module",
5
5
  "description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
6
6
  "license": "MIT",
@@ -82,6 +82,14 @@
82
82
  "types": "./editor/expressmark.d.ts",
83
83
  "import": "./editor/expressmark.js",
84
84
  "default": "./editor/expressmark.js"
85
+ },
86
+ "./theme-system.css": "./theme-system.css",
87
+ "./docs/catalog.json": "./docs/catalog.json",
88
+ "./docs/*": "./docs/*",
89
+ "./docs": {
90
+ "types": "./docs/index.d.ts",
91
+ "import": "./docs/index.mjs",
92
+ "default": "./docs/index.mjs"
85
93
  }
86
94
  },
87
95
  "files": [
@@ -95,7 +103,9 @@
95
103
  "*.css",
96
104
  "README.md",
97
105
  "LICENSE",
98
- "EXPRESSIVE-MARKDOWN.md"
106
+ "EXPRESSIVE-MARKDOWN.md",
107
+ "docs/",
108
+ "bin/"
99
109
  ],
100
110
  "sideEffects": [
101
111
  "./dist/index.js",
@@ -116,7 +126,10 @@
116
126
  "@tiptap/core": ">=2 <3",
117
127
  "@tiptap/pm": ">=2 <3",
118
128
  "@tiptap/vue-3": ">=2 <3",
119
- "vue": "^3.5.43"
129
+ "vue": "^3.5.43",
130
+ "markupress": "^0.8.0",
131
+ "@nextwebwg/htmlkit": "1.0.0-alpha.69",
132
+ "vite": "^8.3.4"
120
133
  },
121
134
  "peerDependenciesMeta": {
122
135
  "@tiptap/core": {
@@ -130,6 +143,15 @@
130
143
  },
131
144
  "vue": {
132
145
  "optional": true
146
+ },
147
+ "markupress": {
148
+ "optional": true
149
+ },
150
+ "@nextwebwg/htmlkit": {
151
+ "optional": true
152
+ },
153
+ "vite": {
154
+ "optional": true
133
155
  }
134
156
  },
135
157
  "devDependencies": {
@@ -184,6 +206,9 @@
184
206
  "engines": {
185
207
  "node": ">=22.22.2 <23 || >=24.15 <25"
186
208
  },
209
+ "bin": {
210
+ "looma-docs": "./bin/looma-docs.mjs"
211
+ },
187
212
  "scripts": {
188
213
  "build": "node build.mjs",
189
214
  "lint": "vue-tsc -p tsconfig.json --noEmit",
@@ -21,7 +21,7 @@
21
21
  --_ui-action-bar-gap: var(--ui-action-bar-gap);
22
22
 
23
23
  --_gap: var(--ui-space-2);
24
- display: block;
24
+ display: block !important;
25
25
  /* A size container sizes itself from its container, never its content. */
26
26
  container-type: inline-size;
27
27
  inline-size: 100%;
@@ -32,16 +32,16 @@
32
32
  .tertiary,
33
33
  .secondary,
34
34
  .primary {
35
- display: flex;
36
- flex-wrap: wrap;
37
- align-items: center;
38
- gap: var(--_ui-action-bar-gap, var(--_gap));
35
+ display: flex !important;
36
+ flex-wrap: wrap !important;
37
+ align-items: center !important;
38
+ gap: var(--_ui-action-bar-gap, var(--_gap)) !important;
39
39
  }
40
40
 
41
41
  /* The tertiary group takes the spare space, pushing the rest to the end edge; without it, the
42
42
  rest still ends the row. */
43
43
  .bar {
44
- justify-content: flex-end;
44
+ justify-content: flex-end !important;
45
45
  }
46
46
 
47
47
  .tertiary {
@@ -51,7 +51,7 @@
51
51
  .tertiary:empty,
52
52
  .secondary:empty,
53
53
  .primary:empty {
54
- display: none;
54
+ display: none !important;
55
55
  }
56
56
 
57
57
  /* A narrow container stacks the actions full width, primary on top: the row turned on its end,
@@ -61,9 +61,9 @@
61
61
  .tertiary,
62
62
  .secondary,
63
63
  .primary {
64
- flex-direction: column-reverse;
65
- flex-wrap: nowrap;
66
- align-items: stretch;
64
+ flex-direction: column-reverse !important;
65
+ flex-wrap: nowrap !important;
66
+ align-items: stretch !important;
67
67
  }
68
68
 
69
69
  .tertiary {
@@ -73,7 +73,7 @@
73
73
 
74
74
  /* A component that sets its display still honours the hidden attribute on its root. */
75
75
  :scope:where([data-component~="ui-action-bar"])[hidden] {
76
- display: none;
76
+ display: none !important;
77
77
  }
78
78
  }
79
79
  @scope ([data-component~="ui-action-bar"]) to ([data-component]) {
@@ -8,7 +8,7 @@
8
8
  }
9
9
  @scope ([data-component~="ui-affordance-scope"]) to ([data-component], [data-slotted]) {
10
10
  :scope:where([data-component~="ui-affordance-scope"]) {
11
- display: contents;
11
+ display: contents !important;
12
12
  --ui-affordance-scope-engaged: 0;
13
13
  --ui-affordance-scope-guide: 1;
14
14
  }
@@ -24,7 +24,7 @@
24
24
 
25
25
  /* A component that sets its display still honours the hidden attribute on its root. */
26
26
  :scope:where([data-component~="ui-affordance-scope"])[hidden] {
27
- display: none;
27
+ display: none !important;
28
28
  }
29
29
  }
30
30
  @scope ([data-component~="ui-affordance-scope"]) to ([data-component]) {
@@ -26,10 +26,10 @@
26
26
  * a white gap out of the avatar underneath. */
27
27
  --_overlap-shadow: -1px 0 0 0 rgb(0 0 0 / 0.22);
28
28
 
29
- display: flex;
30
- align-items: center;
31
- flex-direction: row;
32
- gap: 0;
29
+ display: flex !important;
30
+ align-items: center !important;
31
+ flex-direction: row !important;
32
+ gap: 0 !important;
33
33
  }
34
34
 
35
35
  /* Overlap and the separating shadow are applied by the controller: slotted avatars are nested
@@ -40,10 +40,10 @@
40
40
  }
41
41
 
42
42
  .overflow {
43
- margin-inline-start: -0.5rem;
44
- display: inline-flex;
45
- align-items: center;
46
- justify-content: center;
43
+ margin-inline-start: -0.5rem !important;
44
+ display: inline-flex !important;
45
+ align-items: center !important;
46
+ justify-content: center !important;
47
47
  inline-size: 2.5rem;
48
48
  block-size: 2.5rem;
49
49
  border-radius: var(--ui-radius-round);
@@ -60,13 +60,13 @@
60
60
  }
61
61
 
62
62
  :scope:where([data-component~="ui-avatar-group"])[data-ui-avatar-group-state~="size=sm"] .overflow {
63
- margin-inline-start: -0.25rem;
63
+ margin-inline-start: -0.25rem !important;
64
64
  inline-size: 1.75rem;
65
65
  block-size: 1.75rem;
66
66
  }
67
67
 
68
68
  :scope:where([data-component~="ui-avatar-group"])[data-ui-avatar-group-state~="size=xs"] .overflow {
69
- margin-inline-start: -0.1875rem;
69
+ margin-inline-start: -0.1875rem !important;
70
70
  inline-size: 1.25rem;
71
71
  block-size: 1.25rem;
72
72
  /* Matches the xs Avatar's initials. */
@@ -75,12 +75,12 @@
75
75
  }
76
76
 
77
77
  .overflow[hidden] {
78
- display: none;
78
+ display: none !important;
79
79
  }
80
80
 
81
81
  /* A component that sets its display still honours the hidden attribute on its root. */
82
82
  :scope:where([data-component~="ui-avatar-group"])[hidden] {
83
- display: none;
83
+ display: none !important;
84
84
  }
85
85
  }
86
86
  @scope ([data-component~="ui-avatar-group"]) to ([data-component]) {
@@ -89,12 +89,12 @@
89
89
  /* Overlap and the separating shadow are applied by the controller: slotted avatars are nested
90
90
  * component roots outside this style scope. */
91
91
  :where([data-slotted], [data-slotted] *):is(*) {
92
- margin-inline-start: -0.5rem;
92
+ margin-inline-start: -0.5rem !important;
93
93
  flex-shrink: 0;
94
94
  }
95
95
 
96
96
  :where([data-slotted], [data-slotted] *):is(*:first-child) {
97
- margin-inline-start: 0;
97
+ margin-inline-start: 0 !important;
98
98
  }
99
99
 
100
100
  /* A component that sets its display still honours the hidden attribute on its root. */
@@ -31,7 +31,7 @@
31
31
 
32
32
  :scope:where([data-component~="ui-avatar"]) {
33
33
  --_ui-default-icon-size: 1.25rem;
34
- display: inline-grid;
34
+ display: inline-grid !important;
35
35
  place-items: center;
36
36
  overflow: hidden;
37
37
  inline-size: 2.5rem;
@@ -85,9 +85,9 @@
85
85
 
86
86
  .fallback {
87
87
  grid-area: 1 / 1;
88
- display: inline-flex;
89
- align-items: center;
90
- justify-content: center;
88
+ display: inline-flex !important;
89
+ align-items: center !important;
90
+ justify-content: center !important;
91
91
  inline-size: 100%;
92
92
  block-size: 100%;
93
93
  }
@@ -97,21 +97,21 @@
97
97
  * Trimming applies to block containers, so the box is a block with centred content. */
98
98
  @supports (text-box-trim: trim-both) {
99
99
  .fallback {
100
- display: block;
100
+ display: block !important;
101
101
  text-align: center;
102
- align-content: center;
102
+ align-content: center !important;
103
103
  text-box-trim: trim-both;
104
104
  text-box-edge: cap alphabetic;
105
105
  }
106
106
  }
107
107
 
108
108
  [hidden] {
109
- display: none;
109
+ display: none !important;
110
110
  }
111
111
 
112
112
  /* A component that sets its display still honours the hidden attribute on its root. */
113
113
  :scope:where([data-component~="ui-avatar"])[hidden] {
114
- display: none;
114
+ display: none !important;
115
115
  }
116
116
  }
117
117
  @scope ([data-component~="ui-avatar"]) to ([data-component]) {
@@ -85,14 +85,14 @@
85
85
  --_badge-color-text: var(--_badge-color-ink);
86
86
  --_badge-outline-surface: var(--ui-badge-surface, var(--_badge-color-surface, var(--_badge-surface)));
87
87
 
88
- display: inline-flex;
89
- align-items: center;
90
- justify-content: center;
91
- gap: var(--ui-space-1);
92
- box-sizing: border-box;
88
+ display: inline-flex !important;
89
+ align-items: center !important;
90
+ justify-content: center !important;
91
+ gap: var(--ui-space-1) !important;
92
+ box-sizing: border-box !important;
93
93
  min-inline-size: 0;
94
94
  max-inline-size: 100%;
95
- padding: var(--ui-badge-padding-block, var(--ui-space-0-5)) var(--ui-badge-padding-inline, var(--ui-space-2));
95
+ padding: var(--ui-badge-padding-block, var(--ui-space-0-5)) var(--ui-badge-padding-inline, var(--ui-space-2)) !important;
96
96
  border: var(--ui-border-width) solid var(--ui-badge-border, var(--_badge-color-border, var(--_badge-border)));
97
97
  border-radius: var(--ui-radius-round);
98
98
  background: var(--_badge-outline-surface);
@@ -107,26 +107,26 @@
107
107
  /* A constrained badge keeps its surface intact and ellipsizes only its label. The full
108
108
  text stays in the DOM for accessible names and consumers' selected values. */
109
109
  .label {
110
- display: block;
110
+ display: block !important;
111
111
  min-inline-size: 0;
112
112
  overflow: hidden;
113
113
  text-overflow: ellipsis;
114
114
  }
115
115
 
116
116
  .label:empty {
117
- display: none;
117
+ display: none !important;
118
118
  }
119
119
 
120
120
  /* Icon content has its own flex item so label ellipsis never clips its strokes. */
121
121
  .icon {
122
- display: inline-flex;
123
- align-items: center;
124
- justify-content: center;
122
+ display: inline-flex !important;
123
+ align-items: center !important;
124
+ justify-content: center !important;
125
125
  flex: none;
126
126
  }
127
127
 
128
128
  .icon:empty {
129
- display: none;
129
+ display: none !important;
130
130
  }
131
131
 
132
132
  /* Ordinary icon-plus-text children keep inline ellipsis, with explicit glyph spacing. */
@@ -139,15 +139,15 @@
139
139
  Vertical ink remains visible so trimming never cuts off ascenders or descenders. */
140
140
  @supports (text-box-trim: trim-both) {
141
141
  :scope:where([data-component~="ui-badge"]) {
142
- display: inline-block;
142
+ display: inline-block !important;
143
143
  min-block-size: var(--ui-badge-min-block-size, 1.5rem);
144
144
  text-align: center;
145
- align-content: center;
145
+ align-content: center !important;
146
146
  text-box-trim: none;
147
147
  }
148
148
  :scope:where([data-component~="ui-badge"]):has(.icon:not(:empty)),
149
149
  :scope:where([data-component~="ui-badge"]):has(.label svg) {
150
- display: inline-flex;
150
+ display: inline-flex !important;
151
151
  text-box-trim: none;
152
152
  }
153
153
  .label:not(:has(svg)) {
@@ -159,12 +159,12 @@
159
159
  }
160
160
 
161
161
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="size=xs"] {
162
- box-sizing: border-box;
162
+ box-sizing: border-box !important;
163
163
  min-inline-size: 1rem;
164
164
  min-block-size: var(--ui-badge-min-block-size, 1rem);
165
165
  /* Compact text still needs room at both rounded edges. Fixed marks override this
166
166
  padding below; ordinary text badges retain their larger spacing. */
167
- padding: var(--ui-badge-padding-block, 0) var(--ui-badge-padding-inline, var(--ui-space-1));
167
+ padding: var(--ui-badge-padding-block, 0) var(--ui-badge-padding-inline, var(--ui-space-1)) !important;
168
168
  font-size: var(--ui-badge-font-size, var(--ui-font-size-2xs));
169
169
  line-height: var(--ui-badge-line-height, 1);
170
170
  }
@@ -338,14 +338,14 @@
338
338
  /* An icon mark keeps the existing tone recipe and follows the global spacing and radius. */
339
339
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=square"] {
340
340
  --_badge-square-size: var(--ui-badge-square-size, calc(var(--ui-space-4) * 2));
341
- display: inline-flex;
342
- box-sizing: border-box;
341
+ display: inline-flex !important;
342
+ box-sizing: border-box !important;
343
343
  flex: none;
344
344
  inline-size: var(--_badge-square-size);
345
345
  block-size: var(--_badge-square-size);
346
346
  min-inline-size: var(--_badge-square-size);
347
347
  min-block-size: var(--_badge-square-size);
348
- padding: 0;
348
+ padding: 0 !important;
349
349
  border-radius: var(--ui-radius-md);
350
350
  text-box-trim: none;
351
351
  }
@@ -359,25 +359,25 @@
359
359
  }
360
360
 
361
361
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=square"] .label {
362
- display: inline-flex;
363
- align-items: center;
364
- justify-content: center;
362
+ display: inline-flex !important;
363
+ align-items: center !important;
364
+ justify-content: center !important;
365
365
  }
366
366
 
367
367
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=square"] .label:empty {
368
- display: none;
368
+ display: none !important;
369
369
  }
370
370
 
371
371
  /* A visible glyph needs fixed geometry, unlike a content-sized pill or a hidden-label dot. */
372
372
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=circle"] {
373
373
  --_badge-circle-size: var(--ui-badge-circle-size, calc(var(--ui-space-3) * 2));
374
- display: inline-flex;
374
+ display: inline-flex !important;
375
375
  flex: none;
376
376
  inline-size: var(--_badge-circle-size);
377
377
  block-size: var(--_badge-circle-size);
378
378
  min-inline-size: var(--_badge-circle-size);
379
379
  min-block-size: var(--_badge-circle-size);
380
- padding: 0;
380
+ padding: 0 !important;
381
381
  border-radius: var(--ui-radius-round);
382
382
  text-box-trim: none;
383
383
  }
@@ -395,15 +395,15 @@
395
395
  }
396
396
 
397
397
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=circle"] .label {
398
- display: inline-flex;
399
- align-items: center;
400
- justify-content: center;
398
+ display: inline-flex !important;
399
+ align-items: center !important;
400
+ justify-content: center !important;
401
401
  line-height: 1;
402
402
  text-box-trim: none;
403
403
  }
404
404
 
405
405
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=circle"] .label:empty {
406
- display: none;
406
+ display: none !important;
407
407
  }
408
408
 
409
409
  /* Center capital and numeral ink, rather than the font's ascent/descent line box.
@@ -411,7 +411,7 @@
411
411
  @supports (text-box-trim: trim-both) {
412
412
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=circle"] .label:not(:has(svg)),
413
413
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=square"] .label:not(:has(svg)) {
414
- display: block;
414
+ display: block !important;
415
415
  text-box-trim: trim-both;
416
416
  text-box-edge: cap alphabetic;
417
417
  overflow: visible;
@@ -421,13 +421,13 @@
421
421
  /* A dot uses the badge's tone recipe; only its silhouette and visible label change. */
422
422
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=dot"] {
423
423
  position: relative;
424
- box-sizing: border-box;
424
+ box-sizing: border-box !important;
425
425
  flex: none;
426
426
  inline-size: var(--ui-badge-dot-size, var(--ui-space-2));
427
427
  block-size: var(--ui-badge-dot-size, var(--ui-space-2));
428
428
  min-inline-size: var(--ui-badge-dot-size, var(--ui-space-2));
429
429
  min-block-size: var(--ui-badge-dot-size, var(--ui-space-2));
430
- padding: 0;
430
+ padding: 0 !important;
431
431
  border-radius: var(--ui-radius-round);
432
432
  text-box-trim: none;
433
433
  }
@@ -451,7 +451,7 @@
451
451
  border-color: transparent;
452
452
  border-radius: 0;
453
453
  background: var(--ui-badge-border, var(--_badge-color-border, var(--_badge-border)));
454
- padding-inline-end: calc(var(--ui-badge-padding-inline, var(--ui-space-2)) + var(--_badge-point));
454
+ padding-inline-end: calc(var(--ui-badge-padding-inline, var(--ui-space-2)) + var(--_badge-point)) !important;
455
455
  clip-path: polygon(0 0, calc(100% - var(--_badge-point)) 0, 100% 50%, calc(100% - var(--_badge-point)) 100%, 0 100%);
456
456
  }
457
457
 
@@ -470,8 +470,8 @@
470
470
  }
471
471
 
472
472
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=tag"]:dir(rtl) {
473
- padding-inline-end: var(--ui-badge-padding-inline, var(--ui-space-2));
474
- padding-inline-start: calc(var(--ui-badge-padding-inline, var(--ui-space-2)) + var(--_badge-point));
473
+ padding-inline-end: var(--ui-badge-padding-inline, var(--ui-space-2)) !important;
474
+ padding-inline-start: calc(var(--ui-badge-padding-inline, var(--ui-space-2)) + var(--_badge-point)) !important;
475
475
  clip-path: polygon(var(--_badge-point) 0, 100% 0, 100% 100%, var(--_badge-point) 100%, 0 50%);
476
476
  }
477
477
 
@@ -499,7 +499,7 @@
499
499
 
500
500
  /* A component that sets its display still honours the hidden attribute on its root. */
501
501
  :scope:where([data-component~="ui-badge"])[hidden] {
502
- display: none;
502
+ display: none !important;
503
503
  }
504
504
  }
505
505
  @scope ([data-component~="ui-badge"]) to ([data-component]) {
@@ -511,7 +511,7 @@
511
511
  /* Icon content has its own flex item so label ellipsis never clips its strokes. */
512
512
 
513
513
  .icon :where([data-slotted], [data-slotted] *):is(svg) {
514
- display: block;
514
+ display: block !important;
515
515
  inline-size: 1em;
516
516
  block-size: 1em;
517
517
  flex: none;
@@ -522,7 +522,7 @@
522
522
  inline-size: 1em;
523
523
  block-size: 1em;
524
524
  vertical-align: middle;
525
- margin-inline-end: var(--ui-space-1);
525
+ margin-inline-end: var(--ui-space-1) !important;
526
526
  }
527
527
 
528
528
  /* Center the capital/baseline text box, while clipping only inline overflow for ellipsis.
@@ -548,13 +548,13 @@
548
548
  /* An icon mark keeps the existing tone recipe and follows the global spacing and radius. */
549
549
 
550
550
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=square"] .label :where([data-slotted], [data-slotted] *):is(svg) {
551
- margin-inline-end: 0;
551
+ margin-inline-end: 0 !important;
552
552
  }
553
553
 
554
554
  /* A visible glyph needs fixed geometry, unlike a content-sized pill or a hidden-label dot. */
555
555
 
556
556
  :scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=circle"] .label :where([data-slotted], [data-slotted] *):is(svg) {
557
- margin-inline-end: 0;
557
+ margin-inline-end: 0 !important;
558
558
  }
559
559
 
560
560
  /* Center capital and numeral ink, rather than the font's ascent/descent line box.