@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
@@ -45,6 +45,7 @@
45
45
  than that many fit. */
46
46
  :host-state([layout="grid"]),
47
47
  :host-state([layout="tiles"]) {
48
+ inline-size: 100%;
48
49
  grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--_track)), 1fr));
49
50
  }
50
51
 
@@ -53,6 +54,7 @@
53
54
  --_ui-description-value-size: var(--ui-font-size-lg);
54
55
  --_ui-description-padding: var(--_tile-padding);
55
56
  --_ui-description-border-width: 1px;
57
+ --_ui-description-border-color: var(--ui-border-strong);
56
58
  --_gap: var(--ui-space-3);
57
59
  --_gap-compact: var(--ui-space-2);
58
60
  --_column-gap: var(--_gap);
@@ -1,3 +1,4 @@
1
+ <link rel="component" href="../ui-scroll-area/ui-scroll-area.html">
1
2
  <template component="ui-dialog" controller="./ui-dialog.js">
2
3
  <defs>
3
4
  <prop name="open" type="boolean" default="false">Whether the dialog is open initially or when set externally.</prop>
@@ -31,7 +32,7 @@
31
32
  <h2 class="title" $if="label" $value="label"></h2>
32
33
  <button class="close" $ref="close" type="button" aria-label="Close"></button>
33
34
  </header>
34
- <div class="body"><slot></slot></div>
35
+ <ui-scroll-area class="body"><slot></slot></ui-scroll-area>
35
36
  <footer><slot name="actions"></slot></footer>
36
37
  </dialog>
37
38
  <style>
@@ -83,7 +84,7 @@
83
84
  overflow: hidden;
84
85
  flex-direction: column;
85
86
  background: var(--ui-dialog-surface, var(--ui-overlay-surface, var(--ui-surface-elevated)));
86
- border: 1px solid var(--ui-dialog-border, var(--ui-overlay-border, var(--ui-border-default)));
87
+ border: 1px solid var(--ui-dialog-border, var(--ui-overlay-border, var(--ui-border-strong)));
87
88
  border-radius: var(--ui-dialog-radius, var(--ui-overlay-radius, var(--ui-radius-dialog)));
88
89
  box-shadow: var(--ui-dialog-shadow, var(--ui-overlay-shadow, var(--ui-elevation-dialog, var(--ui-shadow-xl))));
89
90
  visibility: hidden;
@@ -135,7 +136,6 @@
135
136
  gap: var(--ui-space-3);
136
137
  flex: none;
137
138
  padding: var(--ui-space-3) var(--ui-space-3) var(--ui-space-3) var(--ui-space-5);
138
- border-block-end: 1px solid var(--ui-border-default);
139
139
  }
140
140
 
141
141
  /* :host-qualified so page heading rules that reach in cannot outrank the dialog chrome. */
@@ -210,26 +210,7 @@
210
210
  .body {
211
211
  flex: 1 1 auto;
212
212
  min-block-size: 0;
213
- overflow: auto;
214
- overscroll-behavior: contain;
215
213
  padding: var(--ui-space-5);
216
- /* Each edge that hides content fades: the scroll fade every Looma scroller uses (see ui-scroll-area). */
217
- --_ui-scroll-fade-direction: to bottom;
218
- --_ui-scroll-fade-size: var(--ui-scroll-fade-size, 24px);
219
- mask-image: linear-gradient(
220
- var(--_ui-scroll-fade-direction),
221
- transparent,
222
- #000 var(--_ui-scroll-fade-start),
223
- #000 calc(100% - var(--_ui-scroll-fade-end)),
224
- transparent
225
- );
226
- animation: ui-scroll-fade-start linear, ui-scroll-fade-start-hold linear, ui-scroll-fade-end-hold linear, ui-scroll-fade-end linear;
227
- animation-timeline: scroll(self block);
228
- animation-range:
229
- 0 var(--_ui-scroll-fade-size),
230
- var(--_ui-scroll-fade-size) calc(100% + 1px),
231
- -1px calc(100% - var(--_ui-scroll-fade-size)),
232
- calc(100% - var(--_ui-scroll-fade-size)) 100%;
233
214
  }
234
215
 
