@threadlabs/looma 0.16.5 → 0.17.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 (230) hide show
  1. package/components/ui-avatar-group/ui-avatar-group.html +8 -5
  2. package/components/ui-avatar-group/ui-avatar-group.js +3 -3
  3. package/components/ui-badge/ui-badge.html +10 -5
  4. package/components/ui-breadcrumb-item/ui-breadcrumb-item.html +2 -1
  5. package/components/ui-button/ui-button.html +33 -26
  6. package/components/ui-button/ui-button.js +2 -2
  7. package/components/ui-callout/ui-callout.html +3 -1
  8. package/components/ui-card/ui-card.html +5 -3
  9. package/components/ui-checkbox/ui-checkbox.html +36 -8
  10. package/components/ui-combobox/ui-combobox.html +72 -45
  11. package/components/ui-combobox/ui-combobox.js +7 -2
  12. package/components/ui-context-menu/ui-context-menu.html +2 -2
  13. package/components/ui-description-item/ui-description-item.html +1 -1
  14. package/components/ui-description-list/ui-description-list.html +2 -0
  15. package/components/ui-dialog/ui-dialog.html +3 -23
  16. package/components/ui-disclosure/ui-disclosure.html +2 -2
  17. package/components/ui-editor-insert-table-grid/ui-editor-insert-table-grid.html +2 -2
  18. package/components/ui-editor-mention-menu/ui-editor-mention-menu.html +3 -3
  19. package/components/ui-editor-slash-menu/ui-editor-slash-menu.html +4 -4
  20. package/components/ui-editor-slash-menu-item/ui-editor-slash-menu-item.html +6 -1
  21. package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.html +2 -2
  22. package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.html +4 -4
  23. package/components/ui-editor-toolbar/ui-editor-toolbar.html +5 -5
  24. package/components/ui-floating-action-button/ui-floating-action-button.html +4 -2
  25. package/components/ui-icon-button/ui-icon-button.html +57 -17
  26. package/components/ui-icon-button/ui-icon-button.js +1 -1
  27. package/components/ui-list/ui-list.html +46 -6
  28. package/components/ui-list-item/ui-list-item.html +1 -1
  29. package/components/ui-menu/ui-menu.html +4 -3
  30. package/components/ui-menu/ui-menu.js +9 -3
  31. package/components/ui-menu-item/ui-menu-item.html +43 -6
  32. package/components/ui-meter/ui-meter.html +4 -1
  33. package/components/ui-nav-item/ui-nav-item.html +0 -1
  34. package/components/ui-page-header/ui-page-header.html +1 -0
  35. package/components/ui-popover/ui-popover.html +1 -1
  36. package/components/ui-radio/ui-radio.html +5 -2
  37. package/components/ui-scroll-area/ui-scroll-area.html +9 -14
  38. package/components/ui-scroll-area/ui-scroll-area.js +32 -0
  39. package/components/ui-search-result-row/ui-search-result-row.html +5 -3
  40. package/components/ui-search-shell/ui-search-shell.html +8 -8
  41. package/components/ui-section/ui-section.html +5 -3
  42. package/components/ui-separator/ui-separator.html +2 -2
  43. package/components/ui-sidebar/ui-sidebar.html +2 -2
  44. package/components/ui-spinner/ui-spinner.html +28 -8
  45. package/components/ui-status-message/ui-status-message.html +1 -1
  46. package/components/ui-switch/ui-switch.html +17 -8
  47. package/components/ui-table/ui-table.html +1 -1
  48. package/components/ui-tabs/ui-tabs.html +21 -12
  49. package/components/ui-toast/ui-toast.html +1 -1
  50. package/components/ui-toast-region/ui-toast-region.html +1 -1
  51. package/components/ui-tooltip/ui-tooltip.html +12 -12
  52. package/components/ui-tooltip/ui-tooltip.js +1 -1
  53. package/components/ui-top-bar/ui-top-bar.html +1 -1
  54. package/components/ui-tree/ui-tree.js +4 -1
  55. package/components/ui-tree-item/ui-tree-item.html +2 -1
  56. package/dist/index.js +15 -14
  57. package/editor/chunks/extensions.js +3 -4
  58. package/editor/extensions/index.d.ts +1 -1
  59. package/editor/extensions/preset.d.ts +5 -0
  60. package/package.json +1 -1
  61. package/styles/ui-avatar-group.css +8 -5
  62. package/styles/ui-badge.css +10 -5
  63. package/styles/ui-breadcrumb-item.css +2 -1
  64. package/styles/ui-button.css +19 -25
  65. package/styles/ui-callout.css +3 -1
  66. package/styles/ui-card.css +4 -2
  67. package/styles/ui-checkbox.css +38 -8
  68. package/styles/ui-combobox.css +27 -8
  69. package/styles/ui-context-menu.css +2 -2
  70. package/styles/ui-description-item.css +1 -1
  71. package/styles/ui-description-list.css +2 -0
  72. package/styles/ui-dialog.css +1 -22
  73. package/styles/ui-disclosure.css +2 -2
  74. package/styles/ui-editor-insert-table-grid.css +2 -2
  75. package/styles/ui-editor-mention-menu.css +3 -3
  76. package/styles/ui-editor-slash-menu-item.css +6 -1
  77. package/styles/ui-editor-slash-menu.css +4 -4
  78. package/styles/ui-editor-table-context-menu.css +2 -2
  79. package/styles/ui-editor-table-toolbar.css +4 -4
  80. package/styles/ui-editor-toolbar.css +5 -5
  81. package/styles/ui-floating-action-button.css +3 -1
  82. package/styles/ui-icon-button.css +53 -18
  83. package/styles/ui-list-item.css +1 -1
  84. package/styles/ui-list.css +41 -6
  85. package/styles/ui-menu-item.css +43 -5
  86. package/styles/ui-menu.css +3 -3
  87. package/styles/ui-meter.css +4 -1
  88. package/styles/ui-nav-item.css +0 -1
  89. package/styles/ui-page-header.css +1 -0
  90. package/styles/ui-popover.css +1 -1
  91. package/styles/ui-radio.css +5 -2
  92. package/styles/ui-scroll-area.css +10 -16
  93. package/styles/ui-search-result-row.css +3 -2
  94. package/styles/ui-search-shell.css +7 -7
  95. package/styles/ui-section.css +5 -3
  96. package/styles/ui-separator.css +2 -2
  97. package/styles/ui-sidebar.css +2 -2
  98. package/styles/ui-spinner.css +27 -6
  99. package/styles/ui-status-message.css +1 -1
  100. package/styles/ui-switch.css +17 -8
  101. package/styles/ui-table.css +1 -1
  102. package/styles/ui-tabs.css +60 -51
  103. package/styles/ui-toast-region.css +1 -1
  104. package/styles/ui-toast.css +1 -1
  105. package/styles/ui-tooltip.css +12 -12
  106. package/styles/ui-top-bar.css +1 -1
  107. package/styles/ui-tree-item.css +2 -1
  108. package/theme-dark.css +4 -4
  109. package/theme-light.css +3 -3
  110. package/tokens.css +9 -6
  111. package/vanilla/UiButton.d.ts +1 -0
  112. package/vanilla/UiButton.js +17 -19
  113. package/vanilla/UiCombobox.js +162 -159
  114. package/vanilla/UiDialog.js +2 -2
  115. package/vanilla/UiIconButton.d.ts +1 -0
  116. package/vanilla/UiIconButton.js +1 -4
  117. package/vanilla/UiList.d.ts +3 -1
  118. package/vanilla/UiList.js +36 -19
  119. package/vanilla/UiMenu.d.ts +1 -0
  120. package/vanilla/UiMenu.js +1 -1
  121. package/vanilla/UiMenuItem.js +10 -13
  122. package/vanilla/UiScrollArea.js +11 -6
  123. package/vanilla/UiSearchShell.js +2 -2
  124. package/vanilla/UiSpinner.js +2 -4
  125. package/vue/UiAvatarGroup.vue +8 -5
  126. package/vue/UiBadge.vue +10 -5
  127. package/vue/UiBreadcrumbItem.vue +2 -1
  128. package/vue/UiButton.d.ts +2 -0
  129. package/vue/UiButton.vue +31 -28
  130. package/vue/UiCallout.vue +3 -2
  131. package/vue/UiCard.vue +4 -2
  132. package/vue/UiCheckbox.vue +36 -8
  133. package/vue/UiCombobox.d.ts +1 -1
  134. package/vue/UiCombobox.vue +55 -35
  135. package/vue/UiContextMenu.vue +2 -2
  136. package/vue/UiDescriptionItem.vue +1 -1
  137. package/vue/UiDescriptionList.vue +2 -0
  138. package/vue/UiDialog.d.ts +3 -3
  139. package/vue/UiDialog.vue +3 -27
  140. package/vue/UiDisclosure.vue +2 -2
  141. package/vue/UiEditorInsertTableGrid.vue +2 -2
  142. package/vue/UiEditorMentionMenu.d.ts +1 -1
  143. package/vue/UiEditorMentionMenu.vue +4 -3
  144. package/vue/UiEditorSlashMenu.vue +6 -4
  145. package/vue/UiEditorSlashMenuItem.vue +6 -1
  146. package/vue/UiEditorTableContextMenu.vue +2 -2
  147. package/vue/UiEditorTableToolbar.vue +4 -4
  148. package/vue/UiEditorToolbar.vue +5 -5
  149. package/vue/UiFloatingActionButton.vue +3 -1
  150. package/vue/UiIconButton.d.ts +2 -0
  151. package/vue/UiIconButton.vue +61 -19
  152. package/vue/UiList.d.ts +7 -1
  153. package/vue/UiList.vue +57 -6
  154. package/vue/UiListItem.vue +1 -1
  155. package/vue/UiMenu.d.ts +2 -0
  156. package/vue/UiMenu.vue +6 -3
  157. package/vue/UiMenuItem.d.ts +3 -3
  158. package/vue/UiMenuItem.vue +47 -7
  159. package/vue/UiMeter.vue +4 -1
  160. package/vue/UiNavItem.vue +0 -1
  161. package/vue/UiPageHeader.vue +1 -0
  162. package/vue/UiPopover.vue +1 -1
  163. package/vue/UiRadio.vue +5 -2
  164. package/vue/UiScrollArea.vue +24 -18
  165. package/vue/UiSearchResultRow.vue +3 -2
  166. package/vue/UiSearchShell.vue +8 -8
  167. package/vue/UiSection.vue +5 -3
  168. package/vue/UiSeparator.vue +2 -2
  169. package/vue/UiSidebar.vue +2 -2
  170. package/vue/UiSpinner.vue +28 -7
  171. package/vue/UiStatusMessage.vue +1 -1
  172. package/vue/UiSwitch.vue +20 -9
  173. package/vue/UiTable.vue +1 -1
  174. package/vue/UiTabs.vue +25 -12
  175. package/vue/UiToast.vue +1 -1
  176. package/vue/UiToastRegion.vue +1 -1
  177. package/vue/UiTooltip.vue +12 -12
  178. package/vue/UiTopBar.vue +1 -1
  179. package/vue/UiTreeItem.vue +2 -1
  180. package/vue/chunks/UiAvatarGroup.js +1 -1
  181. package/vue/chunks/UiBadge.js +1 -1
  182. package/vue/chunks/UiBreadcrumbItem.js +1 -1
  183. package/vue/chunks/UiButton.js +28 -23
  184. package/vue/chunks/UiCallout.js +1 -1
  185. package/vue/chunks/UiCard.js +1 -1
  186. package/vue/chunks/UiCheckbox.js +1 -1
  187. package/vue/chunks/UiCombobox.js +80 -77
  188. package/vue/chunks/UiContextMenu.js +1 -1
  189. package/vue/chunks/UiDescriptionItem.js +1 -1
  190. package/vue/chunks/UiDescriptionList.js +1 -1
  191. package/vue/chunks/UiDialog.js +7 -4
  192. package/vue/chunks/UiDisclosure.js +1 -1
  193. package/vue/chunks/UiEditorInsertTableGrid.js +1 -1
  194. package/vue/chunks/UiEditorMentionMenu.js +1 -1
  195. package/vue/chunks/UiEditorSlashMenu.js +1 -1
  196. package/vue/chunks/UiEditorSlashMenuItem.js +1 -1
  197. package/vue/chunks/UiEditorTableContextMenu.js +1 -1
  198. package/vue/chunks/UiEditorTableToolbar.js +1 -1
  199. package/vue/chunks/UiEditorToolbar.js +1 -1
  200. package/vue/chunks/UiFloatingActionButton.js +1 -1
  201. package/vue/chunks/UiIconButton.js +13 -8
  202. package/vue/chunks/UiList.js +17 -5
  203. package/vue/chunks/UiListItem.js +1 -1
  204. package/vue/chunks/UiMenu.js +10 -2
  205. package/vue/chunks/UiMenuItem.js +1 -4
  206. package/vue/chunks/UiMeter.js +1 -1
  207. package/vue/chunks/UiNavItem.js +1 -1
  208. package/vue/chunks/UiPageHeader.js +1 -1
  209. package/vue/chunks/UiPopover.js +1 -1
  210. package/vue/chunks/UiRadio.js +1 -1
  211. package/vue/chunks/UiScrollArea.js +22 -3
  212. package/vue/chunks/UiSearchResultRow.js +1 -1
  213. package/vue/chunks/UiSearchShell.js +2 -2
  214. package/vue/chunks/UiSection.js +1 -1
  215. package/vue/chunks/UiSeparator.js +1 -1
  216. package/vue/chunks/UiSidebar.js +1 -1
  217. package/vue/chunks/UiSpinner.js +7 -5
  218. package/vue/chunks/UiStatusMessage.js +1 -1
  219. package/vue/chunks/UiSwitch.js +1 -1
  220. package/vue/chunks/UiTable.js +1 -1
  221. package/vue/chunks/UiTabs.js +1 -1
  222. package/vue/chunks/UiToast.js +1 -1
  223. package/vue/chunks/UiToastRegion.js +1 -1
  224. package/vue/chunks/UiTooltip.js +1 -1
  225. package/vue/chunks/UiTopBar.js +1 -1
  226. package/vue/chunks/UiTreeItem.js +1 -1
  227. package/vue/components.css +1238 -1032
  228. package/vue/editor/LoomaEditor.d.ts +12 -1
  229. package/vue/editor/index.js +7 -1
  230. package/vue/index.js +1 -1
