@threadlabs/looma 0.1.13 → 0.1.15

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 (69) hide show
  1. package/dist/{chunk-DQZJTDIB.js → chunk-SVINNT3E.js} +29 -27
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/looma.cjs.js +1 -1
  4. package/dist/cjs/ui-tree-item.cjs.entry.js +694 -0
  5. package/dist/cjs/ui-tree.cjs.entry.js +257 -0
  6. package/dist/collection/collection-manifest.json +3 -1
  7. package/dist/collection/components/ui-tree/ui-tree.css +11 -0
  8. package/dist/collection/components/ui-tree/ui-tree.js +252 -0
  9. package/dist/collection/components/ui-tree-item/ui-tree-item.css +213 -0
  10. package/dist/collection/components/ui-tree-item/ui-tree-item.js +347 -0
  11. package/dist/collection/utils/drag-drop.js +51 -0
  12. package/dist/components/index.d.ts +4 -0
  13. package/dist/components/index.js +1 -1
  14. package/dist/components/ui-tree-item.d.ts +11 -0
  15. package/dist/components/ui-tree-item.js +13 -0
  16. package/dist/components/ui-tree.d.ts +11 -0
  17. package/dist/components/ui-tree.js +1 -0
  18. package/dist/esm/loader.js +1 -1
  19. package/dist/esm/looma.js +1 -1
  20. package/dist/esm/ui-tree-item.entry.js +692 -0
  21. package/dist/esm/ui-tree.entry.js +255 -0
  22. package/dist/index.cjs +687 -15
  23. package/dist/index.d.cts +17 -1
  24. package/dist/index.d.ts +17 -1
  25. package/dist/index.js +44 -3
  26. package/dist/looma/looma.esm.js +1 -1
  27. package/dist/looma/p-95368dee.entry.js +1 -0
  28. package/dist/looma/p-ef9ca2ed.entry.js +13 -0
  29. package/dist/types/components/ui-tree/ui-tree.d.ts +28 -0
  30. package/dist/types/components/ui-tree-item/ui-tree-item.d.ts +36 -0
  31. package/dist/types/components.d.ts +176 -0
  32. package/dist/types/utils/drag-drop.d.ts +15 -0
  33. package/dist/{ui-affordance-scope.entry-SWTDTGGU.js → ui-affordance-scope.entry-PFP2TDKO.js} +1 -1
  34. package/dist/{ui-avatar-group.entry-VUYE2XOM.js → ui-avatar-group.entry-DQDP325O.js} +1 -1
  35. package/dist/{ui-avatar.entry-2CKHEJTS.js → ui-avatar.entry-WYIDMOFE.js} +1 -1
  36. package/dist/{ui-badge.entry-4SWSD3R5.js → ui-badge.entry-VGHXPEDT.js} +1 -1
  37. package/dist/{ui-button.entry-SS3AS32R.js → ui-button.entry-LKPLOJ22.js} +1 -1
  38. package/dist/{ui-checkbox.entry-V7OYTOLW.js → ui-checkbox.entry-J74HEA22.js} +1 -1
  39. package/dist/{ui-context-menu.entry-UCLTQESP.js → ui-context-menu.entry-MQM2FCLI.js} +1 -1
  40. package/dist/{ui-dialog.entry-PXIVZF7D.js → ui-dialog.entry-DQMMDO4Z.js} +1 -1
  41. package/dist/{ui-disclosure.entry-ZADBPM2D.js → ui-disclosure.entry-ONF7UZDC.js} +1 -1
  42. package/dist/{ui-floating-action-button.entry-WNBWY36T.js → ui-floating-action-button.entry-FKTGVC5T.js} +1 -1
  43. package/dist/{ui-form-field.entry-RZPSWN6Y.js → ui-form-field.entry-M3ISWQNU.js} +1 -1
  44. package/dist/{ui-icon-button.entry-ILU7RD7M.js → ui-icon-button.entry-AWFIQUHM.js} +1 -1
  45. package/dist/{ui-input.entry-FEIUK4EE.js → ui-input.entry-JZ6RETMT.js} +1 -1
  46. package/dist/{ui-menu-item.entry-UJVECPSK.js → ui-menu-item.entry-5MFR5LFL.js} +1 -1
  47. package/dist/{ui-menu.entry-MTCE3F5U.js → ui-menu.entry-IOEIDATQ.js} +1 -1
  48. package/dist/{ui-popover.entry-OAME35VB.js → ui-popover.entry-ELCMKO6Y.js} +1 -1
  49. package/dist/{ui-radio-group.entry-CPFX4LVA.js → ui-radio-group.entry-RJHUPPEM.js} +1 -1
  50. package/dist/{ui-radio.entry-44OTRYPB.js → ui-radio.entry-3VRDPOY4.js} +1 -1
  51. package/dist/{ui-search-result-row.entry-ZU5SL5OP.js → ui-search-result-row.entry-J34YPAV7.js} +1 -1
  52. package/dist/{ui-search-shell.entry-G7HG4RKU.js → ui-search-shell.entry-IJ4UUP27.js} +1 -1
  53. package/dist/{ui-select.entry-NAONXMFG.js → ui-select.entry-C6YD3HQ5.js} +1 -1
  54. package/dist/{ui-switch.entry-SE4ZTCS2.js → ui-switch.entry-UZDF5QTI.js} +1 -1
  55. package/dist/{ui-tabs.entry-2YG2JE3K.js → ui-tabs.entry-YRAKWOMR.js} +1 -1
  56. package/dist/{ui-textarea.entry-PV3APDLY.js → ui-textarea.entry-JLDKFT3K.js} +1 -1
  57. package/dist/{ui-toast-region.entry-WH2OL3FR.js → ui-toast-region.entry-GC7C7KXF.js} +1 -1
  58. package/dist/{ui-tooltip.entry-FY563DP4.js → ui-tooltip.entry-F26XDTYX.js} +1 -1
  59. package/dist/{ui-top-bar.entry-LJSZXFAH.js → ui-top-bar.entry-5W5UA5KV.js} +1 -1
  60. package/dist/ui-tree-item.entry-3LM7IXIK.js +385 -0
  61. package/dist/ui-tree.entry-X4FU42A6.js +244 -0
  62. package/editor.css +42 -0
  63. package/package.json +1 -1
  64. package/styles.css +18 -6
  65. package/vue/{chunk-YN4IUYVY.js → chunk-IITL6UBR.js} +7 -1
  66. package/vue/editor/index.d.ts +41 -3
  67. package/vue/editor/index.js +273 -4
  68. package/vue/index.d.ts +24 -1
  69. package/vue/index.js +5 -1