235
216
  footer {
@@ -239,7 +220,6 @@
239
220
  justify-content: flex-end;
240
221
  gap: var(--ui-space-2);
241
222
  padding: var(--ui-space-3) var(--ui-space-5);
242
- border-block-start: 1px solid var(--ui-border-default);
243
223
  }
244
224
 
245
225
  footer:empty {
@@ -73,7 +73,7 @@
73
73
  display: block;
74
74
  inline-size: 100%;
75
75
  overflow: clip;
76
- border-block-end: 1px solid var(--ui-border-default);
76
+ border-block-end: 1px solid var(--ui-border-divider);
77
77
  color: var(--ui-text-primary);
78
78
  }
79
79
 
@@ -98,7 +98,7 @@
98
98
  }
99
99
 
100
100
  .trigger:hover:not(:disabled) {
101
- background: var(--ui-surface-muted);
101
+ background: color-mix(in srgb, currentColor 6%, transparent);
102
102
  }
103
103
  .trigger:focus-visible {
104
104
  outline: none;
@@ -38,7 +38,7 @@
38
38
  :host {
39
39
  padding: var(--ui-space-3);
40
40
  background: var(--ui-surface);
41
- border: 1px solid var(--ui-border);
41
+ border: 1px solid var(--ui-border-strong);
42
42
  border-radius: var(--ui-radius-md);
43
43
  box-shadow: var(--ui-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));
44
44
  }
@@ -83,7 +83,7 @@
83
83
  width: 1.25rem;
84
84
  height: 1.25rem;
85
85
  padding: 0;
86
- border: 1px solid var(--ui-border);
86
+ border: 1px solid var(--ui-control-border);
87
87
  border-radius: 2px;
88
88
  background: var(--ui-surface);
89
89
  cursor: pointer;
@@ -53,7 +53,7 @@
53
53
  overflow: hidden;
54
54
  flex-direction: column;
55
55
  background: var(--ui-surface);
56
- border: 1px solid var(--ui-border);
56
+ border: 1px solid var(--ui-border-strong);
57
57
  border-radius: var(--ui-radius-dialog);
58
58
  box-shadow: var(--ui-shadow-lg, 0 8px 24px rgb(0 0 0 / 0.12));
59
59
  }
@@ -65,12 +65,12 @@
65
65
  gap: var(--ui-space-3);
66
66
  padding: var(--ui-space-2) var(--ui-space-3);
67
67
  color: var(--ui-text-secondary);
68
- border-bottom: 1px solid var(--ui-border);
68
+ border-bottom: 1px solid var(--ui-border-divider);
69
69
  font-size: var(--ui-font-size-xs);
70
70
  font-weight: var(--ui-font-semibold);
71
71
  }
72
72
 
