@threadlabs/looma 0.6.3 → 0.6.5

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 (250) hide show
  1. package/components/ui-tree-item/ui-tree-item.html +68 -12
  2. package/components/ui-tree-item/ui-tree-item.js +9 -1
  3. package/dist/index.js +1 -1
  4. package/package.json +2 -2
  5. package/styles/ui-affordance-scope.css +1 -1
  6. package/styles/ui-avatar-group.css +1 -1
  7. package/styles/ui-avatar.css +1 -1
  8. package/styles/ui-badge.css +1 -1
  9. package/styles/ui-button.css +1 -1
  10. package/styles/ui-callout.css +1 -1
  11. package/styles/ui-checkbox.css +1 -1
  12. package/styles/ui-cluster.css +1 -1
  13. package/styles/ui-combobox.css +1 -1
  14. package/styles/ui-container.css +1 -1
  15. package/styles/ui-context-menu.css +1 -1
  16. package/styles/ui-dialog.css +1 -1
  17. package/styles/ui-disclosure.css +1 -1
  18. package/styles/ui-editable.css +1 -1
  19. package/styles/ui-editor-insert-table-grid.css +1 -1
  20. package/styles/ui-editor-mention-menu.css +1 -1
  21. package/styles/ui-editor-slash-menu.css +1 -1
  22. package/styles/ui-editor-table-context-menu.css +1 -1
  23. package/styles/ui-editor-table-overlay.css +1 -1
  24. package/styles/ui-editor-table-toolbar.css +1 -1
  25. package/styles/ui-editor-toolbar.css +1 -1
  26. package/styles/ui-floating-action-button.css +1 -1
  27. package/styles/ui-form-field.css +1 -1
  28. package/styles/ui-grid.css +1 -1
  29. package/styles/ui-icon-button.css +1 -1
  30. package/styles/ui-icon.css +1 -1
  31. package/styles/ui-input.css +1 -1
  32. package/styles/ui-menu-item.css +1 -1
  33. package/styles/ui-menu.css +1 -1
  34. package/styles/ui-popover.css +1 -1
  35. package/styles/ui-radio-group.css +1 -1
  36. package/styles/ui-radio.css +1 -1
  37. package/styles/ui-reel.css +1 -1
  38. package/styles/ui-search-result-row.css +1 -1
  39. package/styles/ui-search-shell.css +1 -1
  40. package/styles/ui-select.css +1 -1
  41. package/styles/ui-separator.css +1 -1
  42. package/styles/ui-sidebar.css +1 -1
  43. package/styles/ui-stack.css +1 -1
  44. package/styles/ui-switch.css +1 -1
  45. package/styles/ui-switcher.css +1 -1
  46. package/styles/ui-tabs.css +1 -1
  47. package/styles/ui-textarea.css +1 -1
  48. package/styles/ui-toast-region.css +1 -1
  49. package/styles/ui-tooltip.css +1 -1
  50. package/styles/ui-top-bar.css +1 -1
  51. package/styles/ui-tree-item.css +75 -12
  52. package/styles/ui-tree.css +1 -1
  53. package/vanilla/UiAffordanceScope.d.ts +1 -1
  54. package/vanilla/UiAffordanceScope.js +1 -1
  55. package/vanilla/UiAvatar.d.ts +1 -1
  56. package/vanilla/UiAvatar.js +1 -1
  57. package/vanilla/UiAvatarGroup.d.ts +1 -1
  58. package/vanilla/UiAvatarGroup.js +1 -1
  59. package/vanilla/UiBadge.d.ts +1 -1
  60. package/vanilla/UiBadge.js +1 -1
  61. package/vanilla/UiButton.d.ts +1 -1
  62. package/vanilla/UiButton.js +1 -1
  63. package/vanilla/UiCallout.d.ts +1 -1
  64. package/vanilla/UiCallout.js +1 -1
  65. package/vanilla/UiCheckbox.d.ts +1 -1
  66. package/vanilla/UiCheckbox.js +1 -1
  67. package/vanilla/UiCluster.d.ts +1 -1
  68. package/vanilla/UiCluster.js +1 -1
  69. package/vanilla/UiCombobox.d.ts +1 -1
  70. package/vanilla/UiCombobox.js +1 -1
  71. package/vanilla/UiContainer.d.ts +1 -1
  72. package/vanilla/UiContainer.js +1 -1
  73. package/vanilla/UiContextMenu.d.ts +1 -1
  74. package/vanilla/UiContextMenu.js +1 -1
  75. package/vanilla/UiDialog.d.ts +1 -1
  76. package/vanilla/UiDialog.js +1 -1
  77. package/vanilla/UiDisclosure.d.ts +1 -1
  78. package/vanilla/UiDisclosure.js +1 -1
  79. package/vanilla/UiEditable.d.ts +1 -1
  80. package/vanilla/UiEditable.js +1 -1
  81. package/vanilla/UiEditorInsertTableGrid.d.ts +1 -1
  82. package/vanilla/UiEditorInsertTableGrid.js +1 -1
  83. package/vanilla/UiEditorMentionMenu.d.ts +1 -1
  84. package/vanilla/UiEditorMentionMenu.js +1 -1
  85. package/vanilla/UiEditorSlashMenu.d.ts +1 -1
  86. package/vanilla/UiEditorSlashMenu.js +1 -1
  87. package/vanilla/UiEditorTableContextMenu.d.ts +1 -1
  88. package/vanilla/UiEditorTableContextMenu.js +1 -1
  89. package/vanilla/UiEditorTableOverlay.d.ts +1 -1
  90. package/vanilla/UiEditorTableOverlay.js +1 -1
  91. package/vanilla/UiEditorTableToolbar.d.ts +1 -1
  92. package/vanilla/UiEditorTableToolbar.js +1 -1
  93. package/vanilla/UiEditorToolbar.d.ts +1 -1
  94. package/vanilla/UiEditorToolbar.js +1 -1
  95. package/vanilla/UiFloatingActionButton.d.ts +1 -1
  96. package/vanilla/UiFloatingActionButton.js +1 -1
  97. package/vanilla/UiFormField.d.ts +1 -1
  98. package/vanilla/UiFormField.js +1 -1
  99. package/vanilla/UiGrid.d.ts +1 -1
  100. package/vanilla/UiGrid.js +1 -1
  101. package/vanilla/UiIcon.d.ts +1 -1
  102. package/vanilla/UiIcon.js +1 -1
  103. package/vanilla/UiIconButton.d.ts +1 -1
  104. package/vanilla/UiIconButton.js +1 -1
  105. package/vanilla/UiInput.d.ts +1 -1
  106. package/vanilla/UiInput.js +1 -1
  107. package/vanilla/UiMenu.d.ts +1 -1
  108. package/vanilla/UiMenu.js +1 -1
  109. package/vanilla/UiMenuItem.d.ts +1 -1
  110. package/vanilla/UiMenuItem.js +1 -1
  111. package/vanilla/UiPopover.d.ts +1 -1
  112. package/vanilla/UiPopover.js +1 -1
  113. package/vanilla/UiRadio.d.ts +1 -1
  114. package/vanilla/UiRadio.js +1 -1
  115. package/vanilla/UiRadioGroup.d.ts +1 -1
  116. package/vanilla/UiRadioGroup.js +1 -1
  117. package/vanilla/UiReel.d.ts +1 -1
  118. package/vanilla/UiReel.js +1 -1
  119. package/vanilla/UiSearchResultRow.d.ts +1 -1
  120. package/vanilla/UiSearchResultRow.js +1 -1
  121. package/vanilla/UiSearchShell.d.ts +1 -1
  122. package/vanilla/UiSearchShell.js +1 -1
  123. package/vanilla/UiSelect.d.ts +1 -1
  124. package/vanilla/UiSelect.js +1 -1
  125. package/vanilla/UiSeparator.d.ts +1 -1
  126. package/vanilla/UiSeparator.js +1 -1
  127. package/vanilla/UiSidebar.d.ts +1 -1
  128. package/vanilla/UiSidebar.js +1 -1
  129. package/vanilla/UiStack.d.ts +1 -1
  130. package/vanilla/UiStack.js +1 -1
  131. package/vanilla/UiSwitch.d.ts +1 -1
  132. package/vanilla/UiSwitch.js +1 -1
  133. package/vanilla/UiSwitcher.d.ts +1 -1
  134. package/vanilla/UiSwitcher.js +1 -1
  135. package/vanilla/UiTabs.d.ts +1 -1
  136. package/vanilla/UiTabs.js +1 -1
  137. package/vanilla/UiTextarea.d.ts +1 -1
  138. package/vanilla/UiTextarea.js +1 -1
  139. package/vanilla/UiToastRegion.d.ts +1 -1
  140. package/vanilla/UiToastRegion.js +1 -1
  141. package/vanilla/UiTooltip.d.ts +1 -1
  142. package/vanilla/UiTooltip.js +1 -1
  143. package/vanilla/UiTopBar.d.ts +1 -1
  144. package/vanilla/UiTopBar.js +1 -1
  145. package/vanilla/UiTree.d.ts +1 -1
  146. package/vanilla/UiTree.js +1 -1
  147. package/vanilla/UiTreeItem.d.ts +1 -1
  148. package/vanilla/UiTreeItem.js +2 -2
  149. package/vue/UiAffordanceScope.vue +8 -84
  150. package/vue/UiAvatar.d.ts +1 -1
  151. package/vue/UiAvatar.vue +9 -106
  152. package/vue/UiAvatarGroup.vue +9 -96
  153. package/vue/UiBadge.vue +1 -1
  154. package/vue/UiButton.vue +1 -1
  155. package/vue/UiCallout.vue +1 -1
  156. package/vue/UiCheckbox.vue +22 -123
  157. package/vue/UiCluster.vue +1 -1
  158. package/vue/UiCombobox.d.ts +1 -1
  159. package/vue/UiCombobox.vue +224 -475
  160. package/vue/UiContainer.vue +1 -1
  161. package/vue/UiContextMenu.vue +34 -141
  162. package/vue/UiDialog.vue +25 -126
  163. package/vue/UiDisclosure.vue +26 -138
  164. package/vue/UiEditable.vue +46 -158
  165. package/vue/UiEditorInsertTableGrid.vue +19 -138
  166. package/vue/UiEditorMentionMenu.vue +17 -124
  167. package/vue/UiEditorSlashMenu.vue +17 -109
  168. package/vue/UiEditorTableContextMenu.vue +34 -122
  169. package/vue/UiEditorTableOverlay.vue +61 -167
  170. package/vue/UiEditorTableToolbar.vue +34 -142
  171. package/vue/UiEditorToolbar.vue +1 -1
  172. package/vue/UiFloatingActionButton.vue +1 -1
  173. package/vue/UiFormField.vue +7 -79
  174. package/vue/UiGrid.vue +1 -1
  175. package/vue/UiIcon.vue +8 -84
  176. package/vue/UiIconButton.vue +7 -79
  177. package/vue/UiInput.vue +7 -79
  178. package/vue/UiMenu.vue +42 -127
  179. package/vue/UiMenuItem.vue +1 -1
  180. package/vue/UiPopover.vue +25 -121
  181. package/vue/UiRadio.vue +22 -123
  182. package/vue/UiRadioGroup.d.ts +1 -1
  183. package/vue/UiRadioGroup.vue +32 -119
  184. package/vue/UiReel.vue +1 -1
  185. package/vue/UiSearchResultRow.vue +1 -1
  186. package/vue/UiSearchShell.vue +25 -121
  187. package/vue/UiSelect.vue +7 -79
  188. package/vue/UiSeparator.vue +1 -1
  189. package/vue/UiSidebar.vue +32 -133
  190. package/vue/UiStack.vue +1 -1
  191. package/vue/UiSwitch.vue +22 -123
  192. package/vue/UiSwitcher.vue +1 -1
  193. package/vue/UiTabs.vue +24 -128
  194. package/vue/UiTextarea.vue +7 -79
  195. package/vue/UiToastRegion.vue +37 -126
  196. package/vue/UiTooltip.vue +25 -124
  197. package/vue/UiTopBar.vue +1 -1
  198. package/vue/UiTree.vue +56 -137
  199. package/vue/UiTreeItem.vue +97 -153
  200. package/vue/chunks/UiAffordanceScope.js +9 -78
  201. package/vue/chunks/UiAvatar.js +13 -89
  202. package/vue/chunks/UiAvatarGroup.js +10 -80
  203. package/vue/chunks/UiBadge.js +1 -1
  204. package/vue/chunks/UiButton.js +1 -1
  205. package/vue/chunks/UiCallout.js +1 -1
  206. package/vue/chunks/UiCheckbox.js +17 -95
  207. package/vue/chunks/UiCluster.js +1 -1
  208. package/vue/chunks/UiCombobox.js +114 -325
  209. package/vue/chunks/UiContainer.js +1 -1
  210. package/vue/chunks/UiContextMenu.js +21 -113
  211. package/vue/chunks/UiDialog.js +20 -99
  212. package/vue/chunks/UiDisclosure.js +22 -112
  213. package/vue/chunks/UiEditable.js +32 -128
  214. package/vue/chunks/UiEditorInsertTableGrid.js +22 -116
  215. package/vue/chunks/UiEditorMentionMenu.js +18 -116
  216. package/vue/chunks/UiEditorSlashMenu.js +15 -101
  217. package/vue/chunks/UiEditorTableContextMenu.js +12 -91
  218. package/vue/chunks/UiEditorTableOverlay.js +29 -120
  219. package/vue/chunks/UiEditorTableToolbar.js +16 -111
  220. package/vue/chunks/UiEditorToolbar.js +1 -1
  221. package/vue/chunks/UiFloatingActionButton.js +1 -1
  222. package/vue/chunks/UiFormField.js +8 -73
  223. package/vue/chunks/UiGrid.js +1 -1
  224. package/vue/chunks/UiIcon.js +9 -78
  225. package/vue/chunks/UiIconButton.js +8 -73
  226. package/vue/chunks/UiInput.js +8 -73
  227. package/vue/chunks/UiMenu.js +25 -111
  228. package/vue/chunks/UiMenuItem.js +1 -1
  229. package/vue/chunks/UiPopover.js +18 -105
  230. package/vue/chunks/UiRadio.js +17 -95
  231. package/vue/chunks/UiRadioGroup.js +23 -105
  232. package/vue/chunks/UiReel.js +1 -1
  233. package/vue/chunks/UiSearchResultRow.js +1 -1
  234. package/vue/chunks/UiSearchShell.js +17 -94
  235. package/vue/chunks/UiSelect.js +8 -73
  236. package/vue/chunks/UiSeparator.js +1 -1
  237. package/vue/chunks/UiSidebar.js +23 -108
  238. package/vue/chunks/UiStack.js +1 -1
  239. package/vue/chunks/UiSwitch.js +17 -95
  240. package/vue/chunks/UiSwitcher.js +1 -1
  241. package/vue/chunks/UiTabs.js +22 -103
  242. package/vue/chunks/UiTextarea.js +8 -73
  243. package/vue/chunks/UiToastRegion.js +27 -112
  244. package/vue/chunks/UiTooltip.js +18 -106
  245. package/vue/chunks/UiTopBar.js +1 -1
  246. package/vue/chunks/UiTree.js +31 -109
  247. package/vue/chunks/UiTreeItem.js +35 -118
  248. package/vue/chunks/host.js +101 -0
  249. package/vue/components.css +759 -707
  250. package/vue/host.ts +154 -0