@@ -5,7 +5,7 @@ import { Decoration, DecorationSet } from "@tiptap/pm/view";
5
5
  import { history, redo, undo } from "@tiptap/pm/history";
6
6
  import { dropCursor } from "@tiptap/pm/dropcursor";
7
7
  import { gapCursor } from "@tiptap/pm/gapcursor";
8
- import { common, createLowlight } from "lowlight";
8
+ import { createLowlight } from "lowlight";
9
9
  import { DOMParser, Node as Node$2, Slice } from "@tiptap/pm/model";
10
10
  import MarkdownIt from "markdown-it";
11
11
  import { CellSelection, TableMap, addColumn, addColumnAfter, addColumnBefore, addRow, addRowAfter, addRowBefore, cellAround, columnResizing, deleteCellSelection, deleteColumn, deleteRow, deleteTable, fixTables, goToNextCell, mergeCells, moveTableColumn, moveTableRow, setCellAttr, splitCell, tableEditing, toggleHeader, toggleHeaderCell } from "@tiptap/pm/tables";
@@ -9206,7 +9206,6 @@ var StoredOnlyHighlight = Highlight.extend({
9206
9206
  addInputRules: () => [],
9207
9207
  addPasteRules: () => []
9208
9208
  });
9209
- var lowlight = createLowlight(common);
9210
9209
  /**
9211
9210
  * Complete Looma table schema as one Tiptap extension.
9212
9211
  * Use this in presets that want table, row, header, and cell nodes to remain an
@@ -9246,7 +9245,7 @@ function getLoomaTableExtensions() {
9246
9245
  * framework's Tiptap editor hook.
9247
9246
  */