73
- .header:not(:has(> *)), .empty:not(:has(> *)) {
73
+ :host > .header:empty, :host > .empty:empty {
74
74
  display: none;
75
75
  }
76
76
 
@@ -49,7 +49,7 @@
49
49
 
50
50
  :host {
51
51
  background: var(--ui-surface);
52
- border: 1px solid var(--ui-border);
52
+ border: 1px solid var(--ui-border-strong);
53
53
  border-radius: var(--ui-radius-dialog);
54
54
  box-shadow: var(--ui-shadow-lg, 0 8px 24px rgb(0 0 0 / 0.12));
55
55
  overflow: hidden;
@@ -69,7 +69,7 @@
69
69
  align-items: center;
70
70
  gap: var(--ui-space-2);
71
71
  padding: var(--ui-space-3) var(--ui-space-4);
72
- border-bottom: 1px solid var(--ui-border);
72
+ border-bottom: 1px solid var(--ui-border-divider);
73
73
  font-size: var(--ui-font-size-xs);
74
74
  color: var(--ui-text-muted);
75
75
  font-weight: var(--ui-font-semibold);
@@ -77,7 +77,7 @@
77
77
  letter-spacing: 0.05em;
78
78
  }
79
79
 
80
- .header:not(:has(> *)), .footer:not(:has(> *)), .empty:not(:has(> *)) {
80
+ :host > .header:empty, :host > .footer:empty, :host > .empty:empty {
81
81
  display: none;
82
82
  }
83
83
 
@@ -194,7 +194,7 @@
194
194
 
195
195
  .footer {
196
196
  padding: var(--ui-space-2) var(--ui-space-3);
197
- border-top: 1px solid var(--ui-border);
197
+ border-top: 1px solid var(--ui-border-divider);
198
198
  font-size: var(--ui-font-size-xs);
199
199
  color: var(--ui-text-muted);
200
200
  }
@@ -26,9 +26,14 @@
26
26
  background: var(--ui-accent-subtle);
27
27
  }
28
28
  :host[aria-disabled="true"] {
29
- opacity: 0.6;
29
+ background: var(--ui-disabled-surface);
30
30
  cursor: not-allowed;
31
31
  }
32
+ :host[aria-disabled="true"] .title,
33
+ :host[aria-disabled="true"] .description,
34
+ :host[aria-disabled="true"] .icon {
35
+ color: var(--ui-disabled-text);
36
+ }
32
37
 
33
38
  .icon {
34
39
  display: flex;
@@ -68,7 +68,7 @@
68
68
  max-height: min(28rem, calc(100vh - 24px));
69
69
  padding: var(--ui-space-2);
70
70
  background: var(--ui-surface);
71
- border: 1px solid var(--ui-border);
71
+ border: 1px solid var(--ui-border-strong);
72
72
  border-radius: var(--ui-radius-lg);
73
73
  box-shadow: var(--ui-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));
74
74
  display: flex;
@@ -170,7 +170,7 @@
170
170
 
171
171
  .sep {
172
172
  height: 1px;
173
- background: var(--ui-border);
173
+ background: var(--ui-border-divider);
174
174
  margin: var(--ui-space-1) 0;
175
175
  }
176
176
 
@@ -128,7 +128,7 @@
128
128
  gap: var(--ui-space-1);
129
129
  padding: var(--ui-space-1);
130
130
  background: color-mix(in srgb, var(--ui-surface) 94%, transparent);
131
- border: 1px solid var(--ui-border);
131
+ border: 1px solid var(--ui-border-strong);
132
132
  border-radius: calc(var(--ui-radius-md) + 2px);
133
133
  box-shadow: var(--ui-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));
134
134
  backdrop-filter: blur(10px);
@@ -144,7 +144,7 @@
144
144
  .sep {
145
145
  width: 1px;
146
146
  align-self: stretch;
147
- background: var(--ui-border);
147
+ background: var(--ui-border-divider);
148
148
  }
149
149
 
150
150
  .overflow {
@@ -217,7 +217,7 @@
217
217
  min-width: 12rem;
218
218
  padding: var(--ui-space-1);
219
219
  background: var(--ui-surface);
220
- border: 1px solid var(--ui-border);
220
+ border: 1px solid var(--ui-border-strong);
221
221
  border-radius: var(--ui-radius-md);
222
222
  box-shadow: var(--ui-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));
223
223
  display: flex;
@@ -229,7 +229,7 @@
229
229
  .menu-section + .menu-section {
230
230
  margin-top: var(--ui-space-1);
231
231
  padding-top: var(--ui-space-1);
232
- border-top: 1px solid color-mix(in srgb, var(--ui-border) 80%, transparent);
232
+ border-top: 1px solid var(--ui-border-divider);
233
233
  }
234
234
 
235
235
  .menu-heading {
@@ -13,7 +13,7 @@
13
13
  padding: var(--ui-editor-toolbar-padding-block, 6px) var(--ui-editor-toolbar-padding-inline, 12px);
14
14
  min-height: var(--ui-editor-toolbar-min-height, 48px);
15
15
  background: var(--ui-editor-toolbar-surface, var(--ui-surface));
16
- border-bottom: 1px solid var(--ui-editor-toolbar-border, var(--ui-border));
16
+ border-bottom: 1px solid var(--ui-editor-toolbar-border, var(--ui-border-divider));
17
17
  }
18
18
 
