@fusion.dev/helix-headless 0.146.0 → 0.148.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 (288) hide show
  1. package/custom-elements.json +9287 -1084
  2. package/dist/accordion/item/accordion-item.d.ts +43 -21
  3. package/dist/accordion/item/accordion-item.js +37 -11
  4. package/dist/accordion/root/accordion-root.d.ts +8 -2
  5. package/dist/accordion/root/accordion-root.js +6 -8
  6. package/dist/announcement/root/announcement-root.d.ts +66 -6
  7. package/dist/announcement/root/announcement-root.js +144 -13
  8. package/dist/area-chart/root/area-chart-root.d.ts +18 -1
  9. package/dist/area-chart/root/area-chart-root.js +14 -7
  10. package/dist/avatar/root/avatar-root.d.ts +31 -1
  11. package/dist/avatar/root/avatar-root.js +11 -1
  12. package/dist/badge/count.d.ts +14 -0
  13. package/dist/badge/count.js +20 -0
  14. package/dist/badge/root/badge-root.d.ts +57 -6
  15. package/dist/badge/root/badge-root.js +77 -8
  16. package/dist/bar-chart/root/bar-chart-root.js +11 -20
  17. package/dist/bar-chart/stack.d.ts +10 -0
  18. package/dist/bar-chart/stack.js +8 -0
  19. package/dist/blockquote/root/blockquote-root.d.ts +66 -8
  20. package/dist/blockquote/root/blockquote-root.js +85 -8
  21. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
  22. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
  23. package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -2
  24. package/dist/button/root/button-root.d.ts +24 -38
  25. package/dist/button/root/button-root.js +6 -37
  26. package/dist/button/submitter.d.ts +27 -0
  27. package/dist/button/submitter.js +25 -0
  28. package/dist/button-group/arrows.d.ts +14 -0
  29. package/dist/button-group/arrows.js +10 -0
  30. package/dist/button-group/root/button-group-root.d.ts +141 -3
  31. package/dist/button-group/root/button-group-root.js +142 -2
  32. package/dist/canvas/edge-pan.d.ts +61 -0
  33. package/dist/canvas/edge-pan.js +63 -0
  34. package/dist/canvas/node/canvas-node.d.ts +12 -2
  35. package/dist/canvas/node/canvas-node.js +6 -2
  36. package/dist/canvas/root/canvas-document.d.ts +10 -0
  37. package/dist/canvas/root/canvas-document.js +1 -0
  38. package/dist/canvas/root/canvas-root.d.ts +107 -5
  39. package/dist/canvas/root/canvas-root.js +140 -36
  40. package/dist/canvas/snap.d.ts +42 -0
  41. package/dist/canvas/snap.js +32 -0
  42. package/dist/card/root/card-root.d.ts +12 -1
  43. package/dist/card/root/card-root.js +11 -4
  44. package/dist/carousel/root/carousel-root.d.ts +4 -3
  45. package/dist/carousel/root/carousel-root.js +2 -6
  46. package/dist/chat/root/chat-root.d.ts +28 -4
  47. package/dist/chat/root/chat-root.js +12 -7
  48. package/dist/checkbox/root/checkbox-root.js +5 -7
  49. package/dist/checkbox-group/root/checkbox-group-root.d.ts +13 -0
  50. package/dist/checkbox-group/root/checkbox-group-root.js +16 -7
  51. package/dist/checkbox-group/select-all.d.ts +9 -4
  52. package/dist/checkbox-group/select-all.js +1 -1
  53. package/dist/code-block/root/code-block-root.d.ts +41 -18
  54. package/dist/code-block/root/code-block-root.js +21 -6
  55. package/dist/color-input/root/color-input-root.d.ts +11 -0
  56. package/dist/color-input/root/color-input-root.js +12 -5
  57. package/dist/color-picker/channels.js +1 -2
  58. package/dist/color-picker/root/color-picker-root.d.ts +32 -24
  59. package/dist/color-picker/root/color-picker-root.js +99 -55
  60. package/dist/color-picker/wheel.d.ts +28 -0
  61. package/dist/color-picker/wheel.js +15 -0
  62. package/dist/combobox/root/combobox-root.d.ts +83 -11
  63. package/dist/combobox/root/combobox-root.js +81 -18
  64. package/dist/command/root/command-root.d.ts +7 -4
  65. package/dist/command/root/command-root.js +2 -19
  66. package/dist/copy-button/root/copy-button-root.d.ts +16 -1
  67. package/dist/copy-button/root/copy-button-root.js +7 -2
  68. package/dist/data-table/keys.d.ts +0 -18
  69. package/dist/data-table/keys.js +1 -11
  70. package/dist/data-table/root/data-table-root.js +29 -50
  71. package/dist/date-input/root/date-input-root.d.ts +8 -1
  72. package/dist/date-input/root/date-input-root.js +8 -5
  73. package/dist/date-picker/root/date-picker-root.d.ts +14 -9
  74. package/dist/date-picker/root/date-picker-root.js +21 -16
  75. package/dist/description-list/item/description-list-item.d.ts +22 -4
  76. package/dist/description-list/item/description-list-item.js +14 -4
  77. package/dist/divider/root/divider-root.d.ts +45 -16
  78. package/dist/divider/root/divider-root.js +28 -4
  79. package/dist/donut-chart/root/donut-chart-root.js +13 -6
  80. package/dist/donut-chart/slice-label.d.ts +35 -0
  81. package/dist/donut-chart/slice-label.js +11 -0
  82. package/dist/drawer/root/drawer-root.d.ts +4 -2
  83. package/dist/drawer/root/drawer-root.js +15 -3
  84. package/dist/drilldown/item/drilldown-item.d.ts +21 -1
  85. package/dist/drilldown/item/drilldown-item.js +38 -4
  86. package/dist/drilldown/root/drilldown-root.js +3 -2
  87. package/dist/element-events.generated.js +5 -1
  88. package/dist/empty/root/empty-root.d.ts +46 -2
  89. package/dist/empty/root/empty-root.js +50 -5
  90. package/dist/file-input/root/file-input-root.d.ts +34 -6
  91. package/dist/file-input/root/file-input-root.js +55 -21
  92. package/dist/file-input/status.d.ts +24 -0
  93. package/dist/file-input/status.js +11 -0
  94. package/dist/filter-input/chip/filter-chip.d.ts +23 -0
  95. package/dist/filter-input/chip/filter-chip.js +10 -2
  96. package/dist/filter-input/root/filter-input-root.d.ts +8 -0
  97. package/dist/filter-input/root/filter-input-root.js +17 -27
  98. package/dist/format-date/fields.d.ts +20 -0
  99. package/dist/format-date/fields.js +14 -0
  100. package/dist/format-date/options.d.ts +5 -5
  101. package/dist/format-date/options.js +10 -39
  102. package/dist/format-date/root/format-date-root.d.ts +53 -4
  103. package/dist/format-date/root/format-date-root.js +38 -50
  104. package/dist/graph/root/graph-root.d.ts +23 -5
  105. package/dist/graph/root/graph-root.js +17 -20
  106. package/dist/heatmap/root/buckets.d.ts +21 -0
  107. package/dist/heatmap/root/buckets.js +34 -0
  108. package/dist/heatmap/root/heatmap-root.d.ts +76 -3
  109. package/dist/heatmap/root/heatmap-root.js +105 -20
  110. package/dist/icon/index.d.ts +1 -1
  111. package/dist/icon/index.js +1 -1
  112. package/dist/icon/registry.d.ts +26 -1
  113. package/dist/icon/registry.js +12 -1
  114. package/dist/icon/root/icon-root.d.ts +13 -0
  115. package/dist/icon/root/icon-root.js +23 -2
  116. package/dist/icon/root/index.d.ts +1 -1
  117. package/dist/icon/root/index.js +1 -1
  118. package/dist/image/root/image-root.d.ts +20 -0
  119. package/dist/image/root/image-root.js +6 -1
  120. package/dist/input/root/input-root.d.ts +23 -2
  121. package/dist/input/root/input-root.js +12 -8
  122. package/dist/kbd/root/kbd-root.d.ts +20 -3
  123. package/dist/kbd/root/kbd-root.js +23 -50
  124. package/dist/legend/hidden-series.d.ts +10 -2
  125. package/dist/legend/hidden-series.js +5 -2
  126. package/dist/legend/root/legend-root.d.ts +25 -7
  127. package/dist/legend/root/legend-root.js +25 -26
  128. package/dist/lightbox/root/lightbox-root.d.ts +50 -5
  129. package/dist/lightbox/root/lightbox-root.js +76 -8
  130. package/dist/lightbox/zoom.d.ts +2 -0
  131. package/dist/lightbox/zoom.js +5 -3
  132. package/dist/line-chart/root/line-chart-root.d.ts +16 -0
  133. package/dist/line-chart/root/line-chart-root.js +10 -2
  134. package/dist/list/root/list-root.d.ts +10 -2
  135. package/dist/list/root/list-root.js +31 -24
  136. package/dist/list/selection.d.ts +17 -0
  137. package/dist/list/selection.js +16 -0
  138. package/dist/listbox/root/listbox-root.d.ts +125 -26
  139. package/dist/listbox/root/listbox-root.js +156 -166
  140. package/dist/map/marker/map-marker.d.ts +2 -1
  141. package/dist/map/root/map-root.d.ts +40 -2
  142. package/dist/map/root/map-root.js +64 -23
  143. package/dist/megamenu/hand-over.d.ts +75 -0
  144. package/dist/megamenu/hand-over.js +67 -0
  145. package/dist/megamenu/root/megamenu-root.d.ts +38 -14
  146. package/dist/megamenu/root/megamenu-root.js +29 -50
  147. package/dist/menu/item/menu-item.js +4 -4
  148. package/dist/menu/root/menu-root.d.ts +5 -2
  149. package/dist/meter/root/meter-root.d.ts +42 -0
  150. package/dist/meter/root/meter-root.js +33 -7
  151. package/dist/navigation/root/navigation-root.js +5 -8
  152. package/dist/notifications/group/notification-group.d.ts +8 -1
  153. package/dist/notifications/group/notification-group.js +12 -6
  154. package/dist/notifications/notification/notification.d.ts +12 -1
  155. package/dist/notifications/notification/notification.js +3 -1
  156. package/dist/notifications/root/notifications-root.d.ts +48 -3
  157. package/dist/notifications/root/notifications-root.js +36 -6
  158. package/dist/number-input/grain.d.ts +28 -0
  159. package/dist/number-input/grain.js +14 -0
  160. package/dist/number-input/root/number-input-root.d.ts +17 -1
  161. package/dist/number-input/root/number-input-root.js +29 -18
  162. package/dist/object-inspector/root/object-inspector-root.d.ts +17 -6
  163. package/dist/object-inspector/root/object-inspector-root.js +31 -20
  164. package/dist/option/index.d.ts +1 -0
  165. package/dist/option/index.js +1 -0
  166. package/dist/option/separator/option-separator.d.ts +30 -0
  167. package/dist/option/separator/option-separator.js +21 -0
  168. package/dist/outline/root/outline-root.d.ts +12 -0
  169. package/dist/outline/root/outline-root.js +5 -19
  170. package/dist/pagination/size/pagination-size.d.ts +6 -0
  171. package/dist/pagination/size/pagination-size.js +5 -3
  172. package/dist/pin-input/code.d.ts +51 -1
  173. package/dist/pin-input/code.js +37 -0
  174. package/dist/pin-input/root/pin-input-root.d.ts +98 -121
  175. package/dist/pin-input/root/pin-input-root.js +151 -156
  176. package/dist/popover/hide-outside.js +2 -9
  177. package/dist/popover/root/popover-root.d.ts +7 -1
  178. package/dist/popover/root/popover-root.js +9 -1
  179. package/dist/progress/root/progress-root.d.ts +27 -0
  180. package/dist/progress/root/progress-root.js +25 -7
  181. package/dist/qr-code/export.d.ts +19 -0
  182. package/dist/qr-code/export.js +14 -0
  183. package/dist/qr-code/name.d.ts +11 -0
  184. package/dist/qr-code/name.js +7 -0
  185. package/dist/qr-code/root/qr-code-root.d.ts +31 -9
  186. package/dist/qr-code/root/qr-code-root.js +29 -17
  187. package/dist/radio/group/radio-group.d.ts +15 -0
  188. package/dist/radio/root/radio-root.js +2 -2
  189. package/dist/rating/root/rating-root.d.ts +22 -9
  190. package/dist/rating/root/rating-root.js +15 -39
  191. package/dist/scatter-chart/measures.d.ts +22 -0
  192. package/dist/scatter-chart/measures.js +11 -0
  193. package/dist/scatter-chart/root/scatter-chart-root.d.ts +26 -0
  194. package/dist/scatter-chart/root/scatter-chart-root.js +21 -7
  195. package/dist/scroll-area/scrollbar.d.ts +0 -8
  196. package/dist/scroll-area/scrollbar.js +1 -1
  197. package/dist/select/align.d.ts +47 -0
  198. package/dist/select/align.js +7 -0
  199. package/dist/select/root/select-root.d.ts +115 -11
  200. package/dist/select/root/select-root.js +104 -20
  201. package/dist/slider/root/slider-root.d.ts +18 -1
  202. package/dist/slider/root/slider-root.js +22 -0
  203. package/dist/sparkline/readings.d.ts +30 -12
  204. package/dist/sparkline/readings.js +32 -15
  205. package/dist/sparkline/root/sparkline-root.d.ts +46 -3
  206. package/dist/sparkline/root/sparkline-root.js +60 -21
  207. package/dist/speed-dial/group/speed-dial-group.d.ts +48 -0
  208. package/dist/speed-dial/group/speed-dial-group.js +43 -0
  209. package/dist/speed-dial/index.d.ts +1 -0
  210. package/dist/speed-dial/index.js +1 -0
  211. package/dist/speed-dial/item/speed-dial-item.d.ts +27 -2
  212. package/dist/speed-dial/item/speed-dial-item.js +43 -5
  213. package/dist/speed-dial/long-press.d.ts +50 -0
  214. package/dist/speed-dial/long-press.js +48 -0
  215. package/dist/speed-dial/root/speed-dial-root.d.ts +86 -1
  216. package/dist/speed-dial/root/speed-dial-root.js +123 -6
  217. package/dist/splitter/root/splitter-root.d.ts +9 -2
  218. package/dist/splitter/root/splitter-root.js +18 -3
  219. package/dist/steps/root/steps-root.d.ts +8 -1
  220. package/dist/steps/root/steps-root.js +6 -1
  221. package/dist/steps/step/step.d.ts +1 -0
  222. package/dist/steps/step/step.js +1 -1
  223. package/dist/table/cell/table-cell.d.ts +8 -1
  224. package/dist/table/cell/table-cell.js +6 -2
  225. package/dist/table/column/table-column.d.ts +6 -0
  226. package/dist/table/column/table-column.js +5 -1
  227. package/dist/table/grid-controller.d.ts +117 -0
  228. package/dist/table/grid-controller.js +293 -0
  229. package/dist/table/root/table-root.d.ts +47 -3
  230. package/dist/table/root/table-root.js +93 -29
  231. package/dist/table/row/table-row.d.ts +36 -0
  232. package/dist/table/row/table-row.js +52 -2
  233. package/dist/tabs/root/tabs-root.d.ts +5 -3
  234. package/dist/tag/group/tag-group.d.ts +16 -4
  235. package/dist/tag/group/tag-group.js +23 -20
  236. package/dist/textarea/root/textarea-root.d.ts +14 -2
  237. package/dist/textarea/root/textarea-root.js +6 -7
  238. package/dist/time-input/root/time-input-root.d.ts +5 -1
  239. package/dist/time-input/root/time-input-root.js +10 -7
  240. package/dist/time-picker/root/time-picker-root.d.ts +12 -14
  241. package/dist/time-picker/root/time-picker-root.js +18 -23
  242. package/dist/toast/item/toast-item.d.ts +9 -6
  243. package/dist/toast/item/toast-item.js +1 -1
  244. package/dist/toast/root/toast-root.d.ts +40 -4
  245. package/dist/toast/root/toast-root.js +68 -16
  246. package/dist/toast/words.d.ts +12 -0
  247. package/dist/toast/words.js +25 -0
  248. package/dist/toggle/group/toggle-group.d.ts +29 -5
  249. package/dist/toggle/group/toggle-group.js +26 -43
  250. package/dist/toggle/root/toggle-root.js +2 -4
  251. package/dist/toolbar/root/toolbar-root.d.ts +52 -5
  252. package/dist/toolbar/root/toolbar-root.js +88 -13
  253. package/dist/tooltip/root/tooltip-root.d.ts +7 -1
  254. package/dist/tooltip/root/tooltip-root.js +10 -2
  255. package/dist/tour/root/tour-root.d.ts +15 -0
  256. package/dist/tour/root/tour-root.js +20 -1
  257. package/dist/tour/stop/tour-stop.d.ts +3 -0
  258. package/dist/tour/stop/tour-stop.js +3 -3
  259. package/dist/tree/root/tree-root.js +2 -2
  260. package/dist/trend/figure.d.ts +16 -0
  261. package/dist/trend/figure.js +8 -0
  262. package/dist/trend/root/trend-root.d.ts +41 -2
  263. package/dist/trend/root/trend-root.js +29 -3
  264. package/dist/video/root/extra-controls.d.ts +12 -0
  265. package/dist/video/root/extra-controls.js +6 -2
  266. package/dist/video/root/video-root.d.ts +16 -1
  267. package/dist/video/root/video-root.js +15 -1
  268. package/dist/video-playlist/root/video-playlist-root.d.ts +11 -1
  269. package/dist/video-playlist/root/video-playlist-root.js +3 -0
  270. package/dist/virtual-list/fill.d.ts +11 -0
  271. package/dist/virtual-list/fill.js +9 -0
  272. package/dist/virtual-list/keys.d.ts +16 -7
  273. package/dist/virtual-list/keys.js +17 -6
  274. package/dist/virtual-list/plan.d.ts +17 -1
  275. package/dist/virtual-list/plan.js +13 -2
  276. package/dist/virtual-list/root/virtual-list-root.d.ts +25 -3
  277. package/dist/virtual-list/root/virtual-list-root.js +53 -41
  278. package/lint.json +1 -1
  279. package/package.json +5 -5
  280. package/types/jsx.d.ts +4934 -954
  281. package/types/svelte.d.ts +2 -0
  282. package/types/vue.d.ts +946 -253
  283. package/dist/color-picker/swatches.d.ts +0 -12
  284. package/dist/color-picker/swatches.js +0 -26
  285. package/dist/rating/steps.d.ts +0 -7
  286. package/dist/rating/steps.js +0 -9
  287. package/dist/tooltip/focus-target.d.ts +0 -6
  288. package/dist/tooltip/focus-target.js +0 -9