@@ -1,15 +1,8 @@
1
- <!-- Generated by HTML Next 1.0.0-alpha.2 for Vue 3.5. Do not edit. -->
1
+ <!-- Generated by HTML Next 1.0.0-alpha.3 for Vue 3.5. Do not edit. -->
2
2
  <script setup lang="ts">
3
- import {
4
- computed,
5
- onBeforeUnmount,
6
- onMounted,
7
- ref,
8
- shallowRef,
9
- useTemplateRef,
10
- watchEffect,
11
- } from 'vue'
3
+ import { computed, ref, useTemplateRef } from 'vue'
12
4
  import * as controllerModule from '../components/ui-tree-item/ui-tree-item.js'
5
+ import { createDispatch, useComponentHost } from './host'
13
6
 
14
7
  defineOptions({ inheritAttrs: false })
15
8
 
@@ -56,6 +49,7 @@ const root = ref<HTMLElement | null>(null)
56
49
  const rowElement = useTemplateRef<HTMLElement>('row')
57
50
  const dragHandleElement = useTemplateRef<HTMLElement>('dragHandle')
58
51
  const disclosureElement = useTemplateRef<HTMLElement>('disclosure')
52
+ const actionsElement = useTemplateRef<HTMLElement>('actions')
59
53
  const childrenElement = useTemplateRef<HTMLElement>('children')