19
19
  /* One row, always. When the controls outgrow the space, the row scrolls sideways rather than
@@ -67,7 +67,7 @@
67
67
  :slotted(.divider) {
68
68
  width: 1px;
69
69
  height: 20px;
70
- background: var(--ui-editor-toolbar-divider, var(--ui-border));
70
+ background: var(--ui-editor-toolbar-divider, var(--ui-border-divider));
71
71
  flex-shrink: 0;
72
72
  margin: 0 var(--ui-editor-toolbar-divider-margin, 4px);
73
73
  }
@@ -80,7 +80,7 @@
80
80
  min-height: auto;
81
81
  padding: var(--ui-editor-toolbar-floating-padding, 4px);
82
82
  background: color-mix(in srgb, var(--ui-editor-toolbar-surface, var(--ui-surface)) 96%, transparent);
83
- border: 1px solid var(--ui-editor-toolbar-border, var(--ui-border));
83
+ border: 1px solid var(--ui-editor-toolbar-border, var(--ui-border-strong));
84
84
  border-radius: var(--ui-editor-toolbar-floating-radius, var(--ui-radius-lg));
85
85
  box-shadow: var(--ui-editor-toolbar-floating-shadow, var(--ui-shadow-lg, 0 10px 24px rgb(0 0 0 / 0.12)));
86
86
  backdrop-filter: blur(10px);
@@ -94,7 +94,7 @@
94
94
  left: 0;
95
95
  right: 0;
96
96
  min-height: var(--ui-editor-toolbar-mobile-min-height, 56px);
97
- border-top: 1px solid var(--ui-editor-toolbar-border, var(--ui-border));
97
+ border-top: 1px solid var(--ui-editor-toolbar-border, var(--ui-border-divider));
98
98
  border-bottom: none;
99
99
  box-shadow: var(--ui-editor-toolbar-mobile-shadow, 0 -2px 8px rgb(0 0 0 / 0.06));
100
100
  }
@@ -103,7 +103,7 @@
103
103
  position: relative;
104
104
  inset: auto;
105
105
  min-height: auto;
106
- border: 1px solid var(--ui-editor-toolbar-border, var(--ui-border));
106
+ border: 1px solid var(--ui-editor-toolbar-border, var(--ui-border-strong));
107
107
  border-radius: var(--ui-editor-toolbar-floating-radius, var(--ui-radius-lg));
108
108
  box-shadow: var(--ui-editor-toolbar-floating-shadow, var(--ui-shadow-lg, 0 10px 24px rgb(0 0 0 / 0.12)));
109
109
  }
@@ -1,6 +1,6 @@
1
1
  <template component="ui-floating-action-button">
2
2
  <defs>
3
- <prop name="disabled" type="boolean" default="false">Disables the button, so it cannot be pressed or focused, and fades it to 60% opacity.</prop>
3
+ <prop name="disabled" type="boolean" default="false">Disables the button, so it cannot be pressed or focused, and gives it a flat muted treatment.</prop>
4
4
  <prop name="mobileOnly" type="boolean" default="false"
5
5
  >Hides the button on viewports 768px wide and wider, for a shortcut that only phones need. Make sure the action is reachable another way at those
6
6
  widths.</prop>
@@ -69,7 +69,9 @@
69
69
  }
70
70
 
71
71
  :host:disabled {
72
- opacity: 0.6;
72
+ background: var(--ui-disabled-surface);
73
+ color: var(--ui-disabled-text);
74
+ box-shadow: none;
73
75
  cursor: not-allowed;
74
76
  }
75
77
 
@@ -2,10 +2,11 @@
2
2
  <template component="ui-icon-button" controller="./ui-icon-button.js">
3
3
  <defs>
4
4
  <prop name="disabled" type="boolean" default="false"
5
- >Disables the button, so it cannot be pressed or focused, and washes it out: the same shape, with less colour and contrast (--ui-disabled-filter).</prop>
6
- <prop name="pending" type="boolean" default="false"
5
+ >Disables the button, so it cannot be pressed or focused, and gives it a flat neutral surface and muted icon.</prop>
6
+ <prop name="loading" type="boolean" default="false"
7
7
  >Keeps the button focusable and named while work is in progress. It shows a spinner, states aria-disabled and aria-busy, and prevents activation until
8
8
  cleared.</prop>
9
+ <prop name="pending" type="boolean" default="false">Deprecated alias for loading.</prop>
9
10
  <prop name="label" type="string">Accessible name for the icon.</prop>
10
11
  <prop name="size" type="sm | md | lg" default="md"
11
12
  >Button and icon size together: sm is 1.75rem with a small icon, md is 2rem, and lg is 2.5rem with a large icon. On touch, every size gets an invisible hit
@@ -18,8 +19,14 @@
18
19
  the pointer comes near inside a ui-affordance-scope. Touch devices and the solid variant always show it.</prop>
19
20
  <prop name="round" type="boolean" default="false">Use a fully circular shape.</prop>
20
21
  </defs>
21
- <button :disabled="disabled" type="button" :aria-label="label" :aria-disabled="{ true: 'true', false: null }[format('%s', pending)]" :aria-busy="pending">
22
- <ui-spinner $if="pending" size="sm"></ui-spinner>
22
+ <button
23
+ :disabled="disabled"
24
+ type="button"
25
+ :aria-label="label"
26
+ :aria-disabled="{ true: 'true', false: null }[format('%s', loading or pending)]"
27
+ :aria-busy="loading or pending"
28
+ >
29
+ <ui-spinner $if="loading or pending" size="sm"></ui-spinner>
23
30
  <span class="content"><slot></slot></span>
24
31
  </button>
25
32
  <style>
@@ -125,15 +132,30 @@
125
132
  pointer-events: none;
126
133
  }
127
134
 
128
- /* At rest an anticipatory button shows only its guide dot; proximity, hover, or focus reveals the
129
- * surface and icon. The root is the native button, so hiding it outright would hide the dot
130
- * too, and slotted icons sit outside this scope; `color: transparent` hides currentColor icons. */
135
+ :host-state([anticipatory]):disabled::before {
136
+ opacity: 0;
137
+ }
138
+
139
+ /* At rest an anticipatory button shows only its guide dot. The icon grows into place when
140
+ proximity, hover, or focus reveals it; the button's hit area and guide remain stable. */
141
+ :host-state([anticipatory]) .content {
142
+ opacity: 1;
143
+ transform: scale(1);
144
+ transition: opacity var(--ui-motion-fast) var(--ui-motion-ease), transform calc(var(--ui-motion-fast) * 2) cubic-bezier(0.2, 1.4, 0.35, 1);
145
+ }
146
+
131
147
  @media (hover: hover) and (pointer: fine) {
132
- :host-state([anticipatory]):not(:host-state([variant="solid"]), [data-ui-proximity="near"], :hover, :focus-visible) {
148
+ :host-state([anticipatory]):not(:host-state([variant="solid"]), :host-state([loading]), :host-state([pending]), :disabled, [data-ui-proximity="near"], :hover, :focus-visible) {
133
149
  border-color: transparent;
134
150
  background: transparent;
135
151
  box-shadow: none;
136
- color: transparent;
152
+ }
153
+
154
+ :host-state([anticipatory]):not(:host-state([variant="solid"]), :host-state([loading]), :host-state([pending]), :disabled, [data-ui-proximity="near"], :hover, :focus-visible)
155
+ .content {
156
+ opacity: 0;
157
+ transform: scale(0.65);
158
+ transition-duration: var(--ui-motion-fast);
137
159
  }
138
160
  }
139
161
 
@@ -163,7 +185,7 @@
163
185
  background-color var(--ui-motion-fast) var(--ui-motion-ease),
164
186
  border-color var(--ui-motion-fast) var(--ui-motion-ease),
165
187
  color var(--ui-motion-fast) var(--ui-motion-ease),
166
- box-shadow var(--ui-motion-fast) var(--ui-motion-ease),
188
+ box-shadow var(--ui-motion-base) var(--ui-motion-ease),
167
189
  transform var(--ui-motion-fast) var(--ui-motion-ease);
168
190
  }