9248
9247
  function getDefaultEditorExtensions(options = {}) {
9249
- const { placeholder = "Type “/” for commands, or start writing…", linkOpenOnClick = false, imageInline = false, mention = createLoomaMentionExtension(), disableHighlight = false } = options;
9248
+ const { placeholder = "Type “/” for commands, or start writing…", linkOpenOnClick = false, imageInline = false, mention = createLoomaMentionExtension(), disableHighlight = false, codeLanguages } = options;
9250
9249
  return [
9251
9250
  Document,
9252
9251
  Paragraph,
@@ -9284,7 +9283,7 @@ function getDefaultEditorExtensions(options = {}) {
9284
9283
  (disableHighlight ? StoredOnlyHighlight : Highlight).configure({ multicolor: false }),
9285
9284
  Code,
9286
9285
  LoomaSmartPaste,
9287
- CodeBlockLowlight.configure({ lowlight }),
9286
+ CodeBlockLowlight.configure({ lowlight: createLowlight(codeLanguages) }),
9288
9287
  Typography,
9289
9288
  Placeholder.configure({
9290
9289
  placeholder: ({ node }) => node.type.name === "paragraph" ? placeholder : "",
@@ -9,7 +9,7 @@
9
9
  export { LOOMA_ACTIVE_BLOCK_BLUR_GRACE_MS, LOOMA_ACTIVE_BLOCK_CLASS, LOOMA_ACTIVE_BLOCK_TYPING_IDLE_MS, LoomaActiveBlock, LoomaActiveBlockPluginKey, } from "./active-block.js";
10
10
  export { LoomaCallout, LOOMA_CALLOUT_TONES, type LoomaCalloutTone, } from "./callout.js";
11
11
  export { LoomaChip, LOOMA_CHIP_COLORS, normalizeLoomaChipColor, type LoomaChipColor } from "./chip.js";
12
- export { getDefaultEditorExtensions, getLoomaTableExtensions, LoomaTableKit, type DefaultEditorExtensionsOptions, } from "./preset.js";
12
+ export { getDefaultEditorExtensions, getLoomaTableExtensions, LoomaTableKit, type DefaultEditorExtensionsOptions, type LoomaCodeLanguages, } from "./preset.js";
13
13
  export { LoomaSmartPaste } from "./smart-paste.js";
14
14
  export { getActiveTableUiState, handleTableAction, handleTableOverlayAction, insertTableAtRange, normalizeActiveTableColumnWidths, shouldShowTextFormattingToolbar, type ActiveTableUiState, type InsertTableAtRangeOptions, type TableActionCapabilities, } from "./table-commands.js";
15
15
  export { LoomaTable, getActiveTableCellAlignment, getActiveTableCellBackground, LoomaTableCell, LoomaTableHeader, setActiveTableCellAlignment, setActiveTableCellBackground, TABLE_CELL_BACKGROUND_PRESETS, type TableCellAlignment, type TableCellBackground, } from "./table-formatting.js";
@@ -3,6 +3,9 @@
3
3
  * Uses the Vanilla JS Tiptap API; apps provide @tiptap/core and Looma ships the preset extensions.
4
4
  */
5
5
  import { type AnyExtension } from "@tiptap/core";
6
+ import { createLowlight } from "lowlight";
7
+ /** Grammars supplied by the host; importing a language remains the host's choice. */
8
+ export type LoomaCodeLanguages = NonNullable<Parameters<typeof createLowlight>[0]>;
6
9
  /**
7
10
  * Deliberate policy knobs in Looma's default extension set.
8
11
  * Consumers needing different schemas should compose an explicit Tiptap list
@@ -24,6 +27,8 @@ export interface DefaultEditorExtensionsOptions {
24
27
  * and render. Use it when the application reserves highlighting for itself.
25
28
  */
26
29
  disableHighlight?: boolean;
30
+ /** Code block grammars to register. None are loaded by default. */
31
+ codeLanguages?: LoomaCodeLanguages;
27
32
  }
28
33
  /**
29
34
  * Complete Looma table schema as one Tiptap extension.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadlabs/looma",
3
- "version": "0.16.5",
3
+ "version": "0.17.1",
4
4
  "type": "module",
5
5
  "description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
6
6
  "license": "MIT",
@@ -15,10 +15,9 @@
15
15
  --_ui-avatar-group-overlap-shadow: var(--ui-avatar-group-overlap-shadow);
16
16
  --_ui-avatar-group-edge-ring: var(--ui-avatar-group-edge-ring);
17
17
 
18
- /* Each avatar is ringed in the surface colour, so where one overlaps the next it reads as a
19
- * whole circle set on top, not a shape cut into the one beneath. */
20
- --_overlap-shadow: 0 0 0 0 transparent;
21
- --_edge-ring: 0 0 0 2px var(--ui-surface);
18
+ /* A one-pixel shadow on the leading edge separates overlapping circles without cutting
19
+ * a white gap out of the avatar underneath. */
20
+ --_overlap-shadow: -1px 0 0 0 rgb(0 0 0 / 0.22);
22
21
 
23
22
  display: flex;
24
23
  align-items: center;
@@ -29,6 +28,10 @@
29
28
  /* Overlap and the separating shadow are applied by the controller: slotted avatars are nested
30
29
  * component roots outside this style scope. */
31
30
 
31
+ :scope:dir(rtl) {
32
+ --_overlap-shadow: 1px 0 0 0 rgb(0 0 0 / 0.22);
33
+ }
34
+
32
35
  .overflow {
33
36
  margin-inline-start: -0.5rem;
34
37
  display: inline-flex;
@@ -42,7 +45,7 @@
42
45
  color: var(--ui-text-primary);
43
46
  box-shadow:
44
47
  var(--_ui-avatar-group-overlap-shadow, var(--_overlap-shadow)),
45
- var(--_ui-avatar-group-edge-ring, var(--_edge-ring));
48
+ var(--_ui-avatar-group-edge-ring, 0 0 0 0 transparent);
46
49
  font: inherit;
47
50
  font-size: var(--ui-font-size-xs);
48
51
  font-weight: 600;
@@ -123,27 +123,32 @@
123
123
  }
124
124
 
125
125
  :scope[data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=accent"] {
126
- --_badge-surface: var(--ui-accent-soft);
126
+ --_badge-surface: color-mix(in srgb, var(--ui-accent-solid) 22%, var(--ui-surface-default));
127
+ --_badge-border: color-mix(in srgb, var(--ui-accent-solid) 28%, var(--ui-surface-default));
127
128
  --_badge-text: var(--ui-accent-subtle-text, var(--ui-accent-solid));
128
129
  }
129
130
 
130
131
  :scope[data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=danger"] {
131
- --_badge-surface: var(--ui-danger-soft);
132
+ --_badge-surface: color-mix(in srgb, var(--ui-danger-solid) 22%, var(--ui-surface-default));
133
+ --_badge-border: color-mix(in srgb, var(--ui-danger-solid) 28%, var(--ui-surface-default));
132
134
  --_badge-text: var(--ui-danger-subtle-text, var(--ui-danger-solid));
133
135
  }
134
136
 
135
137
  :scope[data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=success"] {
136
- --_badge-surface: var(--ui-success-soft);
138
+ --_badge-surface: color-mix(in srgb, var(--ui-success-solid) 22%, var(--ui-surface-default));
139
+ --_badge-border: color-mix(in srgb, var(--ui-success-solid) 28%, var(--ui-surface-default));
137
140
  --_badge-text: var(--ui-success-subtle-text, var(--ui-success-solid));
138
141
  }
139
142
 
140
143
  :scope[data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=warning"] {
141
- --_badge-surface: var(--ui-warning-soft);
144
+ --_badge-surface: color-mix(in srgb, var(--ui-warning-solid) 22%, var(--ui-surface-default));
145
+ --_badge-border: color-mix(in srgb, var(--ui-warning-solid) 28%, var(--ui-surface-default));
142
146
  --_badge-text: var(--ui-warning-subtle-text, var(--ui-warning-solid));
143
147
  }
144
148
 
145
149
  :scope[data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=info"] {
146
- --_badge-surface: var(--ui-info-soft);
150
+ --_badge-surface: color-mix(in srgb, var(--ui-info-solid) 22%, var(--ui-surface-default));
151
+ --_badge-border: color-mix(in srgb, var(--ui-info-solid) 28%, var(--ui-surface-default));
147
152
  --_badge-text: var(--ui-info-subtle-text, var(--ui-info-solid));
148
153
  }
149
154
 
@@ -7,12 +7,13 @@
7
7
  align-items: center;
8
8
  gap: var(--ui-space-2);
9
9
  min-inline-size: 0;
10
+ margin: 0;
10
11
  }
11
12
 
12
13
  .separator {
13
14
  display: inline-flex;
14
15
  color: var(--ui-text-muted);
15
- font-size: var(--ui-font-size-xs);
16
+ font-size: var(--ui-font-size-sm);
16
17
  }
17
18
 
18
19
  :scope:first-child .separator {
@@ -127,12 +127,15 @@
127
127
  background-color var(--ui-motion-fast) var(--ui-motion-ease),
128
128
  border-color var(--ui-motion-fast) var(--ui-motion-ease),
129
129
  color var(--ui-motion-fast) var(--ui-motion-ease),
130
- box-shadow var(--ui-motion-fast) var(--ui-motion-ease);
130
+ box-shadow var(--ui-motion-base) var(--ui-motion-ease);
131
131
  margin: 0;
132
132
  }
133
133
 
134
- .pending-spinner {
134
+ .spinner-wrap {
135
+ display: inline-flex;
136
+ flex: none;
135
137
  margin-inline-end: var(--ui-space-2);
138
+ vertical-align: middle;
136
139
  }
137
140
 
138
141
  @supports (text-box-trim: trim-both) {
@@ -262,12 +265,12 @@
262
265
  var(--ui-focus-halo);
263
266
  }
264
267
 
265
- /* Disabled keeps the shape and washes out the rest: every variant keeps its own structure, so a
266
- disabled outline is still an outline and a disabled ghost still has no edge. One filter fades
267
- fill, border, and text together (--ui-disabled-filter), and the theme decides which way is
268
- toward the page. The highlight and shadow go, because nothing that cannot be pressed should
269
- look raised. */
270
- :scope:is(:disabled, [aria-disabled="true"]) {
268
+ /* A loading action stays visually active; only an explicitly disabled action takes the
269
+ neutral disabled palette. Its flat surface and muted ink make the state unambiguous. */
270
+ :scope:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])) {
271
+ border-color: var(--ui-disabled-border);
272
+ background-color: var(--ui-disabled-surface);
273
+ color: var(--ui-disabled-text);
271
274
  filter: var(--ui-button-disabled-filter, var(--ui-disabled-filter));
272
275
  opacity: var(--ui-button-disabled-opacity, 1);
273
276
  cursor: not-allowed;
@@ -275,16 +278,13 @@
275
278
  box-shadow: none;
276
279
  }
277
280
 
278
- :scope[data-ui-button-state~="pending"]:focus-visible {
281
+ :is(:scope[data-ui-button-state~="loading"], :scope[data-ui-button-state~="pending"]):focus-visible {
279
282
  box-shadow: var(--ui-focus-halo);
280
283
  }
281
284
 
282
- /* Ghost has no hover to fall back on, so disabled is the one state it has to state outright:
283
- it takes a surface rather than reading as plain text. The surface is a wash of the faded tone,
284
- the way hover washes the live one, so it stays light in every tone. An opaque mix toward the
285
- hue came out a mid-grey slab for neutral, whose hue is the ink: louder than the enabled button. */
286
- :scope[data-ui-button-state~="variant=ghost"]:is(:disabled, [aria-disabled="true"]) {
287
- background-color: oklch(from var(--_tone) l c h / 14%);
285
+ /* Ghost keeps no border, but gains the same neutral surface as other disabled buttons. */
286
+ :scope[data-ui-button-state~="variant=ghost"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])) {
287
+ background-color: var(--ui-disabled-surface);
288
288
  border-color: transparent;
289
289
  }
290
290
 
@@ -343,7 +343,7 @@
343
343
  transform: none;
344
344
  }
345
345
 
346
- :scope[data-ui-button-state~="variant=link"]:is(:disabled, [aria-disabled="true"]) {
346
+ :scope[data-ui-button-state~="variant=link"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])) {
347
347
  background: none;
348
348
  border-color: transparent;
349
349
  }