60
54
  const internalExpanded = ref(false)
61
55
  const structuralLevel = ref(1)
@@ -70,140 +64,34 @@ const hostState = computed(() =>
70
64
  ].filter(Boolean).join(' ')
71
65
  )
72
66
 
73
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
74
- function dispatch(name: string, detail?: unknown): boolean {
75
- const declared: Record<string, EventInit | undefined> = {
76
- expand: { bubbles: false, composed: true, cancelable: false },
77
- }
78
- const checks: Record<string, (detail: unknown) => boolean> = {
79
- expand: (detail) =>
80
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
81
- && typeof (detail as Record<string, unknown>)['id'] === 'string'
82
- && typeof (detail as Record<string, unknown>)['expanded'] === 'boolean'
83
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
84
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
85
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
86
- && Object.keys(detail as object).every((key) => ['id', 'expanded', 'trigger'].includes(key)),
87
- }
88
- if (detail !== undefined && checks[name] !== undefined && !checks[name]!(detail)) {
89
- throw new TypeError(`HR002: Event \`${name}\` detail does not satisfy its declared type.`)
90
- }
91
- const emitEvent = emit as (name: string, detail: unknown) => void
92
- emitEvent(name, detail)
93
- if (detail !== null && typeof detail === 'object' && 'expanded' in detail) {
94
- emitEvent('update:expanded', (detail as Record<string, unknown>)['expanded'])
95
- }
96
- return root.value?.dispatchEvent(
97
- new CustomEvent(name, { bubbles: true, composed: true, ...declared[name], detail }),
98
- ) ?? true
99
- }
100
-
101
- function read(name: string): unknown {
102
- if (name === 'internalExpanded') return internalExpanded.value
103
- if (name === 'structuralLevel') return structuralLevel.value
104
- if (name === 'tabStop') return tabStop.value
105
- if (name === 'isContainer') return isContainer.value
106
- return (props as Record<string, unknown>)[name]
107
- }
108
-
109
- function write(name: string, value: unknown): boolean {
110
- if (name === 'internalExpanded') {
111
- internalExpanded.value = value as never
112
- return true
113
- }
114
- if (name === 'structuralLevel') {
115
- structuralLevel.value = value as never
116
- return true
117
- }
118
- if (name === 'tabStop') {
119
- tabStop.value = value as never
120
- return true
121
- }
122
- if (name === 'isContainer') {
123
- isContainer.value = value as never
124
- return true
125
- }
126
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`)
127
- }
128
-
129
- const stops: Array<() => void> = []
130
- const host = {
131
- get element(): Element {
132
- return root.value as Element
67
+ const isExpandDetail = (detail: unknown): boolean =>
68
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
69
+ && typeof (detail as Record<string, unknown>)['id'] === 'string'
70
+ && typeof (detail as Record<string, unknown>)['expanded'] === 'boolean'
71
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
72
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
73
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
74
+ && Object.keys(detail as object).every((key) => ['id', 'expanded', 'trigger'].includes(key))
75
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
76
+ declared: { expand: { bubbles: false, composed: true, cancelable: false } },
77
+ checks: {
78
+ expand: isExpandDetail,
133
79
  },
134
- state: new Proxy({} as Record<string, unknown>, {
135
- get: (_target, name) => typeof name === 'string' ? read(name) : undefined,
136
- set: (_target, name, value) => typeof name === 'string' && write(name, value),
137
- }),
80
+ modeled: ['expanded'],
81
+ })
82
+
83
+ useComponentHost(controllerModule.default, {
84
+ root,
85
+ dispatch,
86
+ props,
138
87
  refs: {
139
- get row(): Element {
140
- return rowElement.value as Element
141
- },
142
- get dragHandle(): Element {
143
- return dragHandleElement.value as Element
144
- },
145
- get disclosure(): Element {
146
- return disclosureElement.value as Element
147
- },
148
- get children(): Element {
149
- return childrenElement.value as Element
150
- },
151
- } as Readonly<Record<string, Element>>,
152
- elements: new Proxy({} as Record<string, Element | RadioNodeList | undefined>, {
153
- get: (_target, name) => {
154
- if (typeof name !== 'string' || root.value === null) return undefined
155
- const form = root.value instanceof HTMLFormElement
156
- ? root.value
157
- : root.value.querySelector('form')
158
- return form?.elements.namedItem(name)
159
- ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? undefined
160
- },
161
- }),
162
- signal<T>(initialValue: T) {
163
- const value = shallowRef(initialValue)
164
- return {
165
- get: (): T => value.value,
166
- set: (next: T): void => {
167
- if (!Object.is(value.value, next)) value.value = next
168
- },
169
- update: (next: (current: T) => T): void => {
170
- const updated = next(value.value)
171
- if (!Object.is(value.value, updated)) value.value = updated
172
- },
173
- }
174
- },
175
- computed<T>(compute: () => T) {
176
- const value = computed(compute)
177
- return { get: (): T => value.value }
178
- },
179
- effect(run: () => void | (() => void)): () => void {
180
- const stop = watchEffect((onCleanup) => {
181
- const cleanup = run()
182
- if (typeof cleanup === 'function') onCleanup(cleanup)
183
- }, { flush: 'post' })
184
- stops.push(stop)
185
- return stop
186
- },
187
- on(event: string, listener: EventListener): () => void {
188
- const element = root.value
189
- element?.addEventListener(event, listener)
190
- const off = (): void => element?.removeEventListener(event, listener)
191
- stops.push(off)
192
- return off
88
+ row: rowElement,
89
+ dragHandle: dragHandleElement,
90
+ disclosure: disclosureElement,
91
+ actions: actionsElement,
92
+ children: childrenElement,
193
93
  },
194
- dispatch,
195
- }
196
-
197
- let cleanup: void | (() => void)
198
- let ready: Promise<void> | undefined
199
- onMounted(() => {
200
- ready = Promise.resolve(controllerModule.default(host as never)).then((result) => {
201
- cleanup = result
202
- })
203
- })
204
- onBeforeUnmount(() => {
205
- for (const stop of stops.splice(0)) stop()
206
- if (typeof cleanup === 'function') cleanup()
94
+ state: { internalExpanded, structuralLevel, tabStop, isContainer },
207
95
  })
208
96
  </script>
209
97
 
@@ -263,7 +151,7 @@ onBeforeUnmount(() => {
263
151
  </button>
264
152
  <span class="leading"><slot name="leading" /></span>
265
153
  <span class="label"><slot name="label">{{ label }}</slot></span>
266
- <span class="actions"><slot name="actions" /></span>
154
+ <span class="actions" ref="actions"><slot name="actions" /></span>
267
155
  <span class="drop-indicator row-drop-indicator" aria-hidden="true"></span>
268
156
  </div>
269
157
  <div class="children" role="group" :hidden="!(isContainer && internalExpanded)" ref="children">
@@ -276,6 +164,7 @@ onBeforeUnmount(() => {
276
164
  <style scoped>
277
165
  [data-component~="ui-tree-item"] {
278
166
  --_tree-row-min-height: 32px;
167
+ --_tree-disclosure-size: 16px;
279
168
 
280
169
  position: relative;
281
170
  display: block;
@@ -286,7 +175,7 @@ onBeforeUnmount(() => {
286
175
  .row {
287
176
  position: relative;
288
177
  display: grid;
289
- grid-template-columns: 20px auto minmax(0, 1fr) auto;
178
+ grid-template-columns: var(--_tree-disclosure-size) auto minmax(0, 1fr);
290
179
  align-items: center;
291
180
  min-block-size: var(--ui-tree-item-min-block-size, var(--_tree-row-min-height));
292
181
  min-inline-size: 0;
@@ -334,13 +223,14 @@ onBeforeUnmount(() => {
334
223
  .disclosure-spacer {
335
224
  grid-column: 1;
336
225
  grid-row: 1;
337
- inline-size: 20px;
226
+ inline-size: var(--_tree-disclosure-size);
338
227
  block-size: 28px;
339
228
  }
340
229
 
341
230
  .disclosure {
342
231
  display: grid;
343
- place-items: center;
232
+ /* Start-aligned: the chevron's ink, not its hit area, aligns with the content above it. */
233
+ place-items: center start;
344
234
  padding: 0;
345
235
  color: var(--ui-text-muted);
346
236
  background: transparent;
@@ -361,18 +251,18 @@ onBeforeUnmount(() => {
361
251
  .disclosure-icon {
362
252
  display: grid;
363
253
  place-items: center;
364
- inline-size: 14px;
365
- block-size: 14px;
254
+ inline-size: 12px;
255
+ block-size: 12px;
366
256
  transform: rotate(-90deg);
367
257
  transition: transform var(--ui-motion-fast) var(--ui-motion-ease);
368
258
  }
369
259
 
370
260
  .disclosure-icon::before {
371
261
  display: block;
372
- inline-size: 0.45rem;
373
- block-size: 0.45rem;
374
- border-inline-end: 2px solid currentColor;
375
- border-block-end: 2px solid currentColor;
262
+ inline-size: 0.375rem;
263
+ block-size: 0.375rem;
264
+ border-inline-end: 1.5px solid currentColor;
265
+ border-block-end: 1.5px solid currentColor;
376
266
  content: "";
377
267
  /* A chevron's ink sits below its box centre; lift it so it centres optically (in either rotation). */
378
268
  transform: translateY(-20%) rotate(45deg);
@@ -434,12 +324,66 @@ onBeforeUnmount(() => {
434
324
  min-inline-size: 0;
435
325
  }
436
326
 
327
+ /* The controls sit over the label's end, so the text fades out where they begin. The fade is
328
+ the truncation mark while it shows: an ellipsis under it would read as a second one. */
329
+ .row:hover > .label,
330
+ .row:focus-within > .label {
331
+ text-overflow: clip;
332
+ mask-image: linear-gradient(
333
+ to right,
334
+ #000 calc(100% - var(--_tree-actions-width, 1.75rem) - var(--ui-space-3)),
335
+ transparent calc(100% - var(--_tree-actions-width, 1.75rem))
336
+ );
337
+ }
338
+
339
+ .row:hover > .label:dir(rtl),
340
+ .row:focus-within > .label:dir(rtl) {
341
+ mask-image: linear-gradient(
342
+ to left,
343
+ #000 calc(100% - var(--_tree-actions-width, 1.75rem) - var(--ui-space-3)),
344
+ transparent calc(100% - var(--_tree-actions-width, 1.75rem))
345
+ );
346
+ }
347
+
348
+ .row:hover > .label > :slotted(*),
349
+ .row:focus-within > .label > :slotted(*) {
350
+ text-overflow: clip;
351
+ }
352
+
437
353
  .actions {
438
- grid-column: 4;
439
- grid-row: 1;
354
+ position: absolute;
355
+ z-index: 1;
356
+ inset-block: 0;
357
+ inset-inline-end: 0;
440
358
  display: inline-flex;
441
359
  align-items: center;
442
360
  min-inline-size: 0;
361
+ opacity: 0;
362
+ pointer-events: none;
363
+ transition: opacity var(--ui-motion-fast) var(--ui-motion-ease);
364
+ }
365
+
366
+ .row:hover > .actions,
367
+ .row:focus-within > .actions {
368
+ opacity: 1;
369
+ pointer-events: auto;
370
+ }
371
+
372
+ /* Without hover there is no reveal, so the controls keep their own column. */
373
+ @media (hover: none) {
374
+ .row {
375
+ grid-template-columns: var(--_tree-disclosure-size) auto minmax(0, 1fr) auto;
376
+ }
377
+
378
+ .actions {
379
+ position: static;
380
+ grid-column: 4;
381
+ grid-row: 1;
382
+ padding-inline-start: 0;
383
+ background: none;
384
+ opacity: 1;
385
+ pointer-events: auto;
386
+ }
443
387
  }
444
388
 
445
389
  .drag-handle {
@@ -1,5 +1,6 @@
1
+ import { n as useComponentHost, t as createDispatch } from "./host.js";
1
2
  import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
2
- import { computed, createElementBlock, defineComponent, mergeProps, onBeforeUnmount, onMounted, openBlock, ref, renderSlot, shallowRef, watchEffect } from "vue";
3
+ import { computed, createElementBlock, defineComponent, mergeProps, openBlock, ref, renderSlot } from "vue";
3
4
  import * as controllerModule from "@threadlabs/looma/components/ui-affordance-scope/ui-affordance-scope.js";
4
5
  //#region .build/vue/UiAffordanceScope.vue?vue&type=script&setup=true&lang.ts
5
6
  var _hoisted_1 = ["data-ui-affordance-scope-state"];
@@ -15,82 +16,12 @@ var UiAffordanceScope_default = /*#__PURE__*/ _plugin_vue_export_helper_default(
15
16
  const engaged = ref(false);
16
17
  /** The values the styles' :host-state() rules test. */
17
18
  const hostState = computed(() => [engaged.value && "engaged"].filter(Boolean).join(" "));
18
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
19
- function dispatch(name, detail) {
20
- return root.value?.dispatchEvent(new CustomEvent(name, {
21
- bubbles: true,
22
- composed: true,
23
- detail
24
- })) ?? true;
25
- }
26
- function read(name) {
27
- if (name === "engaged") return engaged.value;
28
- return props[name];
29
- }
30
- function write(name, value) {
31
- if (name === "engaged") {
32
- engaged.value = value;
33
- return true;
34
- }
35
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`);
36
- }
37
- const stops = [];
38
- const host = {
39
- get element() {
40
- return root.value;
41
- },
42
- state: new Proxy({}, {
43
- get: (_target, name) => typeof name === "string" ? read(name) : void 0,
44
- set: (_target, name, value) => typeof name === "string" && write(name, value)
45
- }),
46
- refs: {},
47
- elements: new Proxy({}, { get: (_target, name) => {
48
- if (typeof name !== "string" || root.value === null) return void 0;
49
- return (root.value instanceof HTMLFormElement ? root.value : root.value.querySelector("form"))?.elements.namedItem(name) ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? void 0;
50
- } }),
51
- signal(initialValue) {
52
- const value = shallowRef(initialValue);
53
- return {
54
- get: () => value.value,
55
- set: (next) => {
56
- if (!Object.is(value.value, next)) value.value = next;
57
- },
58
- update: (next) => {
59
- const updated = next(value.value);
60
- if (!Object.is(value.value, updated)) value.value = updated;
61
- }
62
- };
63
- },
64
- computed(compute) {
65
- const value = computed(compute);
66
- return { get: () => value.value };
67
- },
68
- effect(run) {
69
- const stop = watchEffect((onCleanup) => {
70
- const cleanup = run();
71
- if (typeof cleanup === "function") onCleanup(cleanup);
72
- }, { flush: "post" });
73
- stops.push(stop);
74
- return stop;
75
- },
76
- on(event, listener) {
77
- const element = root.value;
78
- element?.addEventListener(event, listener);
79
- const off = () => element?.removeEventListener(event, listener);
80
- stops.push(off);
81
- return off;
82
- },
83
- dispatch
84
- };
85
- let cleanup;
86
- onMounted(() => {
87
- Promise.resolve(controllerModule.default(host)).then((result) => {
88
- cleanup = result;
89
- });
90
- });
91
- onBeforeUnmount(() => {
92
- for (const stop of stops.splice(0)) stop();
93
- if (typeof cleanup === "function") cleanup();
19
+ const dispatch = createDispatch(root);
20
+ useComponentHost(controllerModule.default, {
21
+ root,
22
+ dispatch,
23
+ props,
24
+ state: { engaged }
94
25
  });
95
26
  return (_ctx, _cache) => {
96
27
  return openBlock(), createElementBlock("span", mergeProps({ "data-component": "ui-affordance-scope" }, _ctx.$attrs, {
@@ -100,6 +31,6 @@ var UiAffordanceScope_default = /*#__PURE__*/ _plugin_vue_export_helper_default(
100
31
  }), [renderSlot(_ctx.$slots, "default", {}, void 0, true)], 16, _hoisted_1);
101
32
  };
102
33
  }
103
- }), [["__scopeId", "data-v-3d8ef4c3"]]);
34
+ }), [["__scopeId", "data-v-c1d56d8d"]]);
104
35
  //#endregion