169
191
 
@@ -224,13 +246,16 @@
224
246
  }
225
247
 
226
248
  :host-state([variant="outline"]) {
227
- border-color: var(--ui-icon-button-border, var(--ui-border-default));
249
+ border-color: var(--ui-icon-button-border, var(--ui-control-border, var(--ui-border-strong)));
228
250
  background: var(--ui-icon-button-outline-surface, var(--ui-surface-default));
251
+ background-image: var(--ui-raised-highlight);
229
252
  color: var(--ui-icon-button-outline-text, var(--ui-text-primary));
253
+ box-shadow: var(--ui-raised);
230
254
  }
231
255
 
232
256
  :host-state([variant="solid"]) {
233
257
  background: var(--ui-icon-button-solid-surface, var(--ui-accent-solid));
258
+ background-image: var(--ui-raised-highlight);
234
259
  color: var(--ui-icon-button-solid-text, var(--ui-text-on-accent));
235
260
  box-shadow: var(
236
261
  --ui-icon-button-solid-shadow,
@@ -245,7 +270,7 @@
245
270
  }
246
271
 
247
272
  :host-state([variant="outline"]):hover:enabled:not([aria-disabled="true"]) {
248
- border-color: var(--ui-icon-button-hover-border, var(--ui-border-strong));
273
+ border-color: var(--ui-icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border)));
249
274
  }
