@threadlabs/looma 0.1.21 → 0.1.23

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 (248) hide show
  1. package/dist/{chunk-FSGGPFID.js → chunk-GDMQKT5F.js} +63 -31
  2. package/dist/{chunk-SZJQ3NPX.js → chunk-TL4FIE7X.js} +4 -8
  3. package/dist/cjs/{index-D07f6BOw.js → index-BHG9Rpil.js} +33 -0
  4. package/dist/cjs/loader.cjs.js +2 -2
  5. package/dist/cjs/looma.cjs.js +2 -2
  6. package/dist/cjs/{manager-C9j3HZay.js → manager-Ce25WRtl.js} +6 -7
  7. package/dist/cjs/ui-affordance-scope.cjs.entry.js +1 -1
  8. package/dist/cjs/ui-avatar-group.cjs.entry.js +1 -1
  9. package/dist/cjs/ui-avatar.cjs.entry.js +1 -1
  10. package/dist/cjs/ui-badge.cjs.entry.js +1 -1
  11. package/dist/cjs/ui-button.cjs.entry.js +16 -5
  12. package/dist/cjs/ui-checkbox.cjs.entry.js +1 -1
  13. package/dist/cjs/ui-combobox.cjs.entry.js +541 -0
  14. package/dist/cjs/ui-context-menu.cjs.entry.js +3 -3
  15. package/dist/cjs/ui-dialog.cjs.entry.js +3 -3
  16. package/dist/cjs/ui-disclosure.cjs.entry.js +2 -2
  17. package/dist/cjs/ui-floating-action-button.cjs.entry.js +2 -2
  18. package/dist/cjs/ui-form-field.cjs.entry.js +3 -3
  19. package/dist/cjs/ui-icon-button.cjs.entry.js +2 -2
  20. package/dist/cjs/ui-input.cjs.entry.js +11 -6
  21. package/dist/cjs/ui-menu-item.cjs.entry.js +2 -2
  22. package/dist/cjs/ui-menu.cjs.entry.js +3 -3
  23. package/dist/cjs/ui-popover.cjs.entry.js +3 -3
  24. package/dist/cjs/ui-radio-group.cjs.entry.js +2 -2
  25. package/dist/cjs/ui-radio.cjs.entry.js +3 -3
  26. package/dist/cjs/ui-search-result-row.cjs.entry.js +2 -2
  27. package/dist/cjs/ui-search-shell.cjs.entry.js +2 -2
  28. package/dist/cjs/ui-select.cjs.entry.js +15 -7
  29. package/dist/cjs/ui-switch.cjs.entry.js +3 -3
  30. package/dist/cjs/ui-tabs.cjs.entry.js +2 -2
  31. package/dist/cjs/ui-textarea.cjs.entry.js +10 -6
  32. package/dist/cjs/ui-toast-region.cjs.entry.js +2 -2
  33. package/dist/cjs/ui-tooltip.cjs.entry.js +52 -16
  34. package/dist/cjs/ui-top-bar.cjs.entry.js +2 -2
  35. package/dist/cjs/ui-tree-item.cjs.entry.js +7 -3
  36. package/dist/cjs/ui-tree.cjs.entry.js +113 -21
  37. package/dist/collection/collection-manifest.json +1 -0
  38. package/dist/collection/components/ui-button/ui-button.css +36 -26
  39. package/dist/collection/components/ui-button/ui-button.js +14 -3
  40. package/dist/collection/components/ui-combobox/ui-combobox.css +24 -0
  41. package/dist/collection/components/ui-combobox/ui-combobox.js +973 -0
  42. package/dist/collection/components/ui-context-menu/ui-context-menu.js +1 -1
  43. package/dist/collection/components/ui-dialog/ui-dialog.js +1 -1
  44. package/dist/collection/components/ui-disclosure/ui-disclosure.js +1 -1
  45. package/dist/collection/components/ui-floating-action-button/ui-floating-action-button.js +1 -1
  46. package/dist/collection/components/ui-form-field/ui-form-field.css +4 -0
  47. package/dist/collection/components/ui-form-field/ui-form-field.js +1 -1
  48. package/dist/collection/components/ui-icon-button/ui-icon-button.js +1 -1
  49. package/dist/collection/components/ui-input/ui-input.css +8 -6
  50. package/dist/collection/components/ui-input/ui-input.js +11 -7
  51. package/dist/collection/components/ui-menu/ui-menu.js +1 -1
  52. package/dist/collection/components/ui-menu-item/ui-menu-item.js +1 -1
  53. package/dist/collection/components/ui-popover/ui-popover.js +1 -1
  54. package/dist/collection/components/ui-radio/ui-radio.js +2 -2
  55. package/dist/collection/components/ui-radio-group/ui-radio-group.js +1 -1
  56. package/dist/collection/components/ui-search-result-row/ui-search-result-row.js +1 -1
  57. package/dist/collection/components/ui-search-shell/ui-search-shell.js +1 -1
  58. package/dist/collection/components/ui-select/ui-select.css +8 -6
  59. package/dist/collection/components/ui-select/ui-select.js +17 -11
  60. package/dist/collection/components/ui-switch/ui-switch.js +2 -2
  61. package/dist/collection/components/ui-tabs/ui-tabs.js +1 -1
  62. package/dist/collection/components/ui-textarea/ui-textarea.css +7 -6
  63. package/dist/collection/components/ui-textarea/ui-textarea.js +10 -7
  64. package/dist/collection/components/ui-toast-region/ui-toast-region.js +1 -1
  65. package/dist/collection/components/ui-tooltip/ui-tooltip.js +102 -15
  66. package/dist/collection/components/ui-top-bar/ui-top-bar.js +1 -1
  67. package/dist/collection/components/ui-tree/ui-tree.js +132 -20
  68. package/dist/collection/components/ui-tree-item/ui-tree-item.js +44 -2
  69. package/dist/collection/field/combobox.js +4 -0
  70. package/dist/collection/field/valibot.js +5 -0
  71. package/dist/collection/field/validation.js +62 -0
  72. package/dist/collection/overlay/manager.js +6 -7
  73. package/dist/components/index.d.ts +2 -0
  74. package/dist/components/index.js +1 -1
  75. package/dist/components/p-Bh_1GxOD.js +1 -0
  76. package/dist/components/p-C-0syqXZ.js +1 -0
  77. package/dist/components/p-CaietZcq.js +1 -0
  78. package/dist/components/p-DHd18bK7.js +1 -0
  79. package/dist/components/ui-affordance-scope.js +1 -1
  80. package/dist/components/ui-avatar-group.js +1 -1
  81. package/dist/components/ui-avatar.js +1 -1
  82. package/dist/components/ui-badge.js +1 -1
  83. package/dist/components/ui-button.js +1 -1
  84. package/dist/components/ui-checkbox.js +1 -1
  85. package/dist/components/ui-combobox.d.ts +11 -0
  86. package/dist/components/ui-combobox.js +1 -0
  87. package/dist/components/ui-context-menu.js +1 -1
  88. package/dist/components/ui-dialog.js +1 -1
  89. package/dist/components/ui-disclosure.js +1 -1
  90. package/dist/components/ui-floating-action-button.js +1 -1
  91. package/dist/components/ui-form-field.js +1 -1
  92. package/dist/components/ui-icon-button.js +1 -1
  93. package/dist/components/ui-input.js +1 -1
  94. package/dist/components/ui-menu-item.js +1 -1
  95. package/dist/components/ui-menu.js +1 -1
  96. package/dist/components/ui-popover.js +1 -1
  97. package/dist/components/ui-radio-group.js +1 -1
  98. package/dist/components/ui-radio.js +1 -1
  99. package/dist/components/ui-search-result-row.js +1 -1
  100. package/dist/components/ui-search-shell.js +1 -1
  101. package/dist/components/ui-select.js +1 -1
  102. package/dist/components/ui-switch.js +1 -1
  103. package/dist/components/ui-tabs.js +1 -1
  104. package/dist/components/ui-textarea.js +1 -1
  105. package/dist/components/ui-toast-region.js +1 -1
  106. package/dist/components/ui-tooltip.js +1 -1
  107. package/dist/components/ui-top-bar.js +1 -1
  108. package/dist/components/ui-tree-item.js +2 -2
  109. package/dist/components/ui-tree.js +1 -1
  110. package/dist/esm/{index-CEeiinfk.js → index-8BGiMGQ0.js} +33 -1
  111. package/dist/esm/loader.js +3 -3
  112. package/dist/esm/looma.js +3 -3
  113. package/dist/esm/{manager-PM9a74r7.js → manager-C-0syqXZ.js} +6 -7
  114. package/dist/esm/ui-affordance-scope.entry.js +1 -1
  115. package/dist/esm/ui-avatar-group.entry.js +1 -1
  116. package/dist/esm/ui-avatar.entry.js +1 -1
  117. package/dist/esm/ui-badge.entry.js +1 -1
  118. package/dist/esm/ui-button.entry.js +16 -5
  119. package/dist/esm/ui-checkbox.entry.js +1 -1
  120. package/dist/esm/ui-combobox.entry.js +539 -0
  121. package/dist/esm/ui-context-menu.entry.js +3 -3
  122. package/dist/esm/ui-dialog.entry.js +3 -3
  123. package/dist/esm/ui-disclosure.entry.js +2 -2
  124. package/dist/esm/ui-floating-action-button.entry.js +2 -2
  125. package/dist/esm/ui-form-field.entry.js +3 -3
  126. package/dist/esm/ui-icon-button.entry.js +2 -2
  127. package/dist/esm/ui-input.entry.js +11 -6
  128. package/dist/esm/ui-menu-item.entry.js +2 -2
  129. package/dist/esm/ui-menu.entry.js +3 -3
  130. package/dist/esm/ui-popover.entry.js +3 -3
  131. package/dist/esm/ui-radio-group.entry.js +2 -2
  132. package/dist/esm/ui-radio.entry.js +3 -3
  133. package/dist/esm/ui-search-result-row.entry.js +2 -2
  134. package/dist/esm/ui-search-shell.entry.js +2 -2
  135. package/dist/esm/ui-select.entry.js +15 -7
  136. package/dist/esm/ui-switch.entry.js +3 -3
  137. package/dist/esm/ui-tabs.entry.js +2 -2
  138. package/dist/esm/ui-textarea.entry.js +10 -6
  139. package/dist/esm/ui-toast-region.entry.js +2 -2
  140. package/dist/esm/ui-tooltip.entry.js +52 -16
  141. package/dist/esm/ui-top-bar.entry.js +2 -2
  142. package/dist/esm/ui-tree-item.entry.js +7 -3
  143. package/dist/esm/ui-tree.entry.js +113 -21
  144. package/dist/index.cjs +911 -135
  145. package/dist/index.d.cts +104 -1
  146. package/dist/index.d.ts +104 -1
  147. package/dist/index.js +62 -8
  148. package/dist/looma/looma.esm.js +1 -1
  149. package/dist/looma/{p-0198bb21.entry.js → p-13347631.entry.js} +1 -1
  150. package/dist/looma/p-14c081cf.entry.js +1 -0
  151. package/dist/looma/{p-0f45c5f0.entry.js → p-25366205.entry.js} +1 -1
  152. package/dist/looma/{p-a9f46811.entry.js → p-2e3aa869.entry.js} +1 -1
  153. package/dist/looma/p-40fe7fee.entry.js +1 -0
  154. package/dist/looma/p-446cda76.entry.js +1 -0
  155. package/dist/looma/p-4fc1b005.entry.js +13 -0
  156. package/dist/looma/p-582973b5.entry.js +1 -0
  157. package/dist/looma/{p-d273b857.entry.js → p-5a87b59d.entry.js} +1 -1
  158. package/dist/looma/{p-2ed7e241.entry.js → p-5da09f47.entry.js} +1 -1
  159. package/dist/looma/{p-7e94d90d.entry.js → p-69a5557b.entry.js} +1 -1
  160. package/dist/looma/p-6a8a4736.entry.js +1 -0
  161. package/dist/looma/{p-caa8fc7b.entry.js → p-6bf4038b.entry.js} +1 -1
  162. package/dist/looma/p-7e0bb7f6.entry.js +1 -0
  163. package/dist/looma/{p-ed5abf6d.entry.js → p-8204fee6.entry.js} +1 -1
  164. package/dist/looma/{p-5ba9d496.entry.js → p-8238e0dc.entry.js} +1 -1
  165. package/dist/looma/p-8BGiMGQ0.js +2 -0
  166. package/dist/looma/{p-051f578c.entry.js → p-8b8840b8.entry.js} +1 -1
  167. package/dist/looma/{p-1674cda4.entry.js → p-99d88efb.entry.js} +1 -1
  168. package/dist/looma/p-C-0syqXZ.js +1 -0
  169. package/dist/looma/p-a27669b1.entry.js +1 -0
  170. package/dist/looma/{p-11083743.entry.js → p-a6ee76b7.entry.js} +1 -1
  171. package/dist/looma/p-a90d2821.entry.js +1 -0
  172. package/dist/looma/{p-2e6f791e.entry.js → p-add36e74.entry.js} +1 -1
  173. package/dist/looma/{p-0584a051.entry.js → p-b6398a6b.entry.js} +1 -1
  174. package/dist/looma/{p-078f9fb8.entry.js → p-d50faaff.entry.js} +1 -1
  175. package/dist/looma/{p-b7aa4488.entry.js → p-d77278ce.entry.js} +1 -1
  176. package/dist/looma/p-d9ec13b7.entry.js +1 -0
  177. package/dist/looma/{p-1681b218.entry.js → p-ecf8005f.entry.js} +1 -1
  178. package/dist/looma/p-ed368426.entry.js +1 -0
  179. package/dist/looma/{p-063f5a89.entry.js → p-f0487ff3.entry.js} +1 -1
  180. package/dist/looma/p-f74e5546.entry.js +1 -0
  181. package/dist/types/components/ui-combobox/ui-combobox.d.ts +93 -0
  182. package/dist/types/components/ui-input/ui-input.d.ts +1 -1
  183. package/dist/types/components/ui-select/ui-select.d.ts +3 -2
  184. package/dist/types/components/ui-textarea/ui-textarea.d.ts +1 -1
  185. package/dist/types/components/ui-tooltip/ui-tooltip.d.ts +18 -1
  186. package/dist/types/components/ui-tree/ui-tree.d.ts +11 -1
  187. package/dist/types/components/ui-tree-item/ui-tree-item.d.ts +4 -0
  188. package/dist/types/components.d.ts +260 -28
  189. package/dist/types/field/combobox.d.ts +46 -0
  190. package/dist/types/field/valibot.d.ts +7 -0
  191. package/dist/types/field/validation.d.ts +56 -0
  192. package/dist/{ui-affordance-scope.entry-Z3H4CM6J.js → ui-affordance-scope.entry-VO4C2MZX.js} +1 -1
  193. package/dist/{ui-avatar-group.entry-ONGVFRD3.js → ui-avatar-group.entry-TAXJRIIU.js} +1 -1
  194. package/dist/{ui-avatar.entry-TBA3IEED.js → ui-avatar.entry-T6FU6ZYM.js} +1 -1
  195. package/dist/{ui-badge.entry-DKBPJ7G7.js → ui-badge.entry-MZFYNBMJ.js} +1 -1
  196. package/dist/ui-button.entry-7UXMUGHN.js +80 -0
  197. package/dist/{ui-checkbox.entry-QJTO2U6Z.js → ui-checkbox.entry-DMZJB3RE.js} +1 -1
  198. package/dist/ui-combobox.entry-ZCTPXEES.js +553 -0
  199. package/dist/{ui-context-menu.entry-CC4VXCEB.js → ui-context-menu.entry-2WMCBGCP.js} +6 -6
  200. package/dist/{ui-dialog.entry-GPJWOH5Z.js → ui-dialog.entry-WO23XOSW.js} +6 -6
  201. package/dist/{ui-disclosure.entry-EGG3HXD4.js → ui-disclosure.entry-USX7OUEW.js} +2 -2
  202. package/dist/{ui-floating-action-button.entry-XUD44HRX.js → ui-floating-action-button.entry-MXDIN7MV.js} +2 -2
  203. package/dist/{ui-form-field.entry-UHLNDUXR.js → ui-form-field.entry-7ZCMEHPY.js} +3 -3
  204. package/dist/{ui-icon-button.entry-6HDCV3E7.js → ui-icon-button.entry-MJUNXHBU.js} +2 -2
  205. package/dist/{ui-input.entry-73QXAVLL.js → ui-input.entry-AWG63YIG.js} +8 -6
  206. package/dist/{ui-menu-item.entry-HCZRSY5Y.js → ui-menu-item.entry-HFTWG62N.js} +2 -2
  207. package/dist/{ui-menu.entry-ASIVAX6M.js → ui-menu.entry-IT3GW5TL.js} +7 -7
  208. package/dist/{ui-popover.entry-WSQ7AEJN.js → ui-popover.entry-ZQQB4N6E.js} +6 -6
  209. package/dist/{ui-radio-group.entry-2N7BEBJW.js → ui-radio-group.entry-V7PCTS7I.js} +2 -2
  210. package/dist/{ui-radio.entry-TOM6HBXP.js → ui-radio.entry-JYH6TQBI.js} +3 -3
  211. package/dist/{ui-search-result-row.entry-KA3P76WE.js → ui-search-result-row.entry-JBNYXXUN.js} +2 -2
  212. package/dist/{ui-search-shell.entry-ERMS7TIH.js → ui-search-shell.entry-TEAWE76O.js} +2 -2
  213. package/dist/{ui-select.entry-KDIM3SWS.js → ui-select.entry-F3A6TE2U.js} +13 -7
  214. package/dist/{ui-switch.entry-VRTB6X4D.js → ui-switch.entry-MJIICMP2.js} +3 -3
  215. package/dist/{ui-tabs.entry-GIAO5W3U.js → ui-tabs.entry-6REFIUHV.js} +2 -2
  216. package/dist/{ui-textarea.entry-T6YH4HVG.js → ui-textarea.entry-OJTXCED7.js} +8 -6
  217. package/dist/{ui-toast-region.entry-DBQCXOPJ.js → ui-toast-region.entry-NOFXLKPS.js} +5 -5
  218. package/dist/{ui-tooltip.entry-VS26OECS.js → ui-tooltip.entry-COWTWVHX.js} +57 -21
  219. package/dist/{ui-top-bar.entry-HGWP6PFQ.js → ui-top-bar.entry-PIAWXJNV.js} +2 -2
  220. package/dist/{ui-tree-item.entry-ZRXUIZDR.js → ui-tree-item.entry-BSEWNL2O.js} +7 -3
  221. package/dist/{ui-tree.entry-TC2SCQJF.js → ui-tree.entry-XYI3ZFAZ.js} +105 -20
  222. package/dist/valibot.d.ts +52 -0
  223. package/dist/valibot.js +7 -0
  224. package/package.json +11 -3
  225. package/styles.css +36 -20
  226. package/theme-high-contrast.css +12 -0
  227. package/tokens.css +23 -0
  228. package/vue/{chunk-5KWCMTXB.js → chunk-JLW23USW.js} +88 -1
  229. package/vue/editor/index.js +1 -1
  230. package/vue/index.d.ts +123 -1
  231. package/vue/index.js +3 -1
  232. package/dist/components/p-CEYIKqYc.js +0 -1
  233. package/dist/components/p-CIA4RyEp.js +0 -1
  234. package/dist/components/p-PM9a74r7.js +0 -1
  235. package/dist/looma/p-34417499.entry.js +0 -1
  236. package/dist/looma/p-4b422d40.entry.js +0 -1
  237. package/dist/looma/p-54722713.entry.js +0 -13
  238. package/dist/looma/p-54c41576.entry.js +0 -1
  239. package/dist/looma/p-5d4713a6.entry.js +0 -1
  240. package/dist/looma/p-624ba086.entry.js +0 -1
  241. package/dist/looma/p-8d5adb17.entry.js +0 -1
  242. package/dist/looma/p-9194a99d.entry.js +0 -1
  243. package/dist/looma/p-CEeiinfk.js +0 -2
  244. package/dist/looma/p-PM9a74r7.js +0 -1
  245. package/dist/looma/p-a33522a2.entry.js +0 -1
  246. package/dist/looma/p-a5127c7d.entry.js +0 -1
  247. package/dist/looma/p-b0431118.entry.js +0 -1
  248. package/dist/ui-button.entry-U2MMIHLY.js +0 -71
