@fusion.dev/helix-headless 0.147.0 → 0.149.0

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 (296) hide show
  1. package/custom-elements.json +11222 -2332
  2. package/dist/accordion/item/accordion-item.d.ts +5 -2
  3. package/dist/accordion/item/accordion-item.js +11 -7
  4. package/dist/accordion/root/accordion-root.js +4 -6
  5. package/dist/announcement/root/announcement-root.d.ts +61 -5
  6. package/dist/announcement/root/announcement-root.js +126 -20
  7. package/dist/area-chart/root/area-chart-root.d.ts +11 -0
  8. package/dist/area-chart/root/area-chart-root.js +21 -9
  9. package/dist/avatar/group/avatar-group.d.ts +10 -2
  10. package/dist/avatar/group/avatar-group.js +10 -5
  11. package/dist/badge/count.d.ts +19 -0
  12. package/dist/badge/count.js +20 -0
  13. package/dist/badge/root/badge-root.d.ts +6 -2
  14. package/dist/badge/root/badge-root.js +8 -22
  15. package/dist/bar-chart/root/bar-chart-root.d.ts +13 -1
  16. package/dist/bar-chart/root/bar-chart-root.js +17 -4
  17. package/dist/blockquote/root/blockquote-root.d.ts +66 -8
  18. package/dist/blockquote/root/blockquote-root.js +85 -8
  19. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +2 -2
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +8 -1
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +5 -2
  22. package/dist/button/root/button-root.d.ts +10 -1
  23. package/dist/button/root/button-root.js +3 -2
  24. package/dist/button-group/arrows.d.ts +14 -0
  25. package/dist/button-group/arrows.js +10 -0
  26. package/dist/button-group/root/button-group-root.d.ts +144 -3
  27. package/dist/button-group/root/button-group-root.js +142 -2
  28. package/dist/callout/root/callout-root.d.ts +16 -2
  29. package/dist/callout/root/callout-root.js +16 -4
  30. package/dist/canvas/describe.d.ts +10 -0
  31. package/dist/canvas/describe.js +9 -0
  32. package/dist/canvas/edge-pan.d.ts +61 -0
  33. package/dist/canvas/edge-pan.js +63 -0
  34. package/dist/canvas/neighbor.d.ts +17 -0
  35. package/dist/canvas/neighbor.js +1 -0
  36. package/dist/canvas/node/canvas-node.d.ts +12 -2
  37. package/dist/canvas/node/canvas-node.js +8 -3
  38. package/dist/canvas/root/canvas-document.d.ts +10 -0
  39. package/dist/canvas/root/canvas-document.js +1 -0
  40. package/dist/canvas/root/canvas-root.d.ts +168 -9
  41. package/dist/canvas/root/canvas-root.js +239 -69
  42. package/dist/canvas/snap.d.ts +42 -0
  43. package/dist/canvas/snap.js +32 -0
  44. package/dist/carousel/root/carousel-root.d.ts +9 -3
  45. package/dist/carousel/root/carousel-root.js +17 -10
  46. package/dist/chat/composer/chat-composer.d.ts +5 -0
  47. package/dist/chat/composer/chat-composer.js +4 -1
  48. package/dist/chat/message/chat-message.d.ts +9 -5
  49. package/dist/chat/message/chat-message.js +8 -4
  50. package/dist/chat/naming.js +2 -2
  51. package/dist/chat/root/chat-root.d.ts +40 -4
  52. package/dist/chat/root/chat-root.js +38 -14
  53. package/dist/checkbox/root/checkbox-root.d.ts +11 -0
  54. package/dist/checkbox/root/checkbox-root.js +8 -2
  55. package/dist/checkbox-group/root/checkbox-group-root.d.ts +24 -0
  56. package/dist/checkbox-group/root/checkbox-group-root.js +28 -12
  57. package/dist/checkbox-group/select-all.d.ts +11 -0
  58. package/dist/checkbox-group/select-all.js +5 -0
  59. package/dist/code-block/root/code-block-root.d.ts +20 -8
  60. package/dist/code-block/root/code-block-root.js +16 -5
  61. package/dist/color-input/root/color-input-root.d.ts +13 -0
  62. package/dist/color-input/root/color-input-root.js +18 -5
  63. package/dist/color-picker/root/color-picker-root.d.ts +19 -3
  64. package/dist/color-picker/root/color-picker-root.js +52 -24
  65. package/dist/color-picker/wheel.d.ts +11 -0
  66. package/dist/color-picker/wheel.js +9 -0
  67. package/dist/combobox/root/combobox-root.d.ts +106 -18
  68. package/dist/combobox/root/combobox-root.js +101 -26
  69. package/dist/command/root/command-root.d.ts +19 -9
  70. package/dist/command/root/command-root.js +9 -4
  71. package/dist/copy-button/root/copy-button-root.d.ts +5 -0
  72. package/dist/copy-button/root/copy-button-root.js +7 -2
  73. package/dist/data-table/root/data-table-root.d.ts +171 -29
  74. package/dist/data-table/root/data-table-root.js +284 -161
  75. package/dist/date-input/root/date-input-root.d.ts +32 -9
  76. package/dist/date-input/root/date-input-root.js +66 -44
  77. package/dist/date-picker/root/date-picker-root.d.ts +38 -15
  78. package/dist/date-picker/root/date-picker-root.js +52 -33
  79. package/dist/description-list/item/description-list-item.d.ts +4 -0
  80. package/dist/description-list/item/description-list-item.js +7 -1
  81. package/dist/dialog/root/dialog-root.d.ts +12 -1
  82. package/dist/dialog/root/dialog-root.js +11 -4
  83. package/dist/divider/root/divider-root.d.ts +45 -16
  84. package/dist/divider/root/divider-root.js +28 -4
  85. package/dist/donut-chart/root/donut-chart-root.d.ts +5 -0
  86. package/dist/donut-chart/root/donut-chart-root.js +8 -5
  87. package/dist/drawer/root/drawer-root.d.ts +12 -1
  88. package/dist/drawer/root/drawer-root.js +9 -2
  89. package/dist/drilldown/item/drilldown-item.js +3 -4
  90. package/dist/drilldown/root/drilldown-root.d.ts +5 -0
  91. package/dist/drilldown/root/drilldown-root.js +4 -1
  92. package/dist/element-events.generated.js +26 -3
  93. package/dist/empty/root/empty-root.d.ts +17 -3
  94. package/dist/empty/root/empty-root.js +29 -5
  95. package/dist/file-input/root/file-input-root.d.ts +18 -3
  96. package/dist/file-input/root/file-input-root.js +34 -18
  97. package/dist/file-input/status.js +2 -1
  98. package/dist/filter-input/chip/filter-chip.d.ts +13 -0
  99. package/dist/filter-input/chip/filter-chip.js +7 -3
  100. package/dist/filter-input/menu/filter-menu.d.ts +5 -0
  101. package/dist/filter-input/menu/filter-menu.js +3 -1
  102. package/dist/filter-input/root/filter-input-root.d.ts +20 -3
  103. package/dist/filter-input/root/filter-input-root.js +8 -4
  104. package/dist/format-date/fields.d.ts +20 -0
  105. package/dist/format-date/fields.js +14 -0
  106. package/dist/format-date/options.d.ts +2 -1
  107. package/dist/format-date/options.js +9 -38
  108. package/dist/format-date/root/format-date-root.d.ts +55 -5
  109. package/dist/format-date/root/format-date-root.js +29 -34
  110. package/dist/graph/root/graph-model.d.ts +11 -0
  111. package/dist/graph/root/graph-model.js +4 -0
  112. package/dist/graph/root/graph-root.d.ts +101 -14
  113. package/dist/graph/root/graph-root.js +140 -46
  114. package/dist/heatmap/root/heatmap-root.d.ts +37 -4
  115. package/dist/heatmap/root/heatmap-root.js +51 -16
  116. package/dist/icon-button/root/icon-button-root.d.ts +5 -0
  117. package/dist/icon-button/root/icon-button-root.js +1 -0
  118. package/dist/image/root/image-root.d.ts +11 -0
  119. package/dist/input/root/input-root.d.ts +5 -0
  120. package/dist/input/root/input-root.js +4 -1
  121. package/dist/kbd/root/kbd-root.js +1 -2
  122. package/dist/legend/root/legend-root.js +4 -17
  123. package/dist/lightbox/root/lightbox-root.d.ts +14 -4
  124. package/dist/lightbox/root/lightbox-root.js +25 -7
  125. package/dist/line-chart/root/line-chart-root.d.ts +5 -0
  126. package/dist/line-chart/root/line-chart-root.js +4 -2
  127. package/dist/list/item/list-item.d.ts +32 -0
  128. package/dist/list/item/list-item.js +34 -7
  129. package/dist/list/root/list-root.d.ts +87 -0
  130. package/dist/list/root/list-root.js +119 -23
  131. package/dist/listbox/reorder/index.d.ts +1 -0
  132. package/dist/listbox/reorder/index.js +4 -0
  133. package/dist/listbox/reorder/listbox-reorder.d.ts +83 -0
  134. package/dist/listbox/reorder/listbox-reorder.js +151 -0
  135. package/dist/listbox/root/listbox-root.d.ts +185 -33
  136. package/dist/listbox/root/listbox-root.js +166 -136
  137. package/dist/loader/root/loader-root.d.ts +5 -0
  138. package/dist/loader/root/loader-root.js +3 -1
  139. package/dist/map/area/map-area.d.ts +5 -0
  140. package/dist/map/area/map-area.js +3 -1
  141. package/dist/map/buildings/map-buildings.d.ts +5 -0
  142. package/dist/map/buildings/map-buildings.js +3 -1
  143. package/dist/map/contours/map-contours.d.ts +5 -0
  144. package/dist/map/contours/map-contours.js +3 -1
  145. package/dist/map/landcover/map-landcover.d.ts +5 -0
  146. package/dist/map/landcover/map-landcover.js +3 -1
  147. package/dist/map/marker/map-marker.d.ts +18 -2
  148. package/dist/map/marker/map-marker.js +13 -5
  149. package/dist/map/points/map-points.d.ts +5 -0
  150. package/dist/map/points/map-points.js +6 -4
  151. package/dist/map/position/map-position.d.ts +5 -0
  152. package/dist/map/position/map-position.js +3 -1
  153. package/dist/map/raster/map-raster.d.ts +5 -0
  154. package/dist/map/raster/map-raster.js +3 -1
  155. package/dist/map/root/map-root.d.ts +73 -16
  156. package/dist/map/root/map-root.js +122 -44
  157. package/dist/map/route/map-route.d.ts +5 -0
  158. package/dist/map/route/map-route.js +3 -1
  159. package/dist/map/terrain/map-terrain.d.ts +5 -0
  160. package/dist/map/terrain/map-terrain.js +3 -1
  161. package/dist/megamenu/root/megamenu-root.js +4 -11
  162. package/dist/menu/root/menu-root.d.ts +7 -2
  163. package/dist/menu/root/menu-root.js +3 -1
  164. package/dist/meter/root/meter-root.d.ts +16 -3
  165. package/dist/meter/root/meter-root.js +12 -5
  166. package/dist/navigation/root/navigation-root.d.ts +5 -0
  167. package/dist/navigation/root/navigation-root.js +7 -8
  168. package/dist/notifications/group/notification-group.d.ts +8 -1
  169. package/dist/notifications/group/notification-group.js +12 -6
  170. package/dist/notifications/notification/notification.d.ts +17 -1
  171. package/dist/notifications/notification/notification.js +6 -2
  172. package/dist/notifications/root/notifications-root.d.ts +49 -5
  173. package/dist/notifications/root/notifications-root.js +36 -8
  174. package/dist/number-input/root/number-input-root.d.ts +21 -8
  175. package/dist/number-input/root/number-input-root.js +26 -11
  176. package/dist/object-inspector/root/object-inspector-root.d.ts +56 -13
  177. package/dist/object-inspector/root/object-inspector-root.js +41 -30
  178. package/dist/outline/root/outline-root.d.ts +5 -0
  179. package/dist/outline/root/outline-root.js +3 -1
  180. package/dist/pagination/root/pagination-root.d.ts +7 -1
  181. package/dist/pagination/root/pagination-root.js +16 -7
  182. package/dist/pagination/size/pagination-size.d.ts +8 -3
  183. package/dist/pagination/size/pagination-size.js +5 -3
  184. package/dist/pagination/summary/pagination-summary.d.ts +8 -6
  185. package/dist/pagination/summary/pagination-summary.js +4 -9
  186. package/dist/pin-input/code.d.ts +23 -0
  187. package/dist/pin-input/code.js +21 -0
  188. package/dist/pin-input/root/pin-input-root.d.ts +9 -3
  189. package/dist/pin-input/root/pin-input-root.js +13 -23
  190. package/dist/popover/root/popover-root.d.ts +12 -2
  191. package/dist/popover/root/popover-root.js +10 -4
  192. package/dist/progress/root/progress-root.d.ts +7 -2
  193. package/dist/progress/root/progress-root.js +5 -2
  194. package/dist/qr-code/name.d.ts +3 -2
  195. package/dist/qr-code/name.js +2 -2
  196. package/dist/qr-code/root/qr-code-root.d.ts +26 -5
  197. package/dist/qr-code/root/qr-code-root.js +27 -6
  198. package/dist/radio/group/radio-group.d.ts +11 -0
  199. package/dist/radio/group/radio-group.js +8 -2
  200. package/dist/rating/root/rating-root.d.ts +12 -1
  201. package/dist/rating/root/rating-root.js +10 -3
  202. package/dist/scatter-chart/measures.d.ts +22 -0
  203. package/dist/scatter-chart/measures.js +11 -0
  204. package/dist/scatter-chart/root/scatter-chart-root.d.ts +22 -8
  205. package/dist/scatter-chart/root/scatter-chart-root.js +25 -23
  206. package/dist/select/root/select-root.d.ts +67 -8
  207. package/dist/select/root/select-root.js +45 -11
  208. package/dist/skip-link/root/skip-link-root.d.ts +5 -0
  209. package/dist/skip-link/root/skip-link-root.js +3 -1
  210. package/dist/slider/root/slider-root.d.ts +7 -2
  211. package/dist/slider/root/slider-root.js +11 -5
  212. package/dist/sparkline/readings.d.ts +15 -5
  213. package/dist/sparkline/readings.js +3 -3
  214. package/dist/sparkline/root/sparkline-root.d.ts +9 -4
  215. package/dist/sparkline/root/sparkline-root.js +9 -3
  216. package/dist/speed-dial/group/speed-dial-group.d.ts +48 -0
  217. package/dist/speed-dial/group/speed-dial-group.js +43 -0
  218. package/dist/speed-dial/index.d.ts +1 -0
  219. package/dist/speed-dial/index.js +1 -0
  220. package/dist/speed-dial/item/speed-dial-item.d.ts +26 -1
  221. package/dist/speed-dial/item/speed-dial-item.js +41 -3
  222. package/dist/speed-dial/long-press.d.ts +50 -0
  223. package/dist/speed-dial/long-press.js +48 -0
  224. package/dist/speed-dial/root/speed-dial-root.d.ts +85 -1
  225. package/dist/speed-dial/root/speed-dial-root.js +117 -5
  226. package/dist/splitter/root/splitter-root.d.ts +12 -3
  227. package/dist/splitter/root/splitter-root.js +22 -4
  228. package/dist/steps/root/steps-root.d.ts +9 -2
  229. package/dist/steps/root/steps-root.js +6 -3
  230. package/dist/steps/step/step.d.ts +12 -0
  231. package/dist/steps/step/step.js +11 -2
  232. package/dist/switch/root/switch-root.d.ts +11 -0
  233. package/dist/switch/root/switch-root.js +8 -2
  234. package/dist/table/cell/table-cell.d.ts +8 -1
  235. package/dist/table/cell/table-cell.js +6 -2
  236. package/dist/table/column/table-column.d.ts +11 -4
  237. package/dist/table/column/table-column.js +15 -10
  238. package/dist/table/grid-controller.d.ts +122 -0
  239. package/dist/table/grid-controller.js +299 -0
  240. package/dist/table/root/table-root.d.ts +154 -8
  241. package/dist/table/root/table-root.js +197 -38
  242. package/dist/table/row/table-row.d.ts +55 -1
  243. package/dist/table/row/table-row.js +60 -7
  244. package/dist/tabs/root/tabs-root.d.ts +5 -0
  245. package/dist/tabs/root/tabs-root.js +3 -1
  246. package/dist/tag/group/tag-group.d.ts +5 -0
  247. package/dist/tag/group/tag-group.js +8 -15
  248. package/dist/tag/root/tag-root.d.ts +14 -1
  249. package/dist/tag/root/tag-root.js +11 -8
  250. package/dist/textarea/root/textarea-root.d.ts +5 -0
  251. package/dist/textarea/root/textarea-root.js +3 -1
  252. package/dist/time-input/root/time-input-root.d.ts +14 -7
  253. package/dist/time-input/root/time-input-root.js +43 -32
  254. package/dist/time-picker/root/time-picker-root.d.ts +16 -7
  255. package/dist/time-picker/root/time-picker-root.js +28 -12
  256. package/dist/toast/item/toast-item.d.ts +13 -3
  257. package/dist/toast/item/toast-item.js +2 -0
  258. package/dist/toast/root/toast-root.d.ts +22 -2
  259. package/dist/toast/root/toast-root.js +24 -17
  260. package/dist/toggle/group/toggle-group.js +3 -5
  261. package/dist/toolbar/root/toolbar-root.d.ts +36 -0
  262. package/dist/toolbar/root/toolbar-root.js +43 -9
  263. package/dist/tooltip/root/tooltip-root.d.ts +27 -17
  264. package/dist/tooltip/root/tooltip-root.js +1 -2
  265. package/dist/tour/root/tour-root.d.ts +8 -2
  266. package/dist/tour/root/tour-root.js +4 -2
  267. package/dist/tour/stop/tour-stop.d.ts +5 -0
  268. package/dist/tour/stop/tour-stop.js +6 -1
  269. package/dist/tree/grip.d.ts +5 -0
  270. package/dist/tree/grip.js +1 -0
  271. package/dist/tree/item/tree-item.d.ts +24 -0
  272. package/dist/tree/item/tree-item.js +27 -5
  273. package/dist/tree/root/tree-root.d.ts +66 -1
  274. package/dist/tree/root/tree-root.js +77 -5
  275. package/dist/trend/root/trend-root.d.ts +20 -4
  276. package/dist/trend/root/trend-root.js +20 -5
  277. package/dist/video/root/video-root.d.ts +23 -3
  278. package/dist/video/root/video-root.js +56 -15
  279. package/dist/video-playlist/menu/video-playlist-menu.d.ts +5 -0
  280. package/dist/video-playlist/menu/video-playlist-menu.js +3 -1
  281. package/dist/video-playlist/root/video-playlist-root.d.ts +5 -0
  282. package/dist/video-playlist/root/video-playlist-root.js +3 -1
  283. package/dist/virtual-list/root/virtual-list-root.d.ts +19 -3
  284. package/dist/virtual-list/root/virtual-list-root.js +10 -19
  285. package/lint.json +1 -1
  286. package/package.json +7 -6
  287. package/types/jsx.d.ts +6005 -2114
  288. package/types/svelte.d.ts +1 -0
  289. package/types/vue.d.ts +1594 -676
  290. package/types/words.d.ts +3280 -0
  291. package/dist/kbd/keys.d.ts +0 -29
  292. package/dist/kbd/keys.js +0 -52
  293. package/dist/toast/hotkey.d.ts +0 -22
  294. package/dist/toast/hotkey.js +0 -23
  295. package/dist/tooltip/focus-target.d.ts +0 -6
  296. package/dist/tooltip/focus-target.js +0 -9