250
275
 
251
276
  :host-state([variant="solid"]):hover:enabled:not([aria-disabled="true"]) {
@@ -256,30 +281,45 @@
256
281
  transform: scale(var(--ui-icon-button-active-scale, 0.96));
257
282
  }
258
283
 
259
- :host-state([pending]) {
284
+ :is(:host-state([loading]), :host-state([pending])) {
260
285
  cursor: progress;
261
286
  }
262
287
 
263
288
  .content {
264
- display: contents;
289
+ display: inline-flex;
290
+ align-items: center;
291
+ justify-content: center;
265
292
  }
266
293
 
267
- :host-state([pending]) .content {
294
+ :is(:host-state([loading]), :host-state([pending])) .content {
268
295
  display: none;
269
296
  }
270
297
 
298
+ @media (prefers-reduced-motion: reduce) {
299
+ :host-state([anticipatory]) .content {
300
+ transition: none;
301
+ }
302
+ }
303
+
271
304
  :host:focus-visible {
272
305
  outline: none;
273
306
  box-shadow: var(--ui-focus-halo);
274
307
  }
275
308
 
276
- /* Disabled colours fall back to each variant's own; ghost takes only the icon colour. */
277
- /* Disabled washes the button out the way Button does: the same shape, one filter. */
309
+ /* Disabled is a flat neutral control, independent of the active variant's tone. */
278
310
  :host:disabled {
311
+ border-color: var(--ui-disabled-border);
312
+ background: var(--ui-disabled-surface);
313
+ color: var(--ui-disabled-text);
279
314
  filter: var(--ui-icon-button-disabled-filter, var(--ui-disabled-filter));
280
315
  opacity: var(--ui-icon-button-disabled-opacity, 1);
281
316
  cursor: not-allowed;
282
317
  box-shadow: none;
318
+ background-image: none;
319
+ }
320
+
321
+ :host-state([variant="ghost"]):disabled {
322
+ border-color: transparent;
283
323
  }
284
324
 
285
325
  :host {
@@ -5,7 +5,7 @@ export default function controller(host) {
5
5
  else host.element.removeAttribute("data-ui-affordance");
6
6
  });
7
7
  const onClick = (event) => {
8
- if (!host.state.pending) return;
8
+ if (!host.state.loading && !host.state.pending) return;
9
9
  event.preventDefault();
10
10
  event.stopImmediatePropagation();
11
11
  };
@@ -1,5 +1,7 @@
1
1
  <template component="ui-list">
2
2
  <defs>
3
+ <prop name="as" type="ul | ol" default="ul">The native list element. Use ol when item order matters; its native numbers are shown.</prop>
4
+ <prop name="markers" type="none | disc" default="none">Show disc bullets for a ul of native li elements. An ol always shows native numbers.</prop>
3
5
  <prop name="layout" type="rows | grid" default="rows"
4
6
  >How the items are laid out. Rows stack the items one per line, for a list read top to bottom. Grid sets them in as many columns as fit, each at least
5
7
  --ui-list-min-item-width (14rem) wide, for card items such as pinned or featured entries.</prop>
@@ -7,7 +9,10 @@
7
9
  >How much room each item takes. comfortable is a full row, easy to point at, for lists of things to open; compact sets items close together with no row
8
10
  padding, for a short list of facts inside other content, such as the features a plan includes.</prop>
9
11
  </defs>
10
- <ul role="list"><slot></slot></ul>
12
+ <template $match>
13
+ <ol $when="as = 'ol'"><slot></slot></ol>
14
+ <ul $else role="list"><slot></slot></ul>
15
+ </template>
11
16
  <style>
12
17
  /* This component's hooks style the element they are set on, and never a nested one. */
13
18
  @property --ui-list-gap {
@@ -19,32 +24,67 @@
19
24
  inherits: false;
20
25
  }
21
26
 
22
- /* A list of items (ui-list-item). It owns the spacing between them, so a view never sets it. The
27
+ /* A list of native li elements or structured ui-list-item components. It owns the spacing between them, so a view never sets it. The
23
28
  explicit list role keeps the list announced as one: some browsers drop it from a list with no
24
29
  markers. */
25
30
  :host {
31
+ --_list-gap: var(--ui-list-gap, var(--ui-space-1));
32
+ --_list-min-item-width: var(--ui-list-min-item-width, 14rem);
26
33
  display: flex;
27
34
  flex-direction: column;
28
- gap: var(--ui-list-gap, var(--ui-space-1));
35
+ inline-size: 100%;
36
+ gap: var(--_list-gap);
29
37
  min-inline-size: 0;
30
38
  margin: 0;
31
39
  padding: 0;
32
40
  list-style: none;
33
41
  }
34
42
 
43
+ :host-state([as="ol"]),
44
+ :host-state([markers="disc"]) {
45
+ padding-inline-start: var(--ui-space-5);
46
+ }
47
+
48
+ :host-state([as="ol"]) {
49
+ list-style: decimal;
50
+ }
51
+
52
+ :host-state([markers="disc"]) {
53
+ list-style: disc;
54
+ }
55
+
56
+ :host > :slotted(li) {
57
+ box-sizing: border-box;
58
+ min-inline-size: 0;
59
+ padding: var(--_ui-list-native-padding-block, var(--ui-space-2)) var(--_ui-list-native-padding-inline, var(--ui-space-3));
60
+ border-radius: var(--ui-radius-md);
61
+ color: var(--ui-text-primary);
62
+ list-style: inherit;
63
+ }
64
+
65
+ :host > :slotted(li.card) {
66
+ padding: var(--_ui-list-native-padding-block, var(--ui-space-3)) var(--_ui-list-native-padding-inline, var(--ui-space-4));
67
+ border: 1px solid var(--ui-border-strong);
68
+ border-radius: var(--ui-radius-lg);
69
+ background: var(--ui-surface-raised);
70
+ list-style: none;
71
+ }
72
+
35
73
  /* Compact passes its size to the items through private properties, which cross into each item. */
36
74
  :host-state([density="compact"]) {
75
+ --_list-gap: var(--ui-list-gap, var(--ui-space-2));
37
76
  --_ui-list-item-min-size: 0;
38
77
  --_ui-list-item-padding-block: 0;
39
78
  --_ui-list-item-padding-inline: 0;
40
79
  --_ui-list-item-title-weight: var(--ui-font-normal);
41
- gap: var(--ui-list-gap, var(--ui-space-2));
80
+ --_ui-list-native-padding-block: 0;
81
+ --_ui-list-native-padding-inline: 0;
42
82
  }
43
83
 
44
84
  :host-state([layout="grid"]) {
85
+ --_list-gap: var(--ui-list-gap, var(--ui-space-3));
45
86
  display: grid;
46
- grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--ui-list-min-item-width, 14rem)), 1fr));
47
- gap: var(--ui-list-gap, var(--ui-space-3));
87
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--_list-min-item-width)), 1fr));
48
88
  }