@@ -1,5 +1,5 @@
1
1
  import { Host, h } from "@stencil/core";
2
- import { openOverlay, closeOverlay, requestTopOverlayClose } from "../../overlay/manager";
2
+ import { openOverlay, closeOverlay } from "../../overlay/manager";
3
3
  import { dispatchDetail } from "../../utils/events";
4
4
  import { createAnchoredSurface, } from "../../overlay/positioning";
5
5
  export class UITooltip {
@@ -12,6 +12,12 @@ export class UITooltip {
12
12
  showDelay = 500;
13
13
  /** Pointer leave grace period in milliseconds. */
14
14
  hideDelay = 100;
15
+ /** Click or tap pins the description; activate again to dismiss. */
16
+ toggleOnClick = false;
17
+ pinned = false;
18
+ focused = false;
19
+ opened;
20
+ closed;
15
21
  internalOpen = false;
16
22
  overlayId = `ui-tooltip-${Math.random().toString(36).slice(2, 11)}`;
17
23
  trigger = null;
@@ -45,11 +51,14 @@ export class UITooltip {
45
51
  }
46
52
  }
47
53
  componentDidLoad() {
54
+ if (!this.host.id)
55
+ this.host.id = this.overlayId;
48
56
  this.syncFromProp();
49
57
  this.internalOpen = this.internalOpen || this.defaultOpen;
50
58
  this.syncTrigger();
51
59
  this.setupSurface();
52
- this.host.addEventListener('keydown', this.onKeydown);
60
+ this.host.addEventListener('pointerenter', this.onSurfaceEnter);
61
+ this.host.addEventListener('pointerleave', this.onTriggerLeave);
53
62
  this.syncOverlay();
54
63
  }
55
64
  componentDidUpdate() {
@@ -60,12 +69,13 @@ export class UITooltip {
60
69
  this.detachTriggerListeners();
61
70
  this.surface?.destroy();
62
71
  this.surface = null;
63
- this.host.removeEventListener('keydown', this.onKeydown);
72
+ this.host.removeEventListener('pointerenter', this.onSurfaceEnter);
73
+ this.host.removeEventListener('pointerleave', this.onTriggerLeave);
64
74
  closeOverlay(this.overlayId);
65
75
  }
66
76
  syncTrigger() {
67
77
  const next = this.for
68
- ? this.host.ownerDocument.getElementById(this.for)
78
+ ? this.host.getRootNode().getElementById(this.for)
69
79
  : this.host.previousElementSibling;
70
80
  if (next === this.trigger)
71
81
  return;
@@ -85,6 +95,11 @@ export class UITooltip {
85
95
  this.detachTriggerListeners();
86
96
  if (!this.trigger)
87
97
  return;
98
+ const ids = new Set((this.trigger.getAttribute('aria-describedby') || '').split(/\s+/).filter(Boolean));
99
+ ids.add(this.host.id);
100
+ this.trigger.setAttribute('aria-describedby', [...ids].join(' '));
101
+ this.trigger.addEventListener('click', this.onTriggerClick);
102
+ this.trigger.addEventListener('keydown', this.onTriggerKeydown);
88
103
  this.trigger.addEventListener('pointerenter', this.onTriggerEnter);
89
104
  this.trigger.addEventListener('pointerleave', this.onTriggerLeave);
90
105
  this.trigger.addEventListener('focusin', this.onTriggerFocusIn);
@@ -93,6 +108,13 @@ export class UITooltip {
93
108
  detachTriggerListeners() {
94
109
  if (!this.trigger)
95
110
  return;
111
+ const ids = (this.trigger.getAttribute('aria-describedby') || '').split(/\s+/).filter(id => id && id !== this.host.id);
112
+ if (ids.length)
113
+ this.trigger.setAttribute('aria-describedby', ids.join(' '));
114
+ else
115
+ this.trigger.removeAttribute('aria-describedby');
116
+ this.trigger.removeEventListener('click', this.onTriggerClick);
117
+ this.trigger.removeEventListener('keydown', this.onTriggerKeydown);
96
118
  this.trigger.removeEventListener('pointerenter', this.onTriggerEnter);
97
119
  this.trigger.removeEventListener('pointerleave', this.onTriggerLeave);
98
120
  this.trigger.removeEventListener('focusin', this.onTriggerFocusIn);
@@ -124,7 +146,21 @@ export class UITooltip {
124
146
  trigger,
125
147
  });
126
148
  }
127
- onTriggerEnter = () => {
149
+ onSurfaceEnter = () => this.clearHideTimer();
150
+ onTriggerClick = (event) => {
151
+ if (!this.toggleOnClick)
152
+ return;
153
+ this.clearTimers();
154
+ this.pinned = !this.pinned;
155
+ this.setInteractionOpen(this.pinned, event.detail === 0 ? 'keyboard' : 'pointer');
156
+ };
157
+ onTriggerKeydown = (event) => {
158
+ if (event.key === 'Escape')
159
+ this.clearTimers();
160
+ };
161
+ onTriggerEnter = (event) => {
162
+ if (event.pointerType === 'touch')
163
+ return;
128
164
  this.clearHideTimer();
129
165
  if (this.internalOpen || this.showTimer !== null)
130
166
  return;
@@ -135,7 +171,7 @@ export class UITooltip {
135
171
  };
136
172
  onTriggerLeave = () => {
137
173
  this.clearShowTimer();
138
- if (!this.internalOpen || this.hideTimer !== null)
174
+ if (this.focused || this.pinned || !this.internalOpen || this.hideTimer !== null)
139
175
  return;
140
176
  this.hideTimer = setTimeout(() => {
141
177
  this.hideTimer = null;
@@ -143,6 +179,7 @@ export class UITooltip {
143
179
  }, Math.max(0, this.hideDelay));
144
180
  };
145
181
  onTriggerFocusIn = () => {
182
+ this.focused = true;
146
183
  this.clearTimers();
147
184
  this.setInteractionOpen(true, 'keyboard');
148
185
  };
@@ -150,28 +187,25 @@ export class UITooltip {
150
187
  const related = e.relatedTarget;
151
188
  if (related && this.host.contains(related))
152
189
  return;
190
+ this.focused = false;
191
+ this.pinned = false;
153
192
  this.clearTimers();
154
193
  this.setInteractionOpen(false, 'keyboard');
155
194
  };
156
195
  handleRequestClose(reason, trigger) {
157
- if (reason === 'escape') {
196
+ if (reason === 'escape' || (reason === 'light-dismiss' && this.toggleOnClick)) {
197
+ this.pinned = false;
158
198
  this.clearTimers();
159
199
  this.internalOpen = false;
160
200
  dispatchDetail(this.host, 'close', {
161
201
  open: false,
162
- reason: 'escape',
202
+ reason,
163
203
  trigger: trigger,
164
204
  });
165
- this.trigger?.focus();
166
205
  }
167
206
  }
168
- onKeydown = (e) => {
169
- if (e.key === 'Escape') {
170
- requestTopOverlayClose('escape', 'keyboard');
171
- }
172
- };
173
207
  render() {
174
- return (h(Host, { key: '4c3890a7371508ede06a5b370d1cec32db25280f', role: "tooltip", hidden: !this.internalOpen, "data-open": this.internalOpen ? '' : undefined, onKeyDown: this.onKeydown }, h("slot", { key: '2e3bcd0dc69b0c3e3376d73dc4efc82e4f4cfaaa' })));
208
+ return (h(Host, { key: 'b0199c23316a707ae3e1e7c361f2838872f62221', role: "tooltip", hidden: !this.internalOpen, "data-open": this.internalOpen ? '' : undefined }, h("slot", { key: 'd0c7822f2f47848a509bf8e310806edbdb320f02' })));
175
209
  }
176
210
  static get is() { return "ui-tooltip"; }
177
211
  static get encapsulation() { return "shadow"; }
@@ -313,6 +347,26 @@ export class UITooltip {
313
347
  "reflect": false,
314
348
  "attribute": "hide-delay",
315
349
  "defaultValue": "100"
350
+ },
351
+ "toggleOnClick": {
352
+ "type": "boolean",
353
+ "mutable": false,
354
+ "complexType": {
355
+ "original": "boolean",
356
+ "resolved": "boolean",
357
+ "references": {}
358
+ },
359
+ "required": false,
360
+ "optional": false,
361
+ "docs": {
362
+ "tags": [],
363
+ "text": "Click or tap pins the description; activate again to dismiss."
364
+ },
365
+ "getter": false,
366
+ "setter": false,
367
+ "reflect": false,
368
+ "attribute": "toggle-on-click",
369
+ "defaultValue": "false"
316
370
  }
317
371
  };
318
372
  }
@@ -321,6 +375,39 @@ export class UITooltip {
321
375
  "internalOpen": {}
322
376
  };
323
377
  }
378
+ static get events() {
379
+ return [{
380
+ "method": "opened",
381
+ "name": "open",
382
+ "bubbles": true,
383
+ "cancelable": true,
384
+ "composed": true,
385
+ "docs": {
386
+ "tags": [],
387
+ "text": ""
388
+ },
389
+ "complexType": {
390
+ "original": "{ open: boolean; reason: string; trigger: string }",
391
+ "resolved": "{ open: boolean; reason: string; trigger: string; }",
392
+ "references": {}
393
+ }
394
+ }, {
395
+ "method": "closed",
396
+ "name": "close",
397
+ "bubbles": true,
398
+ "cancelable": true,
399
+ "composed": true,
400
+ "docs": {
401
+ "tags": [],
402
+ "text": ""
403
+ },
404
+ "complexType": {
405
+ "original": "{ open: boolean; reason: string; trigger: string }",
406
+ "resolved": "{ open: boolean; reason: string; trigger: string; }",
407
+ "references": {}
408
+ }
409
+ }];
410
+ }
324
411
  static get elementRef() { return "host"; }
325
412
  static get watchers() {
326
413
  return [{
@@ -27,7 +27,7 @@ export class UITopBar {
27
27
  this.hasActions = slotHasContent(this.actionsSlot);
28
28
  };
29
29
  render() {
30
- return (h(Host, { key: '15c840c082724df0ec39ab6ad4e55f99192df5be' }, h("header", { key: '790afaeecdb3e598b8365391f57ee1e2d8ca69a2', class: "top-bar", part: "base" }, h("div", { key: 'fab822f5875c7e3b8e267be42c075597d79374fa', class: "top-bar__leading", hidden: !this.hasLeading }, h("slot", { key: '0723013c4b674964e4029442b715daa9eb0036db', name: "leading", ref: (el) => (this.leadingSlot = el), onSlotchange: this.syncSlots })), h("div", { key: '77fc006257b7fa6a191191d9969ea66445b8bc3e', class: "top-bar__title" }, h("slot", { key: 'e8a07f1f767c1c0fa1244abcf3bb0e697e36a4fe' })), h("div", { key: 'bde5cdf797ae898f68eddeab362b8395f89bdf28', class: "top-bar__search", hidden: !this.hasSearch }, h("slot", { key: '8b059d6123e94f3b7e18c15c88828ee9c6436136', name: "search", ref: (el) => (this.searchSlot = el), onSlotchange: this.syncSlots })), h("div", { key: 'c262446cf29873903530ea3f840de4de9db3de82', class: "top-bar__actions", hidden: !this.hasActions }, h("slot", { key: 'f417dbc8cc0115a455a72ce0feb5f32b323ce68f', name: "actions", ref: (el) => (this.actionsSlot = el), onSlotchange: this.syncSlots })))));
30
+ return (h(Host, { key: '730e45232ab2b86c2ac99dba773f4ca15d7c3c51' }, h("header", { key: 'f94f9b4f3f5930fda950895d2eec01d3ec175479', class: "top-bar", part: "base" }, h("div", { key: '038f6a404b0f159b4b826ada73d3c920266354c8', class: "top-bar__leading", hidden: !this.hasLeading }, h("slot", { key: '2d415368310c319eca3f3eb9b2c885ef79bb4107', name: "leading", ref: (el) => (this.leadingSlot = el), onSlotchange: this.syncSlots })), h("div", { key: 'dfd78b02066a91e9c610e4655a70da704ad65327', class: "top-bar__title" }, h("slot", { key: '499e24a864a31f6e400fd02aab4a3f960c87e572' })), h("div", { key: '5aa94952996487651dffecd2e351548631fa29b6', class: "top-bar__search", hidden: !this.hasSearch }, h("slot", { key: 'eddad95f8acf787ee0cead2a46e7961a06375d5c', name: "search", ref: (el) => (this.searchSlot = el), onSlotchange: this.syncSlots })), h("div", { key: 'dc69d492aa221a8beb888350bf101f8beeceede9', class: "top-bar__actions", hidden: !this.hasActions }, h("slot", { key: '7cde7e062f487da8209738a32415636c7a6b72f0', name: "actions", ref: (el) => (this.actionsSlot = el), onSlotchange: this.syncSlots })))));
31
31
  }
32
32
  static get is() { return "ui-top-bar"; }
33
33
  static get encapsulation() { return "shadow"; }
@@ -5,13 +5,19 @@ export class UITree {
5
5
  host;
6
6
  label = 'Tree';
7
7
  hoverExpandDelay = 700;
8
+ /** Maximum resulting item depth accepted by pointer reordering. Zero is unlimited. */
9
+ maxDepth = 0;
8
10
  source = null;
9
11
  target = null;
10
12
  position = null;
13
+ rejectedTarget = null;
14
+ rejectedPosition = null;
15
+ rejection = null;
11
16
  hoverIntent = null;
12
17
  componentDidLoad() {
13
18
  this.hoverIntent = createHoverIntent(this.hoverExpandDelay, this.expandTarget);
14
19
  this.host.addEventListener('dragstart', this.onDragStart);
20
+ this.host.addEventListener('drag', this.onDrag);
15
21
  this.host.addEventListener('dragenter', this.onDragOver);
16
22
  this.host.addEventListener('dragover', this.onDragOver);
17
23
  this.host.addEventListener('dragleave', this.onDragLeave);
@@ -22,6 +28,7 @@ export class UITree {
22
28
  disconnectedCallback() {
23
29
  this.hoverIntent?.destroy();
24
30
  this.host.removeEventListener('dragstart', this.onDragStart);
31
+ this.host.removeEventListener('drag', this.onDrag);
25
32
  this.host.removeEventListener('dragenter', this.onDragOver);
26
33
  this.host.removeEventListener('dragover', this.onDragOver);
27
34
  this.host.removeEventListener('dragleave', this.onDragLeave);
@@ -73,19 +80,42 @@ export class UITree {
73
80
  .filter(Boolean),
74
81
  };
75
82
  }
76
- permitsDrop(source, target, position) {
83
+ constraintDepth(item) {
84
+ if (item.dropDepth !== undefined)
85
+ return item.dropDepth;
86
+ const dropDepth = item.getAttribute('drop-depth');
87
+ if (dropDepth !== null)
88
+ return Number(dropDepth);
89
+ if (item.depth !== undefined)
90
+ return item.depth;
91
+ return Number(item.getAttribute('depth')) || 1;
92
+ }
93
+ dropRejection(source, target, position) {
77
94
  // A tree item can never move into (or beside) one of its own descendants.
78
95
  // Reject the target before showing any insertion affordance so the preview
79
96
  // stays truthful instead of promising a move the consumer must undo.
80
97
  if (source.contains(target))
81
- return false;
98
+ return { reason: 'descendant' };
82
99
  const sourceMeta = this.itemMetadata(source);
83
100
  const targetMeta = this.itemMetadata(target);
84
101
  if (position === 'inside') {
85
- return this.acceptsChildren(target)
86
- && (targetMeta.accepts.length === 0 || targetMeta.accepts.includes(sourceMeta.type));
102
+ if (!this.acceptsChildren(target)
103
+ || (targetMeta.accepts.length > 0 && !targetMeta.accepts.includes(sourceMeta.type))) {
104
+ return { reason: 'incompatible' };
105
+ }
106
+ }
107
+ else if (sourceMeta.type !== targetMeta.type) {
108
+ return { reason: 'incompatible' };
87
109
  }
88
- return sourceMeta.type === targetMeta.type;
110
+ const maxDepth = Math.max(0, Math.floor(this.maxDepth));
111
+ if (maxDepth > 0 && source.subtreeDepth !== undefined) {
112
+ const targetDepth = Math.max(0, Math.floor(this.constraintDepth(target)));
113
+ const subtreeDepth = Math.max(0, Math.floor(source.subtreeDepth));
114
+ const resultingDepth = targetDepth + (position === 'inside' ? 1 : 0) + subtreeDepth;
115
+ if (resultingDepth > maxDepth)
116
+ return { reason: 'max-depth', maxDepth, resultingDepth };
117
+ }
118
+ return null;
89
119
  }
90
120
  clearTarget() {
91
121
  this.target?.removeAttribute('data-drop-position');
@@ -93,10 +123,16 @@ export class UITree {
93
123
  this.position = null;
94
124
  this.hoverIntent?.cancel();
95
125
  }
126
+ clearRejection() {
127
+ this.rejectedTarget = null;
128
+ this.rejectedPosition = null;
129
+ this.rejection = null;
130
+ }
96
131
  finishDrag() {
97
132
  this.source?.removeAttribute('data-dragging');
98
133
  this.source = null;
99
134
  this.clearTarget();
135
+ this.clearRejection();
100
136
  }
101
137
  expandTarget = (itemId) => {
102
138
  const item = Array.from(this.host.querySelectorAll('ui-tree-item'))
@@ -129,27 +165,36 @@ export class UITree {
129
165
  }
130
166
  setElementDragImage(event.dataTransfer, row);
131
167
  };
132
- onDragOver = (event) => {
168
+ updateTarget(target, clientY, dataTransfer) {
133
169
  if (!this.source)
134
- return;
135
- const target = this.itemFromEvent(event);
170
+ return false;
136
171
  if (!target || target === this.source) {
137
172
  this.clearTarget();
138
- return;
173
+ this.clearRejection();
174
+ return false;
139
175
  }
140
176
  const row = this.rowFor(target);
141
177
  if (!row)
142
- return;
143
- const position = classifyDropPosition(row.getBoundingClientRect(), event.clientY, this.acceptsChildren(target));
144
- if (!this.permitsDrop(this.source, target, position)) {
145
- if (event.dataTransfer)
146
- event.dataTransfer.dropEffect = 'none';
178
+ return false;
179
+ const position = classifyDropPosition(row.getBoundingClientRect(), clientY, this.acceptsChildren(target));
180
+ const rejection = this.dropRejection(this.source, target, position);
181
+ if (rejection) {
182
+ if (dataTransfer)
183
+ dataTransfer.dropEffect = 'none';
147
184
  this.clearTarget();
148
- return;
185
+ if (rejection.reason === 'max-depth') {
186
+ this.rejectedTarget = target;
187
+ this.rejectedPosition = position;
188
+ this.rejection = rejection;
189
+ }
190
+ else {
191
+ this.clearRejection();
192
+ }
193
+ return false;
149
194
  }
150
- event.preventDefault();
151
- if (event.dataTransfer)
152
- event.dataTransfer.dropEffect = 'move';
195
+ this.clearRejection();
196
+ if (dataTransfer)
197
+ dataTransfer.dropEffect = 'move';
153
198
  if (this.target !== target || this.position !== position) {
154
199
  this.clearTarget();
155
200
  this.target = target;
@@ -162,6 +207,26 @@ export class UITree {
162
207
  else {
163
208
  this.hoverIntent?.cancel();
164
209
  }
210
+ return true;
211
+ }
212
+ onDrag = (event) => {
213
+ if (!this.source || (event.clientX === 0 && event.clientY === 0))
214
+ return;
215
+ const target = this.itemAtPoint(event.clientX, event.clientY);
216
+ // Native dragenter does not fire when a nested source moves onto an
217
+ // ancestor row: the pointer was already inside that ancestor's host. The
218
+ // source drag event still carries the live pointer coordinates, so use it
219
+ // to keep ancestor/outdent feedback current.
220
+ if (target)
221
+ this.updateTarget(target, event.clientY, event.dataTransfer);
222
+ };
223
+ onDragOver = (event) => {
224
+ if (!this.source)
225
+ return;
226
+ const target = this.itemFromEvent(event);
227
+ if (this.updateTarget(target, event.clientY, event.dataTransfer)) {
228
+ event.preventDefault();
229
+ }
165
230
  };
166
231
  onDragLeave = (event) => {
167
232
  if (this.isWithinTree(event.relatedTarget))
@@ -169,12 +234,15 @@ export class UITree {
169
234
  if (this.itemAtPoint(event.clientX, event.clientY))
170
235
  return;
171
236
  this.clearTarget();
237
+ this.clearRejection();
172
238
  };
173
239
  dispatchReorder(source, target, position) {
174
240
  const sourceId = this.itemId(source);
175
241
  const targetId = this.itemId(target);
176
242
  if (!sourceId || !targetId)
177
243
  return;
244
+ if (position === 'inside')
245
+ this.expandTarget(targetId);
178
246
  const sourceMeta = this.itemMetadata(source);
179
247
  const targetMeta = this.itemMetadata(target);
180
248
  dispatchDetail(this.host, 'reorder', {
@@ -188,6 +256,21 @@ export class UITree {
188
256
  trigger: 'pointer',
189
257
  });
190
258
  }
259
+ dispatchReorderRejected(source, target, position, rejection) {
260
+ const sourceId = this.itemId(source);
261
+ const targetId = this.itemId(target);
262
+ if (!sourceId || !targetId)
263
+ return;
264
+ dispatchDetail(this.host, 'reorder-rejected', {
265
+ sourceId,
266
+ targetId,
267
+ position,
268
+ reason: 'max-depth',
269
+ maxDepth: rejection.maxDepth,
270
+ resultingDepth: rejection.resultingDepth,
271
+ trigger: 'pointer',
272
+ });
273
+ }
191
274
  onDrop = (event) => {
192
275
  if (!this.source || !this.target || !this.position)
193
276
  return;
@@ -197,14 +280,23 @@ export class UITree {
197
280
  };
198
281
  onDragEnd = (event) => {
199
282
  if (this.source) {
283
+ if (this.rejectedTarget && this.rejectedPosition && this.rejection) {
284
+ this.dispatchReorderRejected(this.source, this.rejectedTarget, this.rejectedPosition, this.rejection);
285
+ this.finishDrag();
286
+ return;
287
+ }
200
288
  const target = this.itemAtPoint(event.clientX, event.clientY);
201
289
  if (target && target !== this.source) {
202
290
  const row = this.rowFor(target);
203
291
  if (row) {
204
292
  const position = classifyDropPosition(row.getBoundingClientRect(), event.clientY, this.acceptsChildren(target));
205
- if (this.permitsDrop(this.source, target, position)) {
293
+ const rejection = this.dropRejection(this.source, target, position);
294
+ if (!rejection) {
206
295
  this.dispatchReorder(this.source, target, position);
207
296
  }
297
+ else if (rejection.reason === 'max-depth') {
298
+ this.dispatchReorderRejected(this.source, target, position, rejection);
299
+ }
208
300
  }
209
301
  }
210
302
  }
@@ -229,7 +321,7 @@ export class UITree {
229
321
  next.focus();
230
322
  };
231
323
  render() {
232
- return (h(Host, { key: 'b659635f6acdf09a3618c514f5bdd9bf173f9d98', role: "tree", "aria-label": this.label || 'Tree' }, h("slot", { key: '0815f0eb0bfe766dd2f358385af1516fd4328e2e' })));
324
+ return (h(Host, { key: '474c2154d2abe3c76eee9c36bf552390089df6e8', role: "tree", "aria-label": this.label || 'Tree' }, h("slot", { key: '93aedd02f984dd33b5efc811fef417d1199917bd' })));
233
325
  }
234
326
  static get is() { return "ui-tree"; }
235
327
  static get encapsulation() { return "shadow"; }
@@ -284,6 +376,26 @@ export class UITree {
284
376
  "reflect": false,
285
377
  "attribute": "hover-expand-delay",
286
378
  "defaultValue": "700"
379
+ },
380
+ "maxDepth": {
381
+ "type": "number",
382
+ "mutable": false,
383
+ "complexType": {
384
+ "original": "number",
385
+ "resolved": "number",
386
+ "references": {}
387
+ },
388
+ "required": false,
389
+ "optional": false,
390
+ "docs": {
391
+ "tags": [],
392
+ "text": "Maximum resulting item depth accepted by pointer reordering. Zero is unlimited."
393
+ },
394
+ "getter": false,
395
+ "setter": false,
396
+ "reflect": false,
397
+ "attribute": "max-depth",
398
+ "defaultValue": "0"
287
399
  }
288
400
  };
289
401
  }
@@ -9,6 +9,10 @@ export class UITreeItem {
9
9
  label = '';
10
10
  /** One-based visual and semantic nesting level. */
11
11
  depth = 1;
12
+ /** Application hierarchy depth used for drop constraints. Defaults to visual depth. */
13
+ dropDepth;
14
+ /** Deepest descendant distance, used with the tree's max-depth drop constraint. */
15
+ subtreeDepth;
12
16
  /** Whether this item accepts children and exposes disclosure behavior. */
13
17
  container = false;
14
18
  /** Whether this item participates in pointer drag and drop. */
@@ -71,10 +75,10 @@ export class UITreeItem {
71
75
  const level = Math.max(1, Math.floor(this.depth));
72
76
  const disclosureLabel = `${this.internalExpanded ? 'Collapse' : 'Expand'} ${this.label || 'item'}`;
73
77
  const dragLabel = `Drag ${this.label || 'item'} to reorder`;
74
- return (h(Host, { key: 'ea8ed538aa3883c87257a25614a066965364693f', role: "treeitem", "aria-level": String(level), "aria-expanded": this.container ? String(this.internalExpanded) : undefined, "aria-selected": String(this.selected), "aria-disabled": this.disabled ? 'true' : undefined, "data-container": this.container ? '' : undefined, "data-selected": this.selected ? '' : undefined, "data-disabled": this.disabled ? '' : undefined, "data-drag-type": this.dragType || 'item', "data-drop-scope": this.dropScope || undefined, "data-accepts": this.accepts || undefined, tabIndex: this.disabled ? -1 : 0, style: {
78
+ return (h(Host, { key: '606f5fdac8a95489d0c62cd7d4918c6d5d0c759e', role: "treeitem", "aria-level": String(level), "aria-expanded": this.container ? String(this.internalExpanded) : undefined, "aria-selected": String(this.selected), "aria-disabled": this.disabled ? 'true' : undefined, "data-container": this.container ? '' : undefined, "data-selected": this.selected ? '' : undefined, "data-disabled": this.disabled ? '' : undefined, "data-drag-type": this.dragType || 'item', "data-drop-scope": this.dropScope || undefined, "data-accepts": this.accepts || undefined, tabIndex: this.disabled ? -1 : 0, style: {
75
79
  '--ui-tree-item-depth': String(level - 1),
76
80
  'margin-inline-start': level > 1 ? 'var(--ui-tree-indent, 16px)' : '0px',
77
- } }, h("div", { key: '740b93aa47e65d8a1cb899d4b9c966d9ad1d456f', class: "row", part: "row", onClick: this.onRowClick }, this.sortable && !this.disabled ? (h("button", { class: "drag-handle", part: "drag-handle", type: "button", draggable: true, "aria-label": dragLabel, title: dragLabel }, h("span", { innerHTML: loomaIconMarkup('grip-vertical') }))) : null, this.container ? (h("button", { class: "disclosure", part: "disclosure", type: "button", "aria-label": disclosureLabel, "aria-expanded": String(this.internalExpanded), disabled: this.disabled, onClick: this.onDisclosureClick, onKeyDown: this.onDisclosureKeydown }, h("span", { class: { 'disclosure-icon': true, 'disclosure-icon--expanded': this.internalExpanded }, innerHTML: loomaIconMarkup('chevron-down') }))) : h("span", { class: "disclosure-spacer", "aria-hidden": "true" }), h("span", { key: '37e1b7f1cdddf623734becef465ffde83d8b86f2', class: "leading", part: "leading" }, h("slot", { key: '0ab3a60c98628f009918d0d720772154912d2709', name: "leading" })), h("span", { key: 'defdd343f25a0f4354110e981f3889e1d09c27ee', class: "label", part: "label" }, h("slot", { key: 'bde46ccacc1a620348062fc300503c4f1736316b' })), h("span", { key: 'caff9ada38c41be90aeb6e331f4c54a51f31d26c', class: "actions", part: "actions" }, h("slot", { key: 'e11704d6871445c91eaa29c99302d8b751be69d3', name: "actions" })), h("span", { key: '9efc0e95588f1dd4527dade2b7ff9f2774462c2e', class: "drop-indicator row-drop-indicator", part: "drop-indicator", "aria-hidden": "true" })), this.container ? (h("div", { class: "children", part: "children", role: "group", hidden: !this.internalExpanded }, h("slot", { name: "children" }))) : null, h("span", { key: '8893ec2c4082bb8af942ef563055a2910d0d4201', class: "drop-indicator subtree-drop-indicator", part: "drop-indicator", "aria-hidden": "true" })));
81
+ } }, h("div", { key: '2b4bb03d4b24ef668f22b08e803f7f43c2d63ae5', class: "row", part: "row", onClick: this.onRowClick }, this.sortable && !this.disabled ? (h("button", { class: "drag-handle", part: "drag-handle", type: "button", draggable: true, "aria-label": dragLabel, title: dragLabel }, h("span", { innerHTML: loomaIconMarkup('grip-vertical') }))) : null, this.container ? (h("button", { class: "disclosure", part: "disclosure", type: "button", "aria-label": disclosureLabel, "aria-expanded": String(this.internalExpanded), disabled: this.disabled, onClick: this.onDisclosureClick, onKeyDown: this.onDisclosureKeydown }, h("span", { class: { 'disclosure-icon': true, 'disclosure-icon--expanded': this.internalExpanded }, innerHTML: loomaIconMarkup('chevron-down') }))) : h("span", { class: "disclosure-spacer", "aria-hidden": "true" }), h("span", { key: 'e7b935158e35cdc6518bdd73d54c42dcfa211aee', class: "leading", part: "leading" }, h("slot", { key: '8448462349fd23b8be0fb673fc6e101bf94beaa7', name: "leading" })), h("span", { key: 'e0b6338e1ec9ec043446e42c5f03724adf7e1862', class: "label", part: "label" }, h("slot", { key: 'ed44e6f2ce3466c28d2b87fc7511399ecc339255' })), h("span", { key: '2aea78227904fe23cfc4b8e14852a4601e3cc34b', class: "actions", part: "actions" }, h("slot", { key: '7c6549008c2a54c3ea6fcdf9e0fdbe445d379922', name: "actions" })), h("span", { key: '05166ba04765bc518d6b95ca7ae5a67c4394d1bf', class: "drop-indicator row-drop-indicator", part: "drop-indicator", "aria-hidden": "true" })), this.container ? (h("div", { class: "children", part: "children", role: "group", hidden: !this.internalExpanded }, h("slot", { name: "children" }))) : null, h("span", { key: '7381d6e9e2a8f94695f29e73194b1603d79cefb9', class: "drop-indicator subtree-drop-indicator", part: "drop-indicator", "aria-hidden": "true" })));
78
82
  }
79
83
  static get is() { return "ui-tree-item"; }
80
84
  static get encapsulation() { return "shadow"; }
@@ -150,6 +154,44 @@ export class UITreeItem {
150
154
  "attribute": "depth",
151
155
  "defaultValue": "1"
152
156
  },
157
+ "dropDepth": {
158
+ "type": "number",
159
+ "mutable": false,
160
+ "complexType": {
161
+ "original": "number",
162
+ "resolved": "number",
163
+ "references": {}
164
+ },
165
+ "required": false,
166
+ "optional": true,
167
+ "docs": {
168
+ "tags": [],
169
+ "text": "Application hierarchy depth used for drop constraints. Defaults to visual depth."
170
+ },
171
+ "getter": false,
172
+ "setter": false,
173
+ "reflect": false,
174
+ "attribute": "drop-depth"
175
+ },
176
+ "subtreeDepth": {
177
+ "type": "number",
178
+ "mutable": false,
179
+ "complexType": {
180
+ "original": "number",
181
+ "resolved": "number",
182
+ "references": {}
183
+ },
184
+ "required": false,
185
+ "optional": true,
186
+ "docs": {
187
+ "tags": [],
188
+ "text": "Deepest descendant distance, used with the tree's max-depth drop constraint."
189
+ },
190
+ "getter": false,
191
+ "setter": false,
192
+ "reflect": false,
193
+ "attribute": "subtree-depth"
194
+ },
153
195
  "container": {
154
196
  "type": "boolean",
155
197
  "mutable": false,
@@ -0,0 +1,4 @@
1
+ /** Map domain records at the boundary, preserving typed metadata for rich rows. */
2
+ export function mapComboboxOptions(rows, map) {
3
+ return rows.map(row => ({ ...map(row), metadata: row }));
4
+ }
@@ -0,0 +1,5 @@
1
+ /** Valibot's Standard Schema implementation preserves async transforms and issue paths.
2
+ * Type-only Valibot imports keep the adapter free of a schema-library runtime. */
3
+ export function valibotField(schema, options = {}) {
4
+ return { ...options, schema };
5
+ }
@@ -0,0 +1,62 @@
1
+ /** Formatting is additive: every original character must survive in order.
2
+ * Normalization belongs to submitted output, never the visible editing buffer. */
3
+ export function formatEditingValue(raw, selection, format) {
4
+ const unchanged = { display: raw, selection };
5
+ if (!format)
6
+ return unchanged;
7
+ let result;
8
+ try {
9
+ result = format(raw, selection);
10
+ }
11
+ catch {
12
+ return unchanged;
13
+ }
14
+ if (!result)
15
+ return unchanged;
16
+ const characters = Array.from(raw);
17
+ let cursor = 0;
18
+ for (const character of result.display)
19
+ if (character === characters[cursor])
20
+ cursor += 1;
21
+ if (!Number.isInteger(result.selection.start) || !Number.isInteger(result.selection.end) || cursor !== characters.length || result.selection.start < 0 || result.selection.end < result.selection.start
22
+ || result.selection.end > result.display.length)
23
+ return unchanged;
24
+ return result;
25
+ }
26
+ export async function validateField(request, config) {
27
+ let output = request.raw;
28
+ let issues = [];
29
+ const check = () => request.signal.throwIfAborted();
30
+ try {
31
+ check();
32
+ if (config.parse)
33
+ output = await config.parse(request.raw, request);
34
+ check();
35
+ if (config.schema) {
36
+ const result = await config.schema['~standard'].validate(output);
37
+ check();
38
+ if (result.issues)
39
+ issues = result.issues;
40
+ else if ('value' in result)
41
+ output = result.value;
42
+ }
43
+ if (!issues.some(issue => issue.severity !== 'warning')) {
44
+ if (config.normalize)
45
+ output = await config.normalize(output, request);
46
+ check();
47
+ if (config.validator) {
48
+ const result = await config.validator(output, request);
49
+ check();
50
+ issues = [...issues, ...(result.issues ?? [])];
51
+ if ('output' in result)
52
+ output = result.output;
53
+ }
54
+ }
55
+ }
56
+ catch (error) {
57
+ check();
58
+ issues = [{ message: error instanceof Error ? error.message : 'Unable to validate this value.' }];
59
+ }
60
+ issues = [...issues, ...(config.issues ?? [])];
61
+ return { output: issues.some(issue => issue.severity !== 'warning') ? undefined : output, issues };
62
+ }