@@ -378,16 +378,10 @@
378
378
 
379
379
  /* A soft halo that transitions in with the other box-shadow changes, layered on the raised shadow. */
380
380
 
381
- /* Disabled keeps the shape and washes out the rest: every variant keeps its own structure, so a
382
- disabled outline is still an outline and a disabled ghost still has no edge. One filter fades
383
- fill, border, and text together (--ui-disabled-filter), and the theme decides which way is
384
- toward the page. The highlight and shadow go, because nothing that cannot be pressed should
385
- look raised. */
381
+ /* A loading action stays visually active; only an explicitly disabled action takes the
382
+ neutral disabled palette. Its flat surface and muted ink make the state unambiguous. */
386
383
 
387
- /* Ghost has no hover to fall back on, so disabled is the one state it has to state outright:
388
- it takes a surface rather than reading as plain text. The surface is a wash of the faded tone,
389
- the way hover washes the live one, so it stays light in every tone. An opaque mix toward the
390
- hue came out a mid-grey slab for neutral, whose hue is the ink: louder than the enabled button. */
384
+ /* Ghost keeps no border, but gains the same neutral surface as other disabled buttons. */
391
385
 
392
386
  /* The size states outrank :host, so sm is named too, or a small button would stay small. */
393
387
  @media (pointer: coarse) {
@@ -61,7 +61,9 @@
61
61
  gap: var(--ui-callout-gap, calc(var(--ui-space-2) * 0.75));
62
62
  align-items: start;
63
63
  max-width: 100%;
64
- padding: var(--ui-callout-padding-block, var(--ui-space-2)) var(--ui-callout-padding-inline, var(--ui-space-3));
64
+ padding-block: var(--ui-callout-padding-block, var(--ui-space-2));
65
+ padding-inline-start: var(--ui-callout-padding-inline, var(--ui-space-2));
66
+ padding-inline-end: var(--ui-callout-padding-inline, var(--ui-space-3));
65
67
  border: var(--ui-callout-border-width, 1px) solid color-mix(in srgb, var(--ui-callout-border, var(--_callout-border)) 35%, transparent);
66
68
  border-inline-start: var(--ui-callout-leading-border-width, 4px) solid var(--ui-callout-border, var(--_callout-border));
67
69
  border-radius: var(--ui-radius-md);
@@ -9,7 +9,7 @@
9
9
  box-sizing: border-box;
10
10
  min-inline-size: 0;
11
11
  padding: var(--ui-space-5);
12
- border: 1px solid var(--ui-border-default);
12
+ border: 1px solid var(--ui-border-strong);
13
13
  border-radius: var(--ui-radius-lg);
14
14
  background: var(--ui-surface-raised);
15
15
  color: var(--ui-text-primary);
@@ -35,7 +35,9 @@
35
35
  }