49
89
 
50
90
  /* A component that sets its display still honours the hidden attribute on its root. */
@@ -64,7 +64,7 @@
64
64
  :host-state([variant="card"]) {
65
65
  padding-block: var(--ui-list-item-padding-block, var(--ui-space-3));
66
66
  padding-inline: var(--ui-list-item-padding-inline, var(--ui-space-4));
67
- border: 1px solid var(--ui-border-default);
67
+ border: 1px solid var(--ui-border-strong);
68
68
  border-radius: var(--ui-radius-lg);
69
69
  background: var(--ui-surface-raised);
70
70
  }
@@ -2,6 +2,7 @@
2
2
  <defs>
3
3
  <prop name="density" type="comfortable | compact" default="comfortable">Compact trades padding and type size for rows that fit more on screen.</prop>
4
4
  <prop name="open" type="boolean" default="false">Whether the menu is open initially or when set externally.</prop>
5
+ <prop name="inline" type="boolean" default="false">Displays the menu in the page flow without an overlay or trigger, for an embedded list of actions.</prop>
5
6
  <prop name="for" type="string" default="">ID of the control that toggles and anchors the menu.</prop>
6
7
  <prop name="placement" type="string" default="bottom-start">Positions an associated menu relative to its trigger.</prop>
7
8
  <state name="internalOpen" :value="false"></state>