@@ -5,8 +5,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { customElement, HelixElement, hostAria, slottedWords } from '@fusion.dev/helix-core';
8
+ import { dotsSixVertical } from '@fusion.dev/helix-icons';
8
9
  import { html, nothing } from 'lit';
9
10
  import { property } from 'lit/decorators.js';
11
+ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
10
12
  const CONTROL = 'a[href], button, input, select, textarea, [tabindex]';
11
13
  let HelixHeadlessListItem = class HelixHeadlessListItem extends HelixElement {
12
14
  constructor() {
@@ -31,11 +33,18 @@ let HelixHeadlessListItem = class HelixHeadlessListItem extends HelixElement {
31
33
  }
32
34
  get controls() {
33
35
  const slot = this.renderRoot?.querySelector?.('slot[name="end"]');
34
- return (slot?.assignedElements({ flatten: true }) ?? [])
35
- .flatMap((element) => [element, ...element.querySelectorAll('*')])
36
- .filter((element) => element instanceof HTMLElement &&
37
- element.matches(CONTROL) &&
38
- !element.matches(':disabled'));
36
+ const grip = this.gripElement;
37
+ return [
38
+ ...(slot?.assignedElements({ flatten: true }) ?? [])
39
+ .flatMap((element) => [element, ...element.querySelectorAll('*')])
40
+ .filter((element) => element instanceof HTMLElement &&
41
+ element.matches(CONTROL) &&
42
+ !element.matches(':disabled')),
43
+ ...(grip ? [grip] : []),
44
+ ];
45
+ }
46
+ get gripElement() {
47
+ return this.renderRoot?.querySelector?.('[part="grip"]') ?? null;
39
48
  }
40
49
  focusItem() {
41
50
  this.cell?.focus();
@@ -51,6 +60,18 @@ let HelixHeadlessListItem = class HelixHeadlessListItem extends HelixElement {
51
60
  this.internals.ariaCurrent =
52
61
  this.current !== undefined && this.href === '' ? this.current : null;
53
62
  this.toggleState('selected', this.selected === true);
63
+ this.toggleState('dragging', this.move === 'dragging');
64
+ this.toggleState('drop-after', this.move === 'drop-after');
65
+ this.toggleState('drop-before', this.move === 'drop-before');
66
+ }
67
+ renderGrip() {
68
+ return this.grip === undefined
69
+ ? nothing
70
+ : html `<button part="grip" type="button" tabindex=${this.grouped ? '-1' : nothing} aria-label=${this.grip}>
71
+ <svg aria-hidden="true" fill="currentColor" part="grip-mark" viewBox=${dotsSixVertical.viewBox}>
72
+ ${unsafeSVG(dotsSixVertical.content)}
73
+ </svg>
74
+ </button>`;
54
75
  }
55
76
  renderRail() {
56
77
  return nothing;
@@ -70,7 +91,7 @@ let HelixHeadlessListItem = class HelixHeadlessListItem extends HelixElement {
70
91
  tabindex=${tabindex}
71
92
  aria-labelledby=${labelledby}
72
93
  aria-describedby=${describedby}
73
- >${content}<slot name="end"></slot></div>`
94
+ >${content}<slot name="end"></slot>${this.renderGrip()}</div>`
74
95
  : html `<div
75
96
  part="row${this.current === undefined ? '' : ' row-current'}"
76
97
  role=${role}
@@ -85,7 +106,7 @@ let HelixHeadlessListItem = class HelixHeadlessListItem extends HelixElement {
85
106
  aria-current=${this.current ?? nothing}
86
107
  tabindex=${this.grouped ? '-1' : nothing}
87
108
  >${content}</a
88
- ><slot name="end"></slot></div>`;
109
+ ><slot name="end"></slot>${this.renderGrip()}</div>`;
89
110
  }
90
111
  };
91
112
  __decorate([
@@ -101,9 +122,15 @@ __decorate([
101
122
  __decorate([
102
123
  property({ attribute: false })
103
124
  ], HelixHeadlessListItem.prototype, "focusable", void 0);
125
+ __decorate([
126
+ property({ attribute: false })
127
+ ], HelixHeadlessListItem.prototype, "grip", void 0);
104
128
  __decorate([
105
129
  property()
106
130
  ], HelixHeadlessListItem.prototype, "href", void 0);
131
+ __decorate([
132
+ property({ attribute: false })
133
+ ], HelixHeadlessListItem.prototype, "move", void 0);
107
134
  __decorate([
108
135
  property()
109
136
  ], HelixHeadlessListItem.prototype, "rel", void 0);
@@ -46,6 +46,23 @@ import { type ListSelectionBehavior, type ListSelectionMode } from '../selection
46
46
  * in `end` `tabindex="-1"` to leave it to the arrow keys and out of the tab
47
47
  * order.
48
48
  *
49
+ * **`reorderable` lets you move rows.** Each row gets a grip after its `end`
50
+ * slot, named by `move-label`. Drag a grip to move its row, and the list
51
+ * scrolls near an edge. Or press a grip with Space, Enter, or a click to pick
52
+ * up its row, move it with the arrow keys, and press the grip again to drop
53
+ * it. A click on another row drops it there, and Escape puts it back. The list
54
+ * says each step in its `live` region. A drop sends `helix-before-reorder`,
55
+ * which you can refuse, and then `helix-reorder`, whose `keys` hold every
56
+ * row's value in the new order. **You move the rows**: the list moves no
57
+ * element of yours, so your framework keeps the order it rendered.
58
+ *
59
+ * | Key, on a held row's grip | What it does |
60
+ * |---|---|
61
+ * | Down, Up | Moves the row one place. |
62
+ * | Home, End | Moves the row to the top or the bottom. |
63
+ * | Space, Enter | Drops the row. |
64
+ * | Escape | Puts the row back where it was. |
65
+ *
49
66
  * `start` and `reversed` number an ordered list as `<ol>` does. The list
50
67
  * writes where the numbers start and which way they run as `--list-first` and
51
68
  * `--list-step` on its slot, which the styled tier counts from. Reversed with
@@ -63,11 +80,28 @@ import { type ListSelectionBehavior, type ListSelectionMode } from '../selection
63
80
  * @event {Event} change - Fired once a press has changed which rows are selected.
64
81
  * @event {HelixActionEvent} helix-action - Sent from a row when the reader acts on it: Enter, or a press in a list that selects nothing. Read the row from `target`. A row with `href` follows its link instead.
65
82
  * @event {HelixBeforeChangeEvent} helix-before-change - Fired before a press changes which rows are selected, with the `value` it would leave. Cancelable.
83
+ * @event {HelixBeforeReorderEvent} helix-before-reorder - Fired when a row is dropped at a new place, in a `reorderable` list, with every row's value in the new order. Cancelable: cancel it to keep the row where it is.
84
+ * @event {HelixReorderEvent} helix-reorder - Fired after `helix-before-reorder` when nobody canceled it. Move your rows to the order in `keys`. Cancelable: cancel it to say the move did not happen.
85
+ *
86
+ * @csspart drag-preview - A copy of the row a pointer drags, which follows the pointer in the top layer until the row is let go, in a `reorderable` list. Hidden from assistive technology.
87
+ * @csspart live - The region that says each step of a move to screen readers, in a `reorderable` list. Drawn from the first move. Visually hidden in the styled tier.
66
88
  *
67
89
  * @cssproperty --list-first - The number of the first row, written where `start` or `reversed` moves it.
68
90
  * @cssproperty --list-step - What each row adds to the number before it: `1`, or `-1` where `reversed`.
69
91
  */
70
92
  export declare class HelixHeadlessList extends HelixElement {
93
+ /**
94
+ * The key this family's words are registered under, its styled tag:
95
+ * `registerWords('de', { 'helix-list': { moveLabel: '{name} verschieben' } })`.
96
+ */
97
+ static words: string;
98
+ /**
99
+ * What screen readers hear when a held row is put back, or a move is
100
+ * refused, in a `reorderable` list.
101
+ */
102
+ canceledLabel: string;
103
+ /** What screen readers hear when a row is dropped, in a `reorderable` list. */
104
+ droppedLabel: string;
71
105
  /**
72
106
  * The kind of list, which follows from the content.
73
107
  *
@@ -95,6 +129,27 @@ export declare class HelixHeadlessList extends HelixElement {
95
129
  * The list's name, read by screen readers.
96
130
  */
97
131
  label: string;
132
+ /**
133
+ * What screen readers hear each time an arrow key moves a held row, in a
134
+ * `reorderable` list. `{name}` is the row's words, `{position}` the place it
135
+ * would go, counting from 1, and `{count}` the number of rows.
136
+ */
137
+ movedLabel: string;
138
+ /**
139
+ * The name of each row's grip, in a `reorderable` list. `{name}` is
140
+ * replaced with the row's words.
141
+ */
142
+ moveLabel: string;
143
+ /**
144
+ * What screen readers hear when a key or a click picks up a row, in a
145
+ * `reorderable` list. `{name}` is the row's words.
146
+ */
147
+ pickedUpLabel: string;
148
+ /**
149
+ * Lets you move rows by dragging a grip, or with the keys. The list moves no
150
+ * row itself: you move your data on `helix-reorder`.
151
+ */
152
+ reorderable: boolean;
98
153
  /**
99
154
  * Numbers an ordered list downward, so the count falls row by row and ends at
100
155
  * its last row, as `<ol reversed>` does.
@@ -150,6 +205,15 @@ export declare class HelixHeadlessList extends HelixElement {
150
205
  * from the focused row and without wrapping. Left and Right are the row's.
151
206
  */
152
207
  protected readonly keys: KeyboardNavigationController;
208
+ /** The region that says each step of a move. */
209
+ private readonly status;
210
+ /** The value of a row just moved, whose grip takes focus back once the page has moved it. */
211
+ private moved;
212
+ /**
213
+ * Moving rows by their grips, in a `reorderable` list. The rows are the
214
+ * page's, so a drop asks the page to move them.
215
+ */
216
+ private readonly reorder;
153
217
  /** Whether the list is a grid a reader moves through. */
154
218
  private get interactive();
155
219
  /** The rows the list holds, in order. */
@@ -160,6 +224,29 @@ export declare class HelixHeadlessList extends HelixElement {
160
224
  private navigable;
161
225
  /** What a row stands for in `value`: its own `value`, or its words. */
162
226
  private valueFor;
227
+ /** The row that stands for a value. */
228
+ private rowFor;
229
+ /**
230
+ * Asks the page to move a row: `helix-before-reorder`, which can refuse it,
231
+ * then `helix-reorder`. Reports whether it stood.
232
+ */
233
+ private requestMove;
234
+ /**
235
+ * Tells every row whether it has a grip and where it stands in a move. Through
236
+ * `whenHydrated`, as `sync` is.
237
+ */
238
+ private syncMoves;
239
+ /**
240
+ * Gives focus back to the grip of a row the page has just moved, where moving
241
+ * the row took focus to the body.
242
+ *
243
+ * The page moves its rows when it likes, in the same task or a render later,
244
+ * so this waits for the rows to change. Focus that went anywhere but the body
245
+ * is where you put it, and is left there.
246
+ */
247
+ private refocus;
248
+ /** Whether the rows changed since the last move asked for one, for `refocus`. */
249
+ private rowsChanged;
163
250
  /**
164
251
  * Tells every row its place: whether it holds the one tab stop and whether
165
252
  * it is selected, or that it is a plain row. Through `whenHydrated`, so a
@@ -4,17 +4,22 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { commaList, customElement, HelixActionEvent, HelixBeforeChangeEvent, HelixElement, hostAria, inlineStep, KeyboardNavigationController, requestChange, rovingStop, selectsAll, typeaheadByWords, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { commaList, customElement, deepActiveElement, drawStatus, focusItemOf, formatWords, HelixActionEvent, HelixElement, hostAria, inlineStep, KeyboardNavigationController, placeKey, pressedOwnControl, ReorderController, requestReorder, requestValue, rovingStop, StatusController, scrollingAncestor, scrollRoom, selectsAll, typeaheadByWords, whenHydrated, words, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { HelixHeadlessListItem } from '../item/list-item.js';
11
11
  import { numbering } from '../numbering.js';
12
12
  import { choiceValue, pageReach, rowStop, } from '../selection.js';
13
- const PRESSABLE = 'a[href], button, input, label, select, textarea, [tabindex]';
14
13
  let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
15
14
  constructor() {
16
15
  super(...arguments);
16
+ this.canceledLabel = 'Canceled';
17
+ this.droppedLabel = 'Dropped';
17
18
  this.label = '';
19
+ this.movedLabel = '{name} moved to position {position} of {count}';
20
+ this.moveLabel = 'Move {name}';
21
+ this.pickedUpLabel = 'Picked up {name}';
22
+ this.reorderable = false;
18
23
  this.reversed = false;
19
24
  this.selectionBehavior = 'toggle';
20
25
  this.value = '';
@@ -26,6 +31,33 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
26
31
  typeahead: typeaheadByWords(),
27
32
  wrap: false,
28
33
  });
34
+ this.status = new StatusController(this);
35
+ this.reorder = new ReorderController(this, {
36
+ axis: 'block',
37
+ box: (key) => this.rowFor(key)?.getBoundingClientRect(),
38
+ drop: (move) => this.requestMove(move),
39
+ enabled: () => this.reorderable,
40
+ grip: (event) => {
41
+ const row = this.rowOf(event);
42
+ const element = row?.gripElement;
43
+ return row && element && event.composedPath().includes(element)
44
+ ? { element, key: this.valueFor(row) }
45
+ : undefined;
46
+ },
47
+ item: (event) => {
48
+ const row = this.rowOf(event);
49
+ return row ? this.valueFor(row) : undefined;
50
+ },
51
+ keys: () => this.rows.map((row) => this.valueFor(row)),
52
+ name: (key) => this.rowFor(key)?.words || key,
53
+ preview: (key) => this.rowFor(key),
54
+ say: (said) => this.status.say(said),
55
+ scroller: () => {
56
+ const first = this.rows[0];
57
+ return first ? scrollingAncestor(first, { axis: 'y', overflowing: true }) : null;
58
+ },
59
+ });
60
+ this.rowsChanged = false;
29
61
  this.handleKeyCapture = (event) => {
30
62
  this.moving = { extend: event.shiftKey, toggle: event.ctrlKey || event.metaKey };
31
63
  };
@@ -71,11 +103,8 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
71
103
  if (!row) {
72
104
  return;
73
105
  }
74
- const path = event.composedPath();
75
106
  const cell = row.cell;
76
- const end = cell && path.includes(cell) ? path.indexOf(cell) : path.indexOf(row);
77
- const inner = path.slice(0, Math.max(0, end));
78
- if (inner.some((node) => node instanceof HTMLElement && node.matches(PRESSABLE))) {
107
+ if (pressedOwnControl(event, cell && event.composedPath().includes(cell) ? cell : row)) {
79
108
  return;
80
109
  }
81
110
  if (this.selectionMode === 'none') {
@@ -97,9 +126,11 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
97
126
  }
98
127
  };
99
128
  this.handleSlotChange = () => {
129
+ this.rowsChanged = true;
100
130
  this.requestUpdate();
101
131
  };
102
132
  }
133
+ static { this.words = 'helix-list'; }
103
134
  get interactive() {
104
135
  return this.selectionMode !== undefined;
105
136
  }
@@ -110,18 +141,63 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
110
141
  return this.interactive ? this.rows.filter((row) => !row.disabled) : [];
111
142
  }
112
143
  navigable(row) {
113
- return {
114
- contains: (node) => row.contains(node),
144
+ return focusItemOf(row, {
115
145
  disabled: row.disabled,
116
- focusItem: () => row.focusItem(),
117
- select: () => { },
118
- selected: false,
146
+ focus: () => row.focusItem(),
119
147
  words: row.words,
120
- };
148
+ });
121
149
  }
122
150
  valueFor(row) {
123
151
  return row.value || row.words;
124
152
  }
153
+ rowFor(key) {
154
+ return this.rows.find((row) => this.valueFor(row) === key);
155
+ }
156
+ requestMove({ from, key, to }) {
157
+ const old = this.rows.map((row) => this.valueFor(row));
158
+ const keys = placeKey(old, old, key, to);
159
+ const stood = requestReorder(this, {
160
+ from,
161
+ key,
162
+ keys,
163
+ kind: 'item',
164
+ to: keys.indexOf(key),
165
+ value: keys.join(','),
166
+ });
167
+ this.moved = stood ? key : undefined;
168
+ this.rowsChanged = false;
169
+ return stood;
170
+ }
171
+ syncMoves() {
172
+ const held = this.reorder.held;
173
+ const mark = this.reorder.mark;
174
+ for (const row of this.rows) {
175
+ const key = this.valueFor(row);
176
+ whenHydrated(row, () => {
177
+ row.grip =
178
+ this.reorderable && !row.disabled
179
+ ? formatWords(this, 'moveLabel', { name: row.words || key })
180
+ : undefined;
181
+ row.move =
182
+ held?.key === key
183
+ ? 'dragging'
184
+ : mark?.key === key
185
+ ? `drop-${mark.edge}`
186
+ : undefined;
187
+ });
188
+ }
189
+ }
190
+ refocus() {
191
+ const row = this.moved === undefined ? undefined : this.rowFor(this.moved);
192
+ if (!row || !this.rowsChanged) {
193
+ return;
194
+ }
195
+ const active = deepActiveElement();
196
+ if (active === null || active === document.body) {
197
+ row.gripElement?.focus();
198
+ }
199
+ this.moved = undefined;
200
+ }
125
201
  sync() {
126
202
  const mode = this.selectionMode;
127
203
  const chosen = new Set(commaList(this.value));
@@ -149,14 +225,8 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
149
225
  if (next === null) {
150
226
  return;
151
227
  }
152
- requestChange({
153
- apply: (value) => {
154
- this.value = value;
155
- this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
156
- },
157
- event: (value) => new HelixBeforeChangeEvent({ value }),
158
- host: this,
159
- next,
228
+ requestValue(this, next, (value) => {
229
+ this.value = value;
160
230
  });
161
231
  }
162
232
  choice(row, extend, toggle, arrived) {
@@ -203,8 +273,7 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
203
273
  const box = one.getBoundingClientRect();
204
274
  return { bottom: box.bottom, top: box.top };
205
275
  });
206
- const room = this.scrollHeight > this.clientHeight + 1 ? this.clientHeight : window.innerHeight;
207
- const target = rows[pageReach(edges, rows.indexOf(row), room, step)];
276
+ const target = rows[pageReach(edges, rows.indexOf(row), scrollRoom(this), step)];
208
277
  if (target && target !== row) {
209
278
  target.focusItem();
210
279
  }
@@ -254,6 +323,10 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
254
323
  if (this.interactive || changed.get('selectionMode') !== undefined) {
255
324
  this.sync();
256
325
  }
326
+ if (this.reorderable || changed.get('reorderable') !== undefined) {
327
+ this.syncMoves();
328
+ this.refocus();
329
+ }
257
330
  }
258
331
  willUpdate(changed) {
259
332
  super.willUpdate(changed);
@@ -265,15 +338,38 @@ let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
265
338
  return counted ? `--list-first: ${counted.first}; --list-step: ${counted.step}` : nothing;
266
339
  }
267
340
  render() {
268
- return html `<slot style=${this.numbers} @slotchange=${this.handleSlotChange}></slot>`;
341
+ return html `<slot style=${this.numbers} @slotchange=${this.handleSlotChange}></slot>${drawStatus(this.status)}${this.reorder.drawDragPreview()}`;
269
342
  }
270
343
  };
344
+ __decorate([
345
+ words,
346
+ property({ attribute: 'canceled-label' })
347
+ ], HelixHeadlessList.prototype, "canceledLabel", void 0);
348
+ __decorate([
349
+ words,
350
+ property({ attribute: 'dropped-label' })
351
+ ], HelixHeadlessList.prototype, "droppedLabel", void 0);
271
352
  __decorate([
272
353
  property({ reflect: true })
273
354
  ], HelixHeadlessList.prototype, "kind", void 0);
274
355
  __decorate([
275
356
  property()
276
357
  ], HelixHeadlessList.prototype, "label", void 0);
358
+ __decorate([
359
+ words,
360
+ property({ attribute: 'moved-label' })
361
+ ], HelixHeadlessList.prototype, "movedLabel", void 0);
362
+ __decorate([
363
+ words,
364
+ property({ attribute: 'move-label' })
365
+ ], HelixHeadlessList.prototype, "moveLabel", void 0);
366
+ __decorate([
367
+ words,
368
+ property({ attribute: 'picked-up-label' })
369
+ ], HelixHeadlessList.prototype, "pickedUpLabel", void 0);
370
+ __decorate([
371
+ property({ type: Boolean })
372
+ ], HelixHeadlessList.prototype, "reorderable", void 0);
277
373
  __decorate([
278
374
  property({ type: Boolean })
279
375
  ], HelixHeadlessList.prototype, "reversed", void 0);
@@ -0,0 +1 @@
1
+ export { ListboxReorderController, reorderListbox } from './listbox-reorder.js';
@@ -0,0 +1,4 @@
1
+ import { HelixHeadlessListbox } from '../root/listbox-root.js';
2
+ import { reorderListbox } from './listbox-reorder.js';
3
+ reorderListbox(HelixHeadlessListbox);
4
+ export { ListboxReorderController, reorderListbox } from './listbox-reorder.js';
@@ -0,0 +1,83 @@
1
+ import type { CSSResult, ReactiveController } from 'lit';
2
+ import type { HelixHeadlessListbox } from '../root/listbox-root.js';
3
+ /**
4
+ * Moves the options of a `reorderable` listbox, by pointer and by keyboard,
5
+ * and says each move in the list's live region.
6
+ *
7
+ * **Its own entry**, `@fusion.dev/helix-headless/listbox/reorder`, so a list
8
+ * that never moves options carries none of this. Importing the entry gives
9
+ * every listbox one, and `reorderable` turns it on.
10
+ *
11
+ * - **Alt with Up or Down** moves the highlighted option a place at once, and
12
+ * Alt with Home or End to either end, as the APG's rearrangeable listbox
13
+ * does. The highlight stays on the option.
14
+ * - **A pointer** drags a whole option, with no grip: a press that travels is
15
+ * a drag, and one that does not is still a press that chooses it. The list
16
+ * scrolls near an edge.
17
+ * - **The page moves the options.** A drop sends `helix-before-reorder` and
18
+ * then `helix-reorder` with every value in the new order. An option in a
19
+ * group moves within its group, and a list of `items` moves its records.
20
+ *
21
+ * It marks the option being dragged with `:state(dragging)` and the one the
22
+ * drop indicator is beside with `:state(drop-before)` or `:state(drop-after)`.
23
+ * While a pointer drags an option, a copy of it follows the pointer as the
24
+ * list's `drag-preview` part. The styled tier's entry draws those through two
25
+ * sheets it hands in, which this adopts while the list reorders: one into
26
+ * each option, and one into the list.
27
+ */
28
+ export declare class ListboxReorderController implements ReactiveController {
29
+ private readonly host;
30
+ /** The sheet each option adopts while the list reorders, from the styled tier. */
31
+ sheet: CSSResult | undefined;
32
+ /**
33
+ * The sheet the list adopts while it reorders, from the styled tier, which
34
+ * draws the `drag-preview` part.
35
+ */
36
+ listSheet: CSSResult | undefined;
37
+ /** The options marked last, so a mark that moves is taken off where it was. */
38
+ private marked;
39
+ private readonly reorder;
40
+ constructor(host: HelixHeadlessListbox, sheet?: CSSResult, listSheet?: CSSResult);
41
+ /**
42
+ * Marks where each option stands once the list has drawn: after the update,
43
+ * because a list of `items` draws its options in its own last step, and
44
+ * reuses each element for another record as it scrolls.
45
+ */
46
+ hostUpdated(): void;
47
+ /**
48
+ * Draws the list's `drag-preview` part at the end of its shadow root while
49
+ * it reorders, and takes it away after. The list's own template has none to
50
+ * draw, and the controller fills this one while a pointer drags an option.
51
+ */
52
+ private drawPreview;
53
+ /** The options the list draws now: its elements, or the records it drew of `items`. */
54
+ private get drawn();
55
+ /** The option an event passed through. */
56
+ private optionOf;
57
+ /** The drawn option that stands for a value. */
58
+ private optionFor;
59
+ /**
60
+ * The values an option moves among: every record of `items`, or the options
61
+ * beside it, which in a list of groups are the options of its group.
62
+ */
63
+ private keysAround;
64
+ /** Puts each option's state in a move on it, and the styled tier's sheets. */
65
+ private mark;
66
+ }
67
+ /**
68
+ * Gives every listbox of a class a `ListboxReorderController`, and the class
69
+ * the words it says, as properties that read and write their attributes:
70
+ * `movedLabel`, `canceledLabel`, `droppedLabel`, and `pickedUpLabel`.
71
+ *
72
+ * The entries call it for their own tier's class: the headless entry for
73
+ * `HelixHeadlessListbox`, and the styled one for `HelixListbox`, with the
74
+ * sheet that draws a move on an option and the sheet that draws the list's
75
+ * `drag-preview` part. A class that has registered keeps the list of what
76
+ * it was given when it did, so each is given its own.
77
+ *
78
+ * **Lists already on the page are given one too.** A page that imports the
79
+ * list and then this entry has its lists upgraded, and built, before this
80
+ * runs, so the ones in the document and its open shadow roots are found and
81
+ * given theirs, and every list built after gets one as it is built.
82
+ */
83
+ export declare const reorderListbox: (element: typeof HelixHeadlessListbox, sheet?: CSSResult, listSheet?: CSSResult) => void;