36
36
 
37
37
  :scope[data-ui-card-state~="tone=danger"] {
38
- border-color: var(--ui-danger);
38
+ border-color: color-mix(in srgb, var(--ui-danger) 45%, var(--ui-border-default));
39
+ border-inline-start: 4px solid var(--ui-danger);
40
+ background: var(--ui-danger-soft);
39
41
  }
40
42
 
41
43
  /* A component that sets its display still honours the hidden attribute on its root. */
@@ -11,6 +11,20 @@
11
11
  syntax: "*";
12
12
  inherits: false;
13
13
  }
14
+ @keyframes ui-checkbox-check {
15
+ from {
16
+ opacity: 0;
17
+ transform: translate(0.07rem, -0.09rem) rotate(45deg) scale(0.55);
18
+ }
19
+ 65% {
20
+ opacity: 1;
21
+ transform: translate(0.07rem, -0.09rem) rotate(45deg) scale(1.12);
22
+ }
23
+ to {
24
+ opacity: 1;
25
+ transform: translate(0.07rem, -0.09rem) rotate(45deg) scale(1);
26
+ }
27
+ }
14
28
  @scope ([data-component~="ui-checkbox"]) to ([data-component], [data-slotted]) {
15
29
  /* This component's hooks style the element they are set on, and never a nested one. */
16
30
 
@@ -58,10 +72,10 @@
58
72
  inline-size: var(--_ui-checkbox-size, 1.125rem);
59
73
  block-size: var(--_ui-checkbox-size, 1.125rem);
60
74
  margin: 0.125em 0 0;
61
- border: 1px solid var(--ui-control-border-hover, var(--ui-border-strong));
75
+ border: 1px solid var(--ui-control-border, var(--ui-border-strong));
62
76
  border-radius: var(--ui-radius-sm);
63
77
  background: var(--ui-control-surface, var(--ui-surface-default));
64
- box-shadow: inset 0 1px 2px color-mix(in srgb, var(--ui-text-primary) 8%, transparent);
78
+ box-shadow: var(--ui-control-inset);
65
79
  cursor: pointer;
66
80
  transition:
67
81
  background-color var(--ui-motion-fast) var(--ui-motion-ease),
@@ -73,28 +87,30 @@
73
87
  content: "";
74
88
  position: absolute;
75
89
  opacity: 0;
90
+ transition: opacity 120ms var(--ui-motion-ease);
76
91
  }