105
36
  export { UiAffordanceScope_default as t };
@@ -1,5 +1,6 @@
1
+ import { n as useComponentHost, t as createDispatch } from "./host.js";
1
2
  import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
2
- import { computed, createElementBlock, createElementVNode, defineComponent, mergeProps, onBeforeUnmount, onMounted, openBlock, ref, renderSlot, shallowRef, toDisplayString, useTemplateRef, watchEffect } from "vue";
3
+ import { createElementBlock, createElementVNode, defineComponent, mergeProps, openBlock, ref, renderSlot, toDisplayString, useTemplateRef } from "vue";
3
4
  import * as controllerModule from "@threadlabs/looma/components/ui-avatar/ui-avatar.js";
4
5
  //#region .build/vue/UiAvatar.vue?vue&type=script&setup=true&lang.ts
5
6
  var _hoisted_1 = ["src", "hidden"];
@@ -22,94 +23,17 @@ var UiAvatar_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
22
23
  const hasImage = ref(false);
23
24
  const hasAuthoredImage = ref(false);
24
25
  const initials = ref("?");
25
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
26
- function dispatch(name, detail) {
27
- return root.value?.dispatchEvent(new CustomEvent(name, {
28
- bubbles: true,
29
- composed: true,
30
- detail
31
- })) ?? true;
32
- }
33
- function read(name) {
34
- if (name === "hasImage") return hasImage.value;
35
- if (name === "hasAuthoredImage") return hasAuthoredImage.value;
36
- if (name === "initials") return initials.value;
37
- return props[name];
38
- }
39
- function write(name, value) {
40
- if (name === "hasImage") {
41
- hasImage.value = value;
42
- return true;
26
+ const dispatch = createDispatch(root);
27
+ useComponentHost(controllerModule.default, {
28
+ root,
29
+ dispatch,
30
+ props,
31
+ refs: { image: imageElement },
32
+ state: {
33
+ hasImage,
34
+ hasAuthoredImage,
35
+ initials
43
36
  }
44
- if (name === "hasAuthoredImage") {
45
- hasAuthoredImage.value = value;
46
- return true;
47
- }
48
- if (name === "initials") {
49
- initials.value = value;
50
- return true;
51
- }
52
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`);
53
- }
54
- const stops = [];
55
- const host = {
56
- get element() {
57
- return root.value;
58
- },
59
- state: new Proxy({}, {
60
- get: (_target, name) => typeof name === "string" ? read(name) : void 0,
61
- set: (_target, name, value) => typeof name === "string" && write(name, value)
62
- }),
63
- refs: { get image() {
64
- return imageElement.value;
65
- } },
66
- elements: new Proxy({}, { get: (_target, name) => {
67
- if (typeof name !== "string" || root.value === null) return void 0;
68
- return (root.value instanceof HTMLFormElement ? root.value : root.value.querySelector("form"))?.elements.namedItem(name) ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? void 0;
69
- } }),
70
- signal(initialValue) {
71
- const value = shallowRef(initialValue);
72
- return {
73
- get: () => value.value,
74
- set: (next) => {
75
- if (!Object.is(value.value, next)) value.value = next;
76
- },
77
- update: (next) => {
78
- const updated = next(value.value);
79
- if (!Object.is(value.value, updated)) value.value = updated;
80
- }
81
- };
82
- },
83
- computed(compute) {
84
- const value = computed(compute);
85
- return { get: () => value.value };
86
- },
87
- effect(run) {
88
- const stop = watchEffect((onCleanup) => {
89
- const cleanup = run();
90
- if (typeof cleanup === "function") onCleanup(cleanup);
91
- }, { flush: "post" });
92
- stops.push(stop);
93
- return stop;
94
- },
95
- on(event, listener) {
96
- const element = root.value;
97
- element?.addEventListener(event, listener);
98
- const off = () => element?.removeEventListener(event, listener);
99
- stops.push(off);
100
- return off;
101
- },
102
- dispatch
103
- };
104
- let cleanup;
105
- onMounted(() => {
106
- Promise.resolve(controllerModule.default(host)).then((result) => {
107
- cleanup = result;
108
- });
109
- });
110
- onBeforeUnmount(() => {
111
- for (const stop of stops.splice(0)) stop();
112
- if (typeof cleanup === "function") cleanup();
113
37
  });
114
38
  return (_ctx, _cache) => {
115
39
  return openBlock(), createElementBlock("span", mergeProps({ "data-component": "ui-avatar" }, _ctx.$attrs, {
@@ -133,6 +57,6 @@ var UiAvatar_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
133
57
  ], 16);
134
58
  };
135
59
  }
136
- }), [["__scopeId", "data-v-3a27ff1d"]]);
60
+ }), [["__scopeId", "data-v-64e52bdd"]]);
137
61
  //#endregion
138
62
  export { UiAvatar_default as t };
@@ -1,5 +1,6 @@
1
+ import { n as useComponentHost, t as createDispatch } from "./host.js";
1
2
  import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
2
- import { computed, createElementBlock, createElementVNode, defineComponent, mergeProps, onBeforeUnmount, onMounted, openBlock, ref, renderSlot, shallowRef, toDisplayString, useTemplateRef, watchEffect } from "vue";
3
+ import { createElementBlock, createElementVNode, defineComponent, mergeProps, openBlock, ref, renderSlot, toDisplayString, useTemplateRef } from "vue";
3
4
  import * as controllerModule from "@threadlabs/looma/components/ui-avatar-group/ui-avatar-group.js";
4
5
  //#region .build/vue/UiAvatarGroup.vue?vue&type=script&setup=true&lang.ts
5
6
  var _hoisted_1 = ["aria-label"];
@@ -18,84 +19,13 @@ var UiAvatarGroup_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @
18
19
  const root = ref(null);
19
20
  const overflowElement = useTemplateRef("overflow");
20
21
  const overflowCount = ref(0);
21
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
22
- function dispatch(name, detail) {
23
- return root.value?.dispatchEvent(new CustomEvent(name, {
24
- bubbles: true,
25
- composed: true,
26
- detail
27
- })) ?? true;
28
- }
29
- function read(name) {
30
- if (name === "overflowCount") return overflowCount.value;
31
- return props[name];
32
- }
33
- function write(name, value) {
34
- if (name === "overflowCount") {
35
- overflowCount.value = value;
36
- return true;
37
- }
38
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`);
39
- }
40
- const stops = [];
41
- const host = {
42
- get element() {
43
- return root.value;
44
- },
45
- state: new Proxy({}, {
46
- get: (_target, name) => typeof name === "string" ? read(name) : void 0,
47
- set: (_target, name, value) => typeof name === "string" && write(name, value)
48
- }),
49
- refs: { get overflow() {
50
- return overflowElement.value;
51
- } },
52
- elements: new Proxy({}, { get: (_target, name) => {
53
- if (typeof name !== "string" || root.value === null) return void 0;
54
- return (root.value instanceof HTMLFormElement ? root.value : root.value.querySelector("form"))?.elements.namedItem(name) ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? void 0;
55
- } }),
56
- signal(initialValue) {
57
- const value = shallowRef(initialValue);
58
- return {
59
- get: () => value.value,
60
- set: (next) => {
61
- if (!Object.is(value.value, next)) value.value = next;
62
- },
63
- update: (next) => {
64
- const updated = next(value.value);
65
- if (!Object.is(value.value, updated)) value.value = updated;
66
- }
67
- };
68
- },
69
- computed(compute) {
70
- const value = computed(compute);
71
- return { get: () => value.value };
72
- },
73
- effect(run) {
74
- const stop = watchEffect((onCleanup) => {
75
- const cleanup = run();
76
- if (typeof cleanup === "function") onCleanup(cleanup);
77
- }, { flush: "post" });
78
- stops.push(stop);
79
- return stop;
80
- },
81
- on(event, listener) {
82
- const element = root.value;
83
- element?.addEventListener(event, listener);
84
- const off = () => element?.removeEventListener(event, listener);
85
- stops.push(off);
86
- return off;
87
- },
88
- dispatch
89
- };
90
- let cleanup;
91
- onMounted(() => {
92
- Promise.resolve(controllerModule.default(host)).then((result) => {
93
- cleanup = result;
94
- });
95
- });
96
- onBeforeUnmount(() => {
97
- for (const stop of stops.splice(0)) stop();
98
- if (typeof cleanup === "function") cleanup();
22
+ const dispatch = createDispatch(root);
23
+ useComponentHost(controllerModule.default, {
24
+ root,
25
+ dispatch,
26
+ props,
27
+ refs: { overflow: overflowElement },
28
+ state: { overflowCount }
99
29
  });
100
30
  return (_ctx, _cache) => {
101
31
  return openBlock(), createElementBlock("div", mergeProps({
@@ -114,6 +44,6 @@ var UiAvatarGroup_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @
114
44
  }, toDisplayString(`+${overflowCount.value}`), 9, _hoisted_2)], 16, _hoisted_1);
115
45
  };
116
46
  }
117
- }), [["__scopeId", "data-v-2ad5d86f"]]);
47
+ }), [["__scopeId", "data-v-cbb93f58"]]);
118
48
  //#endregion
119
49
  export { UiAvatarGroup_default as t };
@@ -19,6 +19,6 @@ var UiBadge_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
19
19
  return openBlock(), createElementBlock("span", mergeProps({ "data-component": "ui-badge" }, _ctx.$attrs, { "data-ui-badge-state": hostState.value || void 0 }), [renderSlot(_ctx.$slots, "default", {}, void 0, true)], 16, _hoisted_1);
20
20
  };
21
21
  }
22
- }), [["__scopeId", "data-v-7e9b5784"]]);
22
+ }), [["__scopeId", "data-v-90c7d1bb"]]);
23
23
  //#endregion
24
24
  export { UiBadge_default as t };
@@ -41,6 +41,6 @@ var UiButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
41
41
  }), [renderSlot(_ctx.$slots, "default", {}, void 0, true)], 16, _hoisted_1);
42
42
  };
43
43
  }
44
- }), [["__scopeId", "data-v-405b2c60"]]);
44
+ }), [["__scopeId", "data-v-4fd0ad7f"]]);
45
45
  //#endregion
46
46
  export { UiButton_default as t };