@@ -4,22 +4,156 @@ 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 { auditName, customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
7
+ import { auditName, commaList, customElement, HelixElement, hostAria, inlineStep, pressedValue, reportRuntime, requestValue, rovingStop, toolbarAround, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { arrowTarget } from '../arrows.js';
11
+ const isGroupButton = (child) => child instanceof HTMLElement && 'focusable' in child && 'value' in child;
10
12
  let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixElement {
11
13
  constructor() {
12
14
  super(...arguments);
13
15
  this.label = '';
16
+ this.value = '';
17
+ this.lastFocused = undefined;
18
+ this.told = new Map();
19
+ this.warned = false;
20
+ this.handlePress = (event) => {
21
+ const mode = this.selectionMode;
22
+ const button = this.buttons.find((one) => event.composedPath().includes(one));
23
+ if (mode && button && button.value !== '') {
24
+ requestValue(this, pressedValue(mode, this.value, button.value), (next) => {
25
+ this.value = next;
26
+ });
27
+ }
28
+ };
29
+ this.handleKeydown = (event) => {
30
+ const buttons = this.roving ? this.buttons.filter((one) => one.disabled !== true) : [];
31
+ const from = buttons.findIndex((one) => event.composedPath().includes(one));
32
+ const to = arrowTarget(event.key, inlineStep(this, event.key), from, buttons.length);
33
+ if (to >= 0 && !event.defaultPrevented) {
34
+ event.preventDefault();
35
+ buttons[to]?.focus();
36
+ }
37
+ };
38
+ this.noteFocus = (event) => {
39
+ const button = this.buttons.find((one) => event.composedPath().includes(one));
40
+ if (button && button !== this.lastFocused) {
41
+ this.lastFocused = button;
42
+ this.sync();
43
+ }
44
+ };
45
+ }
46
+ get buttons() {
47
+ return this.selectionMode && this.children ? [...this.children].filter(isGroupButton) : [];
48
+ }
49
+ get roving() {
50
+ return this.selectionMode !== undefined && toolbarAround(this) === null;
51
+ }
52
+ pressed(button) {
53
+ return button.value !== '' && commaList(this.value).includes(button.value);
54
+ }
55
+ sync() {
56
+ const buttons = this.buttons;
57
+ const roving = this.roving;
58
+ const stop = roving
59
+ ? rovingStop(buttons, this.lastFocused, {
60
+ disabled: (button) => button.disabled === true,
61
+ selected: (button) => this.pressed(button),
62
+ })
63
+ : undefined;
64
+ for (const [button, roved] of this.told) {
65
+ if (!buttons.includes(button)) {
66
+ this.told.delete(button);
67
+ this.mark(button);
68
+ if (roved) {
69
+ whenHydrated(button, () => {
70
+ button.focusable = true;
71
+ });
72
+ }
73
+ }
74
+ }
75
+ for (const button of buttons) {
76
+ this.told.set(button, roving);
77
+ this.mark(button);
78
+ if (roving) {
79
+ whenHydrated(button, () => {
80
+ button.focusable = button === stop;
81
+ });
82
+ }
83
+ }
84
+ for (const child of this.selectionMode && this.children ? this.children : []) {
85
+ if (child.localName.includes('-') && !isGroupButton(child)) {
86
+ void customElements.whenDefined(child.localName).then(() => this.sync());
87
+ }
88
+ else if (child.localName === 'button' && !child.hasAttribute('aria-pressed')) {
89
+ this.warn(child);
90
+ }
91
+ }
92
+ }
93
+ warn(button) {
94
+ if (this.warned) {
95
+ return;
96
+ }
97
+ this.warned = true;
98
+ reportRuntime({
99
+ kind: 'untold-toggle',
100
+ message: `<${this.localName}> cannot press a native <button>: its state would be written onto your ` +
101
+ 'markup. Slot a Helix button with a `value`, or set `aria-pressed` on the button yourself.',
102
+ tag: button.localName,
103
+ });
104
+ }
105
+ mark(button) {
106
+ void button.updateComplete.then(() => {
107
+ const control = button.shadowRoot?.querySelector('button');
108
+ if (control && !button.hasAttribute('aria-pressed')) {
109
+ const toggle = this.told.has(button) && button.value !== '';
110
+ this.markPressed(control, toggle ? this.pressed(button) : undefined);
111
+ }
112
+ });
113
+ }
114
+ markPressed(control, pressed) {
115
+ if (pressed === undefined) {
116
+ control.removeAttribute('aria-pressed');
117
+ }
118
+ else {
119
+ control.setAttribute('aria-pressed', String(pressed));
120
+ }
121
+ control.style.setProperty('--button-group-pressed', pressed === undefined ? '' : pressed ? '1' : '0');
122
+ }
123
+ connectedCallback() {
124
+ super.connectedCallback();
125
+ this.addEventListener('focusin', this.noteFocus);
126
+ this.addEventListener('helix-press', this.handlePress);
127
+ this.addEventListener('keydown', this.handleKeydown);
128
+ this.watcher = new MutationObserver(() => this.sync());
129
+ this.watcher.observe(this, {
130
+ attributeFilter: ['disabled', 'value'],
131
+ childList: true,
132
+ subtree: true,
133
+ });
134
+ this.requestUpdate();
135
+ }
136
+ disconnectedCallback() {
137
+ super.disconnectedCallback();
138
+ this.removeEventListener('focusin', this.noteFocus);
139
+ this.removeEventListener('helix-press', this.handlePress);
140
+ this.removeEventListener('keydown', this.handleKeydown);
141
+ this.watcher?.disconnect();
14
142
  }
15
143
  willUpdate(changed) {
16
144
  super.willUpdate(changed);
17
- hostAria(this.internals, { label: this.label, role: 'group' });
145
+ const toolbar = this.selectionMode !== undefined && toolbarAround(this) === null;
146
+ hostAria(this.internals, { label: this.label, role: toolbar ? 'toolbar' : 'group' });
147
+ this.internals.ariaOrientation = toolbar ? (this.orientation ?? null) : null;
18
148
  }
19
149
  firstUpdated(changed) {
20
150
  super.firstUpdated(changed);
21
151
  auditName(this, () => null, 'Give it a `label`, or an `aria-label` that says what the buttons are for.', () => this.label !== '');
22
152
  }
153
+ updated(changed) {
154
+ super.updated(changed);
155
+ this.sync();
156
+ }
23
157
  render() {
24
158
  return html `<slot></slot>`;
25
159
  }
@@ -30,6 +164,12 @@ __decorate([
30
164
  __decorate([
31
165
  property({ reflect: true })
32
166
  ], HelixHeadlessButtonGroup.prototype, "orientation", void 0);
167
+ __decorate([
168
+ property({ attribute: 'selection-mode', reflect: true })
169
+ ], HelixHeadlessButtonGroup.prototype, "selectionMode", void 0);
170
+ __decorate([
171
+ property()
172
+ ], HelixHeadlessButtonGroup.prototype, "value", void 0);
33
173
  HelixHeadlessButtonGroup = __decorate([
34
174
  customElement('helix-headless-button-group')
35
175
  ], HelixHeadlessButtonGroup);
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Moving the view while something is carried to its edge: a card, a corner, a
3
+ * connection being drawn, or the box that selects.
4
+ *
5
+ * **A board is larger than its box, and a hand stops at the edge of the box.**
6
+ * Without this, carrying a card to a place off screen took a drop at the edge,
7
+ * a pan, and a second pick-up, and a connection to a card off screen could not
8
+ * be drawn by pointer at all.
9
+ */
10
+ /** A point on screen, in pixels. */
11
+ export interface EdgePoint {
12
+ x: number;
13
+ y: number;
14
+ }
15
+ /** The box the view is drawn in, on screen. */
16
+ export interface EdgeRect {
17
+ bottom: number;
18
+ left: number;
19
+ right: number;
20
+ top: number;
21
+ }
22
+ /** How near an edge, in pixels, the view starts to move. */
23
+ export declare const EDGE_ZONE = 32;
24
+ /** The most the view moves in one frame, in pixels: at the edge and past it. */
25
+ export declare const EDGE_MOST = 12;
26
+ /**
27
+ * How far the view should move toward each side in one frame, in pixels, for
28
+ * a pointer at `point`: positive toward the right and the bottom, nothing
29
+ * outside the zone, and faster the nearer the edge, up to `most` at it and
30
+ * past it.
31
+ *
32
+ * A box narrower than two zones moves only once the pointer is past its edge,
33
+ * so a small board is not always moving.
34
+ */
35
+ export declare const edgeSpeed: (point: EdgePoint, rect: EdgeRect, zone?: number, most?: number) => EdgePoint;
36
+ /**
37
+ * The frames that move the view while a pointer holds something near an edge.
38
+ *
39
+ * `follow` with every pointer move keeps it going while the pointer is in the
40
+ * zone, and `stop` ends it, which the board calls when the gesture ends and
41
+ * when it leaves the page. Each frame hands `step` how far to move, and the
42
+ * board moves the view and carries what is in hand with it.
43
+ */
44
+ export declare class EdgePan {
45
+ private readonly rect;
46
+ private readonly step;
47
+ private readonly ended;
48
+ /** The frame asked for, while the view is moving. */
49
+ private frame;
50
+ /** Where the pointer last was. */
51
+ private point;
52
+ constructor(rect: () => EdgeRect | undefined, step: (by: EdgePoint) => void, ended?: () => void);
53
+ /** Whether the view is moving. */
54
+ get moving(): boolean;
55
+ /** Where the pointer is now, which starts the frames where it is in the zone. */
56
+ follow(point: EdgePoint): void;
57
+ /** Ends the frames. */
58
+ stop(): void;
59
+ private speed;
60
+ private readonly tick;
61
+ }
@@ -0,0 +1,63 @@
1
+ export const EDGE_ZONE = 32;
2
+ export const EDGE_MOST = 12;
3
+ export const edgeSpeed = (point, rect, zone = EDGE_ZONE, most = EDGE_MOST) => {
4
+ const along = (at, start, end) => {
5
+ if (at >= end) {
6
+ return 1;
7
+ }
8
+ if (at <= start) {
9
+ return -1;
10
+ }
11
+ const reach = end - start < zone * 2 ? 0 : zone;
12
+ if (reach > 0 && at > end - reach) {
13
+ return (at - (end - reach)) / reach;
14
+ }
15
+ if (reach > 0 && at < start + reach) {
16
+ return -(start + reach - at) / reach;
17
+ }
18
+ return 0;
19
+ };
20
+ return {
21
+ x: Math.round(along(point.x, rect.left, rect.right) * most),
22
+ y: Math.round(along(point.y, rect.top, rect.bottom) * most),
23
+ };
24
+ };
25
+ export class EdgePan {
26
+ constructor(rect, step, ended = () => undefined) {
27
+ this.rect = rect;
28
+ this.step = step;
29
+ this.ended = ended;
30
+ this.tick = () => {
31
+ const by = this.speed();
32
+ if (by.x === 0 && by.y === 0) {
33
+ this.frame = undefined;
34
+ this.ended();
35
+ return;
36
+ }
37
+ this.step(by);
38
+ this.frame = requestAnimationFrame(this.tick);
39
+ };
40
+ }
41
+ get moving() {
42
+ return this.frame !== undefined;
43
+ }
44
+ follow(point) {
45
+ this.point = point;
46
+ const by = this.speed();
47
+ if (this.frame === undefined && (by.x !== 0 || by.y !== 0)) {
48
+ this.frame = requestAnimationFrame(this.tick);
49
+ }
50
+ }
51
+ stop() {
52
+ this.point = undefined;
53
+ if (this.frame !== undefined) {
54
+ cancelAnimationFrame(this.frame);
55
+ this.frame = undefined;
56
+ this.ended();
57
+ }
58
+ }
59
+ speed() {
60
+ const rect = this.rect();
61
+ return this.point && rect ? edgeSpeed(this.point, rect) : { x: 0, y: 0 };
62
+ }
63
+ }
@@ -150,6 +150,16 @@ export declare class HelixHeadlessCanvasNode extends HelixElement {
150
150
  * point and one to a circle on its curve without the board knowing which.
151
151
  */
152
152
  shape?: 'circle' | 'diamond' | 'pill' | 'square';
153
+ /**
154
+ * @internal What the card's state adds to what it says, in the page's words,
155
+ * written by the board: its `selected-label` while it is selected. Read
156
+ * first, before what the tone means.
157
+ *
158
+ * **A selection a reader cannot see has to be said.** A card is an article,
159
+ * and an article has no selected state for `aria-selected` to carry, so a
160
+ * reader who selected three cards heard nothing on any of them.
161
+ */
162
+ status: string;
153
163
  /**
154
164
  * @internal Whether this is the card the reader selected, written by the
155
165
  * board. Kept apart from focus, so a reader who clicks a button beside the
@@ -211,8 +221,8 @@ export declare class HelixHeadlessCanvasNode extends HelixElement {
211
221
  */
212
222
  focus(options?: FocusOptions): void;
213
223
  /**
214
- * The card, and the sentence that says what its tone means and where it
215
- * leads.
224
+ * The card, and the sentence that says whether it is selected, what its
225
+ * tone means and where it leads.
216
226
  *
217
227
  * **`aria-describedby` at a hidden element, which is allowed and is the
218
228
  * point.** A description is computed from its target whether or not the
@@ -33,6 +33,7 @@ let HelixHeadlessCanvasNode = class HelixHeadlessCanvasNode extends HelixElement
33
33
  this.links = '';
34
34
  this.meaning = '';
35
35
  this.readOnly = false;
36
+ this.status = '';
36
37
  this.selected = false;
37
38
  this.movable = false;
38
39
  this.resizable = false;
@@ -72,7 +73,7 @@ let HelixHeadlessCanvasNode = class HelixHeadlessCanvasNode extends HelixElement
72
73
  </svg>`
73
74
  : nothing}<div
74
75
  part="node"
75
- aria-describedby=${this.meaning || this.links ? 'about' : nothing}
76
+ aria-describedby=${this.status || this.meaning || this.links ? 'about' : nothing}
76
77
  aria-label=${this.label || nothing}
77
78
  aria-labelledby=${this.label || this.group ? nothing : 'content'}
78
79
  aria-keyshortcuts=${this.connectable ? 'Enter F2 Space Shift+ArrowRight Shift+ArrowDown Alt+ArrowRight Alt+ArrowDown C Delete' : nothing}
@@ -81,7 +82,7 @@ let HelixHeadlessCanvasNode = class HelixHeadlessCanvasNode extends HelixElement
81
82
  >
82
83
  <slot id="content"></slot>
83
84
  <slot name="description"></slot>
84
- <span id="about" hidden>${[this.meaning, this.links].filter(Boolean).join(', ')}</span>
85
+ <span id="about" hidden>${[this.status, this.meaning, this.links].filter(Boolean).join(', ')}</span>
85
86
  </div>
86
87
  ${this.connectable
87
88
  ? html `<span part="handle handle-top" aria-hidden="true" data-side="top"></span>
@@ -131,6 +132,9 @@ __decorate([
131
132
  __decorate([
132
133
  property({ reflect: true })
133
134
  ], HelixHeadlessCanvasNode.prototype, "shape", void 0);
135
+ __decorate([
136
+ state()
137
+ ], HelixHeadlessCanvasNode.prototype, "status", void 0);
134
138
  __decorate([
135
139
  state()
136
140
  ], HelixHeadlessCanvasNode.prototype, "selected", void 0);
@@ -127,6 +127,16 @@ export declare const ends: (edge: CanvasEdge, from: CanvasNode, to: CanvasNode)
127
127
  fromSide: CanvasSide;
128
128
  toSide: CanvasSide;
129
129
  };
130
+ /**
131
+ * How far a point is from a card's box, in the document's units: nothing
132
+ * inside it, and the shortest way to its edge outside.
133
+ */
134
+ export declare const distanceTo: (node: {
135
+ x: number;
136
+ y: number;
137
+ width: number;
138
+ height: number;
139
+ }, point: Point) => number;
130
140
  /**
131
141
  * The side of a card nearest a point, which is where a connection a reader is
132
142
  * holding arrives.
@@ -175,6 +175,7 @@ export const ends = (edge, from, to) => {
175
175
  const toSide = edge.toSide ?? fallbackTo;
176
176
  return { end: port(to, toSide), fromSide, start: port(from, fromSide), toSide };
177
177
  };
178
+ export const distanceTo = (node, point) => Math.hypot(Math.max(node.x - point.x, 0, point.x - (node.x + node.width)), Math.max(node.y - point.y, 0, point.y - (node.y + node.height)));
178
179
  export const sideNear = (node, point) => ['top', 'right', 'bottom', 'left']
179
180
  .map((side) => {
180
181
  const at = port(node, side);
@@ -34,20 +34,34 @@ declare const HelixHeadlessCanvas_base: (new (...args: any[]) => import("@fusion
34
34
  * keep every card in place, such as on a published board. Set `readonly` on one
35
35
  * card or connection to keep only that one in place.
36
36
  *
37
+ * Set `snap` to a length in the document's units, such as `32`, and a card
38
+ * that is moved or resized lands on a multiple of it. Carrying a card, a
39
+ * corner, a connection, or the selection box near the edge of the board moves
40
+ * the board under it, so a card can be taken to a place off screen in one
41
+ * drag. A connection let go within 20 pixels of a card arrives at it. A
42
+ * double click on the empty board zooms in about that point, and Shift with a
43
+ * double click zooms out.
44
+ *
37
45
  * Keyboard behavior:
38
46
  * - One card holds the board's tab stop.
39
47
  * - The arrow keys move through the cards in reading order. The card you land
40
48
  * on scrolls into view, and its connections are announced with it.
41
- * - Shift with an arrow key moves the card.
49
+ * - Shift with an arrow key moves the card: by 16 units, or to the next
50
+ * multiple of `snap` where it is set. Alt with an arrow key resizes it from
51
+ * its bottom right corner the same way.
42
52
  * - The connections leaving a card are stops of their own, straight after it.
43
53
  * Enter on one moves to the card it arrives at.
54
+ * - What a key changes that a reader cannot see is said: where a card moved
55
+ * to, its new size, how many cards are selected, and the zoom. A selected
56
+ * card or connection says so when a reader arrives on it.
44
57
  *
45
58
  * Every drag also works with clicks, as WCAG 2.5.7 requires for a pointer that
46
59
  * cannot hold a button down. Click a selected card's move handle, a corner, a
47
60
  * card's connection point, or the end of a selected connection to pick it up.
48
61
  * It follows the pointer with no button held, and the next click puts it down
49
62
  * where a drag would have. On touch, the next tap sets where it lands. Escape,
50
- * or a press outside the board, puts it back.
63
+ * or a press outside the board, puts it back. So a finger connects two cards
64
+ * with three taps: the card, one of its points, and the card to connect to.
51
65
  *
52
66
  * Connecting and removing dispatch requests, and your code applies them:
53
67
  * - Drawing from a card's handle to another card, or pressing C on one card and
@@ -75,7 +89,14 @@ declare const HelixHeadlessCanvas_base: (new (...args: any[]) => import("@fusion
75
89
  * @slot - The board's `helix-canvas-node` and `helix-canvas-edge` elements, drawn on the plane.
76
90
  * @slot empty - Content shown when the document has no nodes.
77
91
  * @slot footer - Content below the board.
92
+ * @slot fullscreen-icon - Replaces the glyph inside the fullscreen button.
78
93
  * @slot header - Content above the board.
94
+ * @slot pan-down-icon - Replaces the glyph inside the pan down button.
95
+ * @slot pan-end-icon - Replaces the glyph inside the button that pans toward the end of a line of text.
96
+ * @slot pan-start-icon - Replaces the glyph inside the button that pans toward the start of a line of text.
97
+ * @slot pan-up-icon - Replaces the glyph inside the pan up button.
98
+ * @slot zoom-in-icon - Replaces the glyph inside the zoom-in button.
99
+ * @slot zoom-out-icon - Replaces the glyph inside the zoom-out button.
79
100
  *
80
101
  * @event {HelixBeforeMoveEvent} helix-before-move - Cards are about to move. Cancelable: cancel it to keep the positions in your own state.
81
102
  * @event {HelixBeforeReconnectEvent} helix-before-reconnect - A connection's end is about to move to another card or side. Cancelable: cancel it to keep connections in your own state.
@@ -171,6 +192,15 @@ export declare class HelixHeadlessCanvas extends HelixHeadlessCanvas_base {
171
192
  * Third", rather than with a comma this component chose.
172
193
  */
173
194
  leadsToLabel: string;
195
+ /**
196
+ * What screen readers hear after a key moves a card, with `{name}` for the
197
+ * card and `{x}` and `{y}` for where it now is, in the document's units.
198
+ *
199
+ * **A move a reader cannot see has to be said.** Shift with an arrow moved
200
+ * the card and said nothing, so a reader moving one by keys could not tell
201
+ * whether it had moved, or how far.
202
+ */
203
+ movedLabel: string;
174
204
  /**
175
205
  * The order the arrow keys and screen readers move through the cards:
176
206
  * `spatial` or `edges`.
@@ -208,6 +238,12 @@ export declare class HelixHeadlessCanvas extends HelixHeadlessCanvas_base {
208
238
  * `{to}`.
209
239
  */
210
240
  reconnectingLabel: string;
241
+ /**
242
+ * What screen readers hear after a key resizes a card, with `{name}` for the
243
+ * card and `{width}` and `{height}` for its new size, in the document's
244
+ * units.
245
+ */
246
+ resizedLabel: string;
211
247
  /**
212
248
  * The names of the selected cards and connections, comma separated. Empty
213
249
  * when nothing is selected.
@@ -230,6 +266,35 @@ export declare class HelixHeadlessCanvas extends HelixHeadlessCanvas_base {
230
266
  * Written to select from outside, and read to act on the selection.
231
267
  */
232
268
  selected: string;
269
+ /**
270
+ * What a selected card or connection adds to what screen readers hear on
271
+ * it, before its tone and its connections. Empty adds nothing.
272
+ *
273
+ * A card is an article and a connection a button, and neither has a selected
274
+ * state for `aria-selected` to carry, so the state is said in words.
275
+ */
276
+ selectedLabel: string;
277
+ /**
278
+ * What screen readers hear after the selection grows or shrinks, with
279
+ * `{count}` for how many cards and connections are selected: by Space, a
280
+ * click with Shift, Command or Control, Command or Control with A, a box
281
+ * drawn across the board, or Escape.
282
+ *
283
+ * A selection of one made by arriving on a card or clicking it is not said,
284
+ * since the card is.
285
+ */
286
+ selectionLabel: string;
287
+ /**
288
+ * Snaps the cards a reader moves or resizes to a multiple of this many of the
289
+ * document's units, such as `32` to land on the lines `grid` draws.
290
+ *
291
+ * **A drag lets go on the nearest line and a key goes to the next one.**
292
+ * Shift with an arrow moves a card to the next line that way, rather than
293
+ * by its step of 16, and Alt with an arrow moves its bottom right corner
294
+ * the same way. A group moves with what it carries, so a card inside one
295
+ * keeps its place in it. Absent, cards land where they are let go.
296
+ */
297
+ snap?: number;
233
298
  /**
234
299
  * A label being edited in place: whose, and what it said before.
235
300
  */
@@ -247,6 +312,11 @@ export declare class HelixHeadlessCanvas extends HelixHeadlessCanvas_base {
247
312
  * told the same. A tone left out is not read.
248
313
  */
249
314
  toneLabels: Partial<Record<CanvasTone, string>>;
315
+ /**
316
+ * What screen readers hear after a zoom button or key, with `{zoom}` for the
317
+ * zoom as a percentage, written the way the page's language writes one.
318
+ */
319
+ zoomedLabel: string;
250
320
  /** The card or connection that holds the board's one tab stop, by its key. */
251
321
  private stop;
252
322
  /**
@@ -254,8 +324,20 @@ export declare class HelixHeadlessCanvas extends HelixHeadlessCanvas_base {
254
324
  * started it, and where the pointer is, in the document's own units.
255
325
  */
256
326
  private linking;
257
- /** What the live region says, which is only ever about a connection being made. */
327
+ /**
328
+ * What the live region says: a connection being made, and what a key did
329
+ * that a reader cannot see, a move, a resize, the selection, the zoom.
330
+ */
258
331
  private said;
332
+ /**
333
+ * Says something in the live region.
334
+ *
335
+ * The same words twice would change nothing in the region and be heard
336
+ * once, so a second "2 selected" differs by a space no reader says.
337
+ */
338
+ private say;
339
+ /** Numbers as the page's language writes them. */
340
+ private get numbers();
259
341
  /**
260
342
  * Where focus goes once something a reader removed has gone.
261
343
  *
@@ -469,7 +551,8 @@ export declare class HelixHeadlessCanvas extends HelixHeadlessCanvas_base {
469
551
  private toDocument;
470
552
  /**
471
553
  * The card under a point, the smallest where they overlap, so a card inside
472
- * a group is found before the group around it.
554
+ * a group is found before the group around it. Where none is, the nearest
555
+ * within `reach`, in the document's units.
473
556
  */
474
557
  private cardAt;
475
558
  /** What a card is called, by id, for what the live region says. */
@@ -631,6 +714,22 @@ export declare class HelixHeadlessCanvas extends HelixHeadlessCanvas_base {
631
714
  * Returns whether it applied, so a caller knows whether to report a finish.
632
715
  */
633
716
  private requestMove;
717
+ /**
718
+ * Moves the view while a pointer carries something near its edge, and
719
+ * carries it along: a card, a corner, a connection being drawn, the box that
720
+ * selects.
721
+ */
722
+ private readonly edgePan;
723
+ /** The last pointer move of a carry, which a frame of `edgePan` moves on from. */
724
+ private carryPointer;
725
+ /**
726
+ * One frame of moving the view under something carried to its edge: the
727
+ * board moves by `by` and what is in hand stays under the pointer, so a card
728
+ * goes on moving over the board while the hand is still.
729
+ */
730
+ private panCarrying;
731
+ /** Follows a pointer carrying something, which moves the view at an edge. */
732
+ private carryOn;
634
733
  /**
635
734
  * Drag to move the board, which is the gesture a canvas is reached for with.
636
735
  *
@@ -767,7 +866,10 @@ export declare class HelixHeadlessCanvas extends HelixHeadlessCanvas_base {
767
866
  * board draws; a card's content by asking, which the board does not.
768
867
  */
769
868
  private editStop;
770
- /** A double-click on a card or a connection edits it, the pointer's F2. */
869
+ /**
870
+ * A double-click on a card or a connection edits it, the pointer's F2, and
871
+ * one on the empty board zooms in about where it landed.
872
+ */
771
873
  private readonly handleDoubleClick;
772
874
  /**
773
875
  * Finishes editing a label: asks, writes it where the page did not refuse,