77
92
 
78
93
  input:checked,
79
94
  input:indeterminate {
80
95
  border-color: var(--ui-accent-solid);
81
96
  background: var(--ui-accent-solid);
82
- box-shadow: inset 0 1px 2px color-mix(in srgb, #000 16%, transparent);
97
+ box-shadow: var(--ui-control-inset);
83
98
  }
84
99
 
85
100
  /* Centre the tick's box, then lift it: a rotated L's ink sits ~0.11rem below its box centre. */
86
101
  input:checked::after {
87
102
  inset: 0;
88
103
  margin: auto;
89
- inline-size: 0.32rem;
90
- block-size: 0.58rem;
104
+ inline-size: 0.28rem;
105
+ block-size: 0.5rem;
91
106
  /* Longhands, not `border: solid var(...)`: lowering drops a shorthand that omits a
92
107
  component, which left the tick with no style and no colour. */
93
108
  border-style: solid;
94
109
  border-color: var(--ui-text-on-accent);
95
110
  border-width: 0 0.125rem 0.125rem 0;
96
111
  opacity: 1;
97
- transform: translateY(-0.11rem) rotate(45deg);
112
+ transform: translate(0.07rem, -0.09rem) rotate(45deg);
113
+ animation: ui-checkbox-check 180ms var(--ui-motion-ease-out, cubic-bezier(0.16, 1, 0.3, 1)) both;
98
114
  }
99
115
 
100
116
  input:indeterminate::after {
@@ -106,6 +122,13 @@
106
122
  transform: translateY(-50%);
107
123
  }
108
124
 
125
+ @media (prefers-reduced-motion: reduce) {
126
+ input::after {
127
+ transition: none;
128
+ animation: none;
129
+ }
130
+ }
131
+
109
132
  input:hover:enabled {
110
133
  border-color: var(--ui-accent-solid);
111
134
  }
@@ -123,9 +146,13 @@
123
146
  color: var(--ui-disabled-text);
124
147
  cursor: not-allowed;
125
148
  }
149
+ :scope[data-ui-checkbox-state~="disabled"] .description {
150
+ color: var(--ui-disabled-text);
151
+ }
126
152
  :scope[data-ui-checkbox-state~="disabled"] input {
127
- border-color: var(--ui-border-default);
128
- background: var(--ui-control-surface-disabled, var(--ui-surface-muted));
153
+ border-color: var(--ui-disabled-border);
154
+ background: var(--ui-disabled-surface);
155
+ box-shadow: none;
129
156
  cursor: not-allowed;
130
157
  }
131
158
 
@@ -172,6 +199,9 @@
172
199
 
173
200
  /* Centre the tick's box, then lift it: a rotated L's ink sits ~0.11rem below its box centre. */
174
201
 
202
+ @media (prefers-reduced-motion: reduce) {
203
+ }
204
+
175
205
  /* A sized choice keeps its box and aligns instead: the label takes that size's field type size,
176
206
  and the first line centres in that control height, so the label shares a row's baseline.
177
207
  Multi-line labels and descriptions still grow downward from that first line. */
@@ -121,6 +121,11 @@
121
121
  var(--ui-control-inset),
122
122
  var(--ui-control-focus-halo-shadow);
123
123
  }