@@ -0,0 +1,255 @@
1
+ import { r as registerInstance, g as getElement, h, H as Host } from './index-CEeiinfk.js';
2
+ import { d as dispatchDetail } from './events-JwSoedEO.js';
3
+
4
+ /**
5
+ * Classify the pointer against stable edge bands. Containers reserve their
6
+ * middle half for containment; leaf rows split cleanly at their midpoint.
7
+ */
8
+ function classifyDropPosition(rect, clientY, acceptsChildren) {
9
+ const progress = rect.height > 0
10
+ ? Math.min(1, Math.max(0, (clientY - rect.top) / rect.height))
11
+ : 0.5;
12
+ if (!acceptsChildren)
13
+ return progress < 0.5 ? 'before' : 'after';
14
+ if (progress < 0.25)
15
+ return 'before';
16
+ if (progress > 0.75)
17
+ return 'after';
18
+ return 'inside';
19
+ }
20
+ /** Use the rendered row—not the tiny handle—as the browser drag preview. */
21
+ function setElementDragImage(dataTransfer, element) {
22
+ if (!dataTransfer || typeof dataTransfer.setDragImage !== 'function')
23
+ return;
24
+ const { height } = element.getBoundingClientRect();
25
+ dataTransfer.setDragImage(element, 16, Math.max(0, height / 2));
26
+ }
27
+ /** A keyed, replaceable hover timer suitable for expansion and disclosure intent. */
28
+ function createHoverIntent(delay, onIntent) {
29
+ let timer;
30
+ let pendingKey;
31
+ function cancel() {
32
+ if (timer)
33
+ clearTimeout(timer);
34
+ timer = undefined;
35
+ pendingKey = undefined;
36
+ }
37
+ return {
38
+ schedule(key) {
39
+ if (pendingKey === key && timer)
40
+ return;
41
+ cancel();
42
+ pendingKey = key;
43
+ timer = setTimeout(() => {
44
+ timer = undefined;
45
+ const resolvedKey = pendingKey;
46
+ pendingKey = undefined;
47
+ if (resolvedKey)
48
+ onIntent(resolvedKey);
49
+ }, Math.max(0, delay));
50
+ },
51
+ cancel,
52
+ destroy: cancel,
53
+ };
54
+ }
55
+
56
+ const uiTreeCss = () => `:host{--ui-tree-indent:16px;display:block;min-inline-size:0;padding-inline-start:var(--ui-tree-gutter, 22px)}::slotted(ui-tree-item){--ui-tree-indent:inherit}`;
57
+
58
+ const UITree = class {
59
+ constructor(hostRef) {
60
+ registerInstance(this, hostRef);
61
+ }
62
+ get host() { return getElement(this); }
63
+ label = 'Tree';
64
+ hoverExpandDelay = 700;
65
+ source = null;
66
+ target = null;
67
+ position = null;
68
+ hoverIntent = null;
69
+ componentDidLoad() {
70
+ this.hoverIntent = createHoverIntent(this.hoverExpandDelay, this.expandTarget);
71
+ this.host.addEventListener('dragstart', this.onDragStart);
72
+ this.host.addEventListener('dragover', this.onDragOver);
73
+ this.host.addEventListener('dragleave', this.onDragLeave);
74
+ this.host.addEventListener('drop', this.onDrop);
75
+ this.host.addEventListener('dragend', this.onDragEnd);
76
+ this.host.addEventListener('keydown', this.onKeyDown);
77
+ }
78
+ disconnectedCallback() {
79
+ this.hoverIntent?.destroy();
80
+ this.host.removeEventListener('dragstart', this.onDragStart);
81
+ this.host.removeEventListener('dragover', this.onDragOver);
82
+ this.host.removeEventListener('dragleave', this.onDragLeave);
83
+ this.host.removeEventListener('drop', this.onDrop);
84
+ this.host.removeEventListener('dragend', this.onDragEnd);
85
+ this.host.removeEventListener('keydown', this.onKeyDown);
86
+ }
87
+ itemFromEvent(event) {
88
+ return event.composedPath().find(node => (node instanceof HTMLElement && node.localName === 'ui-tree-item')) ?? null;
89
+ }
90
+ itemId(item) {
91
+ return item.itemId || item.getAttribute('item-id') || '';
92
+ }
93
+ rowFor(item) {
94
+ return item.shadowRoot?.querySelector('[part="row"]') ?? null;
95
+ }
96
+ acceptsChildren(item) {
97
+ return Boolean(item.container ?? item.hasAttribute('container'))
98
+ && !Boolean(item.disabled ?? item.hasAttribute('disabled'));
99
+ }
100
+ itemMetadata(item) {
101
+ return {
102
+ type: item.getAttribute('data-drag-type') || item.getAttribute('drag-type') || 'item',
103
+ scope: item.getAttribute('data-drop-scope') || item.getAttribute('drop-scope') || '',
104
+ accepts: (item.getAttribute('data-accepts') || item.getAttribute('accepts') || '')
105
+ .split(',')
106
+ .map(value => value.trim())
107
+ .filter(Boolean),
108
+ };
109
+ }
110
+ permitsDrop(source, target, position) {
111
+ // A tree item can never move into (or beside) one of its own descendants.
112
+ // Reject the target before showing any insertion affordance so the preview
113
+ // stays truthful instead of promising a move the consumer must undo.
114
+ if (source.contains(target))
115
+ return false;
116
+ const sourceMeta = this.itemMetadata(source);
117
+ const targetMeta = this.itemMetadata(target);
118
+ if (position === 'inside') {
119
+ return this.acceptsChildren(target)
120
+ && (targetMeta.accepts.length === 0 || targetMeta.accepts.includes(sourceMeta.type));
121
+ }
122
+ return sourceMeta.type === targetMeta.type;
123
+ }
124
+ clearTarget() {
125
+ this.target?.removeAttribute('data-drop-position');
126
+ this.target = null;
127
+ this.position = null;
128
+ this.hoverIntent?.cancel();
129
+ }
130
+ finishDrag() {
131
+ this.source?.removeAttribute('data-dragging');
132
+ this.source = null;
133
+ this.clearTarget();
134
+ }
135
+ expandTarget = (itemId) => {
136
+ const item = Array.from(this.host.querySelectorAll('ui-tree-item'))
137
+ .find(candidate => this.itemId(candidate) === itemId);
138
+ if (!item || item.getAttribute('aria-expanded') !== 'false')
139
+ return;
140
+ item.dispatchEvent(new CustomEvent('ui-tree-auto-expand'));
141
+ };
142
+ onDragStart = (event) => {
143
+ const item = this.itemFromEvent(event);
144
+ if (!item || !Boolean(item.sortable ?? item.hasAttribute('sortable'))
145
+ || Boolean(item.disabled ?? item.hasAttribute('disabled')))
146
+ return;
147
+ const fromHandle = event.composedPath().some(node => (node instanceof HTMLElement && node.getAttribute('part') === 'drag-handle'));
148
+ if (!fromHandle) {
149
+ event.preventDefault();
150
+ return;
151
+ }
152
+ const sourceId = this.itemId(item);
153
+ const row = this.rowFor(item);
154
+ if (!sourceId || !row) {
155
+ event.preventDefault();
156
+ return;
157
+ }
158
+ this.source = item;
159
+ item.setAttribute('data-dragging', 'true');
160
+ if (event.dataTransfer) {
161
+ event.dataTransfer.effectAllowed = 'move';
162
+ event.dataTransfer.setData('text/plain', sourceId);
163
+ }
164
+ setElementDragImage(event.dataTransfer, row);
165
+ };
166
+ onDragOver = (event) => {
167
+ if (!this.source)
168
+ return;
169
+ const target = this.itemFromEvent(event);
170
+ if (!target || target === this.source) {
171
+ this.clearTarget();
172
+ return;
173
+ }
174
+ const row = this.rowFor(target);
175
+ if (!row)
176
+ return;
177
+ const position = classifyDropPosition(row.getBoundingClientRect(), event.clientY, this.acceptsChildren(target));
178
+ if (!this.permitsDrop(this.source, target, position)) {
179
+ if (event.dataTransfer)
180
+ event.dataTransfer.dropEffect = 'none';
181
+ this.clearTarget();
182
+ return;
183
+ }
184
+ event.preventDefault();
185
+ if (event.dataTransfer)
186
+ event.dataTransfer.dropEffect = 'move';
187
+ if (this.target !== target || this.position !== position) {
188
+ this.clearTarget();
189
+ this.target = target;
190
+ this.position = position;
191
+ target.setAttribute('data-drop-position', position);
192
+ }
193
+ if (position === 'inside' && target.getAttribute('aria-expanded') === 'false') {
194
+ this.hoverIntent?.schedule(this.itemId(target));
195
+ }
196
+ else {
197
+ this.hoverIntent?.cancel();
198
+ }
199
+ };
200
+ onDragLeave = (event) => {
201
+ const related = event.relatedTarget;
202
+ if (related instanceof Node && this.host.contains(related))
203
+ return;
204
+ this.clearTarget();
205
+ };
206
+ onDrop = (event) => {
207
+ if (!this.source || !this.target || !this.position)
208
+ return;
209
+ event.preventDefault();
210
+ const sourceId = this.itemId(this.source);
211
+ const targetId = this.itemId(this.target);
212
+ if (sourceId && targetId) {
213
+ const sourceMeta = this.itemMetadata(this.source);
214
+ const targetMeta = this.itemMetadata(this.target);
215
+ dispatchDetail(this.host, 'reorder', {
216
+ sourceId,
217
+ targetId,
218
+ position: this.position,
219
+ sourceType: sourceMeta.type,
220
+ targetType: targetMeta.type,
221
+ sourceScope: sourceMeta.scope,
222
+ targetScope: targetMeta.scope,
223
+ trigger: 'pointer',
224
+ });
225
+ }
226
+ this.finishDrag();
227
+ };
228
+ onDragEnd = () => {
229
+ this.finishDrag();
230
+ };
231
+ visibleItems() {
232
+ return Array.from(this.host.querySelectorAll('ui-tree-item'))
233
+ .filter(item => item.getClientRects().length > 0 && !item.hasAttribute('disabled'));
234
+ }
235
+ onKeyDown = (event) => {
236
+ const current = this.itemFromEvent(event);
237
+ if (!current)
238
+ return;
239
+ const items = this.visibleItems();
240
+ const index = items.indexOf(current);
241
+ if (index < 0)
242
+ return;
243
+ const next = event.key === 'ArrowDown' ? items[index + 1] : event.key === 'ArrowUp' ? items[index - 1] : null;
244
+ if (!next)
245
+ return;
246
+ event.preventDefault();
247
+ next.focus();
248
+ };
249
+ render() {
250
+ return (h(Host, { key: '5761d2840d2694340a4b937d46522f15f81973ac', role: "tree", "aria-label": this.label || 'Tree' }, h("slot", { key: '08e5a7b489eed4f4eae9de6462104fd12defd336' })));
251
+ }
252
+ };
253
+ UITree.style = uiTreeCss();
254
+
255
+ export { UITree as ui_tree };