@@ -79,7 +80,7 @@
79
80
  max-inline-size: inherit;
80
81
  padding: var(--ui-space-1);
81
82
  background: var(--_ui-menu-surface, var(--ui-overlay-surface, var(--ui-surface-elevated)));
82
- border: 1px solid var(--_ui-menu-border, var(--ui-overlay-border, var(--ui-border-default)));
83
+ border: 1px solid var(--_ui-menu-border, var(--ui-overlay-border, var(--ui-border-strong)));
83
84
  border-radius: var(--_ui-menu-radius, var(--ui-overlay-radius, var(--ui-radius-lg)));
84
85
  box-shadow: var(--_ui-menu-shadow, var(--ui-overlay-shadow, var(--ui-elevation-overlay, var(--ui-shadow-lg))));
85
86
  max-block-size: inherit;
@@ -91,10 +92,10 @@
91
92
  block-size: 0;
92
93
  margin: var(--ui-space-1) 0;
93
94
  border: 0;
94
- border-block-start: 1px solid var(--ui-border-default);
95
+ border-block-start: 1px solid var(--ui-border-divider);
95
96
  }
96
97
 
97
- :host:not(:host-state([internalOpen])) {
98
+ :host:not(:host-state([internalOpen])):not(:host-state([inline])) {
98
99
  display: none;
99
100
  }
100
101
 
@@ -40,7 +40,7 @@ export default function controller(host) {
40
40
  };
41
41
  const ids = createIdResolver(document, () => apply());
42
42
  const setup = () => {
43
- const nextFor = String(host.state.for ?? "");
43
+ const nextFor = host.state.inline ? "" : String(host.state.for ?? "");
44
44
  const nextPlacement = String(host.state.placement ?? "bottom-start");
45
45
  if (nextFor === lastFor && nextPlacement === lastPlacement && surface) return;
46
46
  lastFor = nextFor;
@@ -52,18 +52,22 @@ export default function controller(host) {
52
52
  surface = anchor ? createAnchoredSurface(element, { anchor, placement: nextPlacement }) : null;
53
53
  };
54
54
  const apply = () => {
55
+ const inline = Boolean(host.state.inline);
55
56
  const externalOpen = Boolean(host.state.open);
56
57
  if (externalOpen !== lastExternalOpen) {
57
58
  lastExternalOpen = externalOpen;
58
59
  host.state.internalOpen = externalOpen;
59
60
  }
60
61
  setup();
61
- const open = Boolean(host.state.internalOpen);
62
+ const open = inline || Boolean(host.state.internalOpen);
62
63
  if (anchor) {
63
64
  anchor.setAttribute("aria-haspopup", "menu");
64
65
  anchor.setAttribute("aria-expanded", String(open));
65
66
  }
66
- if (open) {
67
+ if (inline) {
68
+ surface?.hide();
69
+ closeOverlay(document, overlayId);
70
+ } else if (open) {
67
71
  surface?.show();
68
72
  openOverlay({ id: overlayId, modal: false, element, relatedElements: anchor ? [anchor] : [], dismissible: true, requestClose: close });
69
73
  } else {
@@ -81,12 +85,14 @@ export default function controller(host) {
81
85
  return;
82
86
  }
83
87
  host.dispatch("select", { value, trigger });
88
+ if (host.state.inline) return;
84
89
  host.dispatch("close", { open: false, reason: "action", trigger });
85
90
  host.state.internalOpen = false;
86
91
  };
87
92
  const onClick = (event) => select(menuItemFrom(event.target), triggerFor(event));
88
93
  const onKeydown = (event) => {
89
94
  if (event.key === "Escape") {
95
+ if (host.state.inline) return;
90
96
  event.preventDefault();
91
97
  requestTopOverlayClose(document, "escape", "keyboard");
92
98
  return;