124
+ .entry {
125
+ display: flex;
126
+ flex: 1 1 auto;
127
+ min-inline-size: 0;
128
+ }
124
129
  /* A ghost icon button: the affordance is the mark, not a box around it. */
125
130
  .help {
126
131
  flex: none;
@@ -240,7 +245,7 @@
240
245
  overflow: auto;
241
246
  margin: 0;
242
247
  padding: var(--ui-space-1);
243
- border: 1px solid var(--_ui-combobox-popup-border, var(--ui-overlay-border, var(--ui-border-default)));
248
+ border: 1px solid var(--_ui-combobox-popup-border, var(--ui-overlay-border, var(--ui-border-strong)));
244
249
  border-radius: var(--_ui-combobox-popup-radius, var(--ui-overlay-radius, var(--ui-radius-md)));
245
250
  background: var(--_ui-combobox-popup-surface, var(--ui-overlay-surface, var(--ui-surface-elevated)));
246
251
  color: var(--ui-text-primary);
@@ -264,6 +269,10 @@
264
269
  color: var(--ui-disabled-text);
265
270
  cursor: not-allowed;
266
271
  }
272
+ .option[aria-disabled="true"] .primary,
273
+ .option[aria-disabled="true"] .secondary {
274
+ color: var(--ui-disabled-text);
275
+ }
267
276
  .primary {
268
277
  display: block;
269
278
  color: var(--_ui-combobox-option-text, var(--ui-text-primary));
@@ -360,21 +369,29 @@
360
369
  );
361
370
  }
362
371
 
363
- /* Multiple mode: chips wrap before the cursor on one flexible field line. */
372
+ /* Multiple mode keeps one control height. Chips and the input scroll within the entry,
373
+ while the clear and disclosure controls remain fixed at the end of the field. */
364
374
  :scope[data-ui-combobox-state~="multiple"] .field {
365
- flex-wrap: wrap;
366
375
  align-items: center;
367
- gap: var(--ui-space-1);
368
376
  min-block-size: var(--_ui-combobox-item-min-block-size, 2.5rem);
369
377
  padding: var(--ui-space-1);
370
378
  }
379
+ :scope[data-ui-combobox-state~="multiple"] .entry {
380
+ align-items: center;
381
+ gap: var(--ui-space-1);
382
+ overflow-x: auto;
383
+ scrollbar-width: none;
384
+ }
385
+ :scope[data-ui-combobox-state~="multiple"] .entry::-webkit-scrollbar {
386
+ display: none;
387
+ }
371
388
  :scope[data-ui-combobox-state~="multiple"] input {
372
389
  flex: 1 0 var(--_ui-combobox-item-input-min-inline-size, 5rem);
373
390
  width: auto;
374
391
  min-block-size: 1.75rem;
375
392
  padding: var(--ui-space-0-5) var(--ui-space-1);
376
393
  }
377
- /* A small multiple field starts at the small control height; chosen items still wrap it taller. */
394
+ /* Size variants keep their control height as selections are added. */
378
395
  :scope[data-ui-combobox-state~="multiple"]:scope[data-ui-combobox-state~="size=sm"] .field {
379
396
  min-block-size: 0;
380
397
  padding: var(--ui-space-0-5);
@@ -393,6 +410,7 @@
393
410
  .item {
394
411
  appearance: none;
395
412
  display: inline-flex;
413
+ flex: none;
396
414
  min-inline-size: 0;
397
415
  max-inline-size: min(100%, var(--_ui-combobox-item-item-max-inline-size, 12rem));
398
416
  overflow: hidden;
@@ -409,7 +427,7 @@
409
427
  outline-offset: 1px;
410
428
  }
411
429
  .item:disabled {
412
- opacity: 0.6;
430
+ color: var(--ui-disabled-text);
413
431
  }
414
432
 
415
433
  /* A component that sets its display still honours the hidden attribute on its root. */
@@ -434,8 +452,9 @@
434
452
  before anything is picked. aria-selected is the state; this draws it.
435
453
  Longhands, not shorthands: lowering drops a shorthand that omits a component. */
436
454
 
437
- /* Multiple mode: chips wrap before the cursor on one flexible field line. */
438
- /* A small multiple field starts at the small control height; chosen items still wrap it taller. */
455
+ /* Multiple mode keeps one control height. Chips and the input scroll within the entry,
456
+ while the clear and disclosure controls remain fixed at the end of the field. */
457
+ /* Size variants keep their control height as selections are added. */
439
458
  /* A large multiple field starts at the large control height, as sm starts at the small one. */
440
459
 
441
460
  /* A component that sets its display still honours the hidden attribute on its root. */
@@ -42,7 +42,7 @@
42
42
  box-sizing: border-box;
43
43
  padding: var(--ui-space-1);
44
44
  background: var(--_ui-context-menu-surface, var(--ui-overlay-surface, var(--ui-surface-elevated)));
45
- border: 1px solid var(--_ui-context-menu-border, var(--ui-overlay-border, var(--ui-border-default)));
45
+ border: 1px solid var(--_ui-context-menu-border, var(--ui-overlay-border, var(--ui-border-strong)));
46
46
  border-radius: var(--_ui-context-menu-radius, var(--ui-overlay-radius, var(--ui-radius-lg)));
47
47
  box-shadow: var(--_ui-context-menu-shadow, var(--ui-overlay-shadow, var(--ui-elevation-overlay, var(--ui-shadow-lg))));
48
48
  outline: 0;
@@ -63,7 +63,7 @@
63
63
  block-size: 0;
64
64
  margin: var(--ui-space-1) 0;
65
65
  border: 0;
66
- border-block-start: 1px solid var(--ui-border-default);
66
+ border-block-start: 1px solid var(--ui-border-divider);
67
67
  }
68
68
 
69
69
  .menu:popover-open {
@@ -12,7 +12,7 @@
12
12
  padding: var(--_ui-description-padding, 0);
13
13
  border-width: var(--_ui-description-border-width, 0);
14
14
  border-style: solid;
15
- border-color: var(--ui-border-default);
15
+ border-color: var(--_ui-description-border-color, var(--ui-border-default));
16
16
  border-radius: var(--ui-radius-md);
17
17
  font-size: var(--ui-font-size-sm);
18
18
  }
@@ -33,6 +33,7 @@
33
33
  than that many fit. */
34
34
  :scope[data-ui-description-list-state~="layout=grid"],
35
35
  :scope[data-ui-description-list-state~="layout=tiles"] {
36
+ inline-size: 100%;
36
37
  grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--_track)), 1fr));
37
38
  }
38
39
 
@@ -41,6 +42,7 @@
41
42
  --_ui-description-value-size: var(--ui-font-size-lg);
42
43
  --_ui-description-padding: var(--_tile-padding);
43
44
  --_ui-description-border-width: 1px;
45
+ --_ui-description-border-color: var(--ui-border-strong);
44
46
  --_gap: var(--ui-space-3);
45
47
  --_gap-compact: var(--ui-space-2);
46
48
  --_column-gap: var(--_gap);
@@ -59,7 +59,7 @@
59
59
  overflow: hidden;
60
60
  flex-direction: column;
61
61
  background: var(--ui-dialog-surface, var(--ui-overlay-surface, var(--ui-surface-elevated)));
62
- border: 1px solid var(--ui-dialog-border, var(--ui-overlay-border, var(--ui-border-default)));
62
+ border: 1px solid var(--ui-dialog-border, var(--ui-overlay-border, var(--ui-border-strong)));
63
63
  border-radius: var(--ui-dialog-radius, var(--ui-overlay-radius, var(--ui-radius-dialog)));
64
64
  box-shadow: var(--ui-dialog-shadow, var(--ui-overlay-shadow, var(--ui-elevation-dialog, var(--ui-shadow-xl))));
65
65
  visibility: hidden;
@@ -111,7 +111,6 @@
111
111
  gap: var(--ui-space-3);
112
112
  flex: none;
113
113
  padding: var(--ui-space-3) var(--ui-space-3) var(--ui-space-3) var(--ui-space-5);
114
- border-block-end: 1px solid var(--ui-border-default);
115
114
  }
116
115
 
117
116
  /* :host-qualified so page heading rules that reach in cannot outrank the dialog chrome. */
@@ -186,26 +185,7 @@
186
185
  .body {
187
186
  flex: 1 1 auto;
188
187
  min-block-size: 0;
189
- overflow: auto;
190
- overscroll-behavior: contain;
191
188
  padding: var(--ui-space-5);
192
- /* Each edge that hides content fades: the scroll fade every Looma scroller uses (see ui-scroll-area). */
193
- --_ui-scroll-fade-direction: to bottom;
194
- --_ui-scroll-fade-size: var(--ui-scroll-fade-size, 24px);
195
- mask-image: linear-gradient(
196
- var(--_ui-scroll-fade-direction),
197
- transparent,
198
- #000 var(--_ui-scroll-fade-start),
199
- #000 calc(100% - var(--_ui-scroll-fade-end)),
200
- transparent
201
- );
202
- animation: ui-scroll-fade-start linear, ui-scroll-fade-start-hold linear, ui-scroll-fade-end-hold linear, ui-scroll-fade-end linear;
203
- animation-timeline: scroll(self block);
204
- animation-range:
205
- 0 var(--_ui-scroll-fade-size),
206
- var(--_ui-scroll-fade-size) calc(100% + 1px),
207
- -1px calc(100% - var(--_ui-scroll-fade-size)),
208
- calc(100% - var(--_ui-scroll-fade-size)) 100%;
209
189
  }
210
190
 
211
191
  footer {
@@ -215,7 +195,6 @@
215
195
  justify-content: flex-end;
216
196
  gap: var(--ui-space-2);
217
197
  padding: var(--ui-space-3) var(--ui-space-5);
218
- border-block-start: 1px solid var(--ui-border-default);
219
198
  }
220
199
 
221
200
  footer:empty {
@@ -38,7 +38,7 @@
38
38
  display: block;
39
39
  inline-size: 100%;
40
40
  overflow: clip;
41
- border-block-end: 1px solid var(--ui-border-default);
41
+ border-block-end: 1px solid var(--ui-border-divider);
42
42
  color: var(--ui-text-primary);
43
43
  }
44
44
 
@@ -63,7 +63,7 @@
63
63
  }
64
64
 
65
65
  .trigger:hover:not(:disabled) {
66
- background: var(--ui-surface-muted);
66
+ background: color-mix(in srgb, currentColor 6%, transparent);
67
67
  }
68
68
  .trigger:focus-visible {
69
69
  outline: none;
@@ -3,7 +3,7 @@
3
3
  :scope {
4
4
  padding: var(--ui-space-3);
5
5
  background: var(--ui-surface);
6
- border: 1px solid var(--ui-border);
6
+ border: 1px solid var(--ui-border-strong);
7
7
  border-radius: var(--ui-radius-md);
8
8
  box-shadow: var(--ui-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));
9
9
  }
@@ -48,7 +48,7 @@
48
48
  width: 1.25rem;
49
49
  height: 1.25rem;
50
50
  padding: 0;
51
- border: 1px solid var(--ui-border);
51
+ border: 1px solid var(--ui-control-border);
52
52
  border-radius: 2px;
53
53
  background: var(--ui-surface);
54
54
  cursor: pointer;
@@ -9,7 +9,7 @@
9
9
  overflow: hidden;
10
10
  flex-direction: column;
11
11
  background: var(--ui-surface);
12
- border: 1px solid var(--ui-border);
12
+ border: 1px solid var(--ui-border-strong);
13
13
  border-radius: var(--ui-radius-dialog);
14
14
  box-shadow: var(--ui-shadow-lg, 0 8px 24px rgb(0 0 0 / 0.12));
15
15
  }
@@ -21,12 +21,12 @@
21
21
  gap: var(--ui-space-3);
22
22
  padding: var(--ui-space-2) var(--ui-space-3);
23
23
  color: var(--ui-text-secondary);
24
- border-bottom: 1px solid var(--ui-border);
24
+ border-bottom: 1px solid var(--ui-border-divider);
25
25
  font-size: var(--ui-font-size-xs);
26
26
  font-weight: var(--ui-font-semibold);
27
27
  }
28
28
 
29
- .header:not(:has(> *)), .empty:not(:has(> *)) {
29
+ :scope > .header:empty, :scope > .empty:empty {
30
30
  display: none;
31
31
  }
32
32