@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
@@ -4,12 +4,16 @@ 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 { capturePointer, customElement, fillTemplate, HelixBeforeMoveEvent, HelixBeforeReconnectEvent, HelixBeforeRelabelEvent, HelixCanvasEditEvent, HelixCanvasPanEvent, HelixCanvasViewEvent, HelixCanvasZoomEvent, HelixConnectEvent, HelixElement, HelixMoveEvent, HelixReconnectEvent, HelixRelabelEvent, HelixRemoveEvent, HelixSelectEvent, hostAria, inlineStep, isRtl, MixinViewport, wordsConverter, } from '@fusion.dev/helix-core';
7
+ import { assignSlots, capturePointer, customElement, formatPercent, formatWords, HelixBeforeMoveEvent, HelixBeforeReconnectEvent, HelixBeforeRelabelEvent, HelixCanvasEditEvent, HelixCanvasPanEvent, HelixCanvasViewEvent, HelixCanvasZoomEvent, HelixConnectEvent, HelixElement, HelixMoveEvent, HelixReconnectEvent, HelixRelabelEvent, HelixRemoveEvent, HelixSelectEvent, hostAria, inlineStep, isRtl, MixinViewport, words, wordsConverter, wordsLocale, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing, svg } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
+ import { descriptionOf } from '../describe.js';
10
11
  import { HelixHeadlessCanvasEdge } from '../edge/canvas-edge.js';
12
+ import { EdgePan } from '../edge-pan.js';
13
+ import { neighborOf } from '../neighbor.js';
11
14
  import { HelixHeadlessCanvasNode } from '../node/canvas-node.js';
12
- import { colorOf, connector, ends, extent, inside, port, reading, sideNear, } from './canvas-document.js';
15
+ import { snapBox, snapTo, stepTo } from '../snap.js';
16
+ import { colorOf, connector, distanceTo, ends, extent, inside, port, reading, sideNear, } from './canvas-document.js';
13
17
  export { fromJsonCanvas } from './canvas-document.js';
14
18
  const MARGIN = 32;
15
19
  const ARROW = 'canvas-arrow';
@@ -20,6 +24,7 @@ const ZOOM_MIN = 0.1;
20
24
  const ZOOM_MAX = 8;
21
25
  const ruling = (zoom) => zoom >= 0.5 ? zoom : zoom * 2 ** Math.ceil(Math.log2(0.5 / zoom));
22
26
  const SLOP = 3;
27
+ const REACH = 20;
23
28
  const heads = (edge) => ({
24
29
  end: (edge.toEnd ?? 'arrow') === 'arrow',
25
30
  start: edge.fromEnd === 'arrow',
@@ -37,19 +42,32 @@ const size = (value) => (value > 0 ? `${value}px` : undefined);
37
42
  let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixElement) {
38
43
  constructor() {
39
44
  super(...arguments);
45
+ this.activateHintLabel = 'Press the board to use it';
40
46
  this.comesFromLabel = 'from {cards}';
41
47
  this.connectedLabel = 'Asked to connect {from} to {to}.';
42
48
  this.connectingLabel = 'Connecting from {from}. Move to another card and press Enter, or Escape to stop.';
43
49
  this.connectionLabel = 'From {from} to {to}';
50
+ this.controlsLabel = 'Board controls';
51
+ this.fallbackLabel = 'Canvas';
44
52
  this.label = '';
45
53
  this.labelEditorLabel = 'Label for {name}';
46
54
  this.leadsToLabel = 'leads to {cards}';
55
+ this.linkedLabel = '{leadsTo}; {comesFrom}';
56
+ this.movedLabel = '{name} moved to {x}, {y}';
47
57
  this.readOnly = false;
48
58
  this.reconnectingLabel = 'Moving the end of the connection from {from} to {to}. Move to a card and press Enter, or Escape to stop.';
59
+ this.resizedLabel = '{name} resized to {width} by {height}';
49
60
  this.selected = '';
61
+ this.selectedLabel = 'selected';
62
+ this.selectionLabel = '{count} selected';
50
63
  this.stoppedLabel = 'Stopped connecting.';
51
64
  this.toneLabels = {};
65
+ this.twoFingerHintLabel = 'Use two fingers to move the board';
66
+ this.usingLabel = 'Using the board. Press Escape to scroll the page again.';
67
+ this.wheelHintLabel = 'Use {key} and scroll to zoom the board';
68
+ this.zoomedLabel = 'Zoom {zoom}';
52
69
  this.said = '';
70
+ this.walked = [];
53
71
  this.at = { x: 0, y: 0, zoom: 1 };
54
72
  this.direct = false;
55
73
  this.touched = false;
@@ -62,6 +80,11 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
62
80
  this.fingers = new Map();
63
81
  this.keying = undefined;
64
82
  this.edgeKeys = new WeakMap();
83
+ this.edgePan = new EdgePan(() => this.partNamed('viewport')?.getBoundingClientRect(), (by) => this.panCarrying(by), () => {
84
+ if (!this.dragging) {
85
+ this.direct = false;
86
+ }
87
+ });
65
88
  this.handlePointerDown = (event) => {
66
89
  if (!this.gestureAllowed(event)) {
67
90
  return;
@@ -212,17 +235,19 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
212
235
  }
213
236
  const sizing = this.sizing;
214
237
  if (sizing && (sizing.held || sizing.pointer === event.pointerId)) {
215
- const box = this.resized(sizing.start, sizing.corner, (event.clientX - sizing.from.x) / this.at.zoom, (event.clientY - sizing.from.y) / this.at.zoom);
238
+ const box = snapBox(this.resized(sizing.start, sizing.corner, (event.clientX - sizing.from.x) / this.at.zoom, (event.clientY - sizing.from.y) / this.at.zoom), sizing.start, sizing.corner, this.snap, { height: MIN_HEIGHT, width: MIN_WIDTH });
216
239
  const detail = { nodes: [{ name: sizing.card.name, ...box }] };
217
240
  this.touched = true;
218
241
  sizing.asked = true;
219
242
  if (this.requestMove(detail)) {
220
243
  sizing.moved = detail;
221
244
  }
245
+ this.carryOn(event);
222
246
  return;
223
247
  }
224
248
  if (this.marquee?.pointer === event.pointerId) {
225
249
  this.marquee = { ...this.marquee, to: this.toDocument(event) };
250
+ this.carryOn(event);
226
251
  return;
227
252
  }
228
253
  if (this.linking && (this.linking.held || this.linking.pointer === event.pointerId)) {
@@ -234,7 +259,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
234
259
  capturePointer(this, event.pointerId);
235
260
  }
236
261
  const at = this.toDocument(event);
237
- const over = this.cardAt(at);
262
+ const over = this.cardAt(at, REACH / this.at.zoom);
238
263
  const to = this.arrival(over?.id);
239
264
  this.linking = {
240
265
  ...this.linking,
@@ -244,6 +269,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
244
269
  to,
245
270
  toSide: to !== undefined && over ? sideNear(over, at) : undefined,
246
271
  };
272
+ this.carryOn(event);
247
273
  return;
248
274
  }
249
275
  const carry = this.carrying;
@@ -258,17 +284,22 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
258
284
  }
259
285
  carry.started = true;
260
286
  this.touched = true;
287
+ const lead = carry.cards.find(({ card }) => card.name === carry.pressed) ?? carry.cards[0];
288
+ const shift = (from, by) => from === undefined ? by : snapTo(from + by, this.snap) - from;
289
+ const right = shift(lead?.x, across / this.at.zoom);
290
+ const lower = shift(lead?.y, down / this.at.zoom);
261
291
  const detail = {
262
292
  nodes: carry.cards.map(({ card, x, y }) => ({
263
293
  name: card.name,
264
- x: Math.round(x + across / this.at.zoom),
265
- y: Math.round(y + down / this.at.zoom),
294
+ x: Math.round(x + right),
295
+ y: Math.round(y + lower),
266
296
  })),
267
297
  };
268
298
  carry.asked = true;
269
299
  if (this.requestMove(detail)) {
270
300
  carry.moved = detail;
271
301
  }
302
+ this.carryOn(event);
272
303
  return;
273
304
  }
274
305
  const drag = this.dragging;
@@ -303,6 +334,8 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
303
334
  if (finger && !owner && this.fingers.size > 0) {
304
335
  return;
305
336
  }
337
+ this.edgePan.stop();
338
+ this.carryPointer = undefined;
306
339
  this.pressing = false;
307
340
  const pointing = this.pointing;
308
341
  this.pointing = false;
@@ -322,7 +355,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
322
355
  if (marquee?.pointer === event.pointerId) {
323
356
  this.marquee = undefined;
324
357
  if (event.type !== 'pointercancel') {
325
- this.choose([...marquee.base, ...this.within(marquee)]);
358
+ this.choose([...marquee.base, ...this.within(marquee)], true);
326
359
  }
327
360
  return;
328
361
  }
@@ -433,15 +466,23 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
433
466
  if (this.fixed(card)) {
434
467
  return;
435
468
  }
469
+ const step = this.snap;
470
+ const right = step ? stepTo(card.x, along, step) - card.x : along * NUDGE;
471
+ const lower = step ? stepTo(card.y, down, step) - card.y : down * NUDGE;
436
472
  const detail = {
437
473
  nodes: this.carriedAll(card).map((one) => ({
438
474
  name: one.name,
439
- x: one.x + along * NUDGE,
440
- y: one.y + down * NUDGE,
475
+ x: one.x + right,
476
+ y: one.y + lower,
441
477
  })),
442
478
  };
443
479
  if (this.requestMove(detail)) {
444
480
  this.dispatchEvent(new HelixMoveEvent(detail));
481
+ this.say(formatWords(this, 'movedLabel', {
482
+ name: this.nameOf(card.name),
483
+ x: card.x,
484
+ y: card.y,
485
+ }));
445
486
  }
446
487
  void this.updateComplete.then(() => this.reveal(card.name));
447
488
  return;
@@ -451,10 +492,17 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
451
492
  if (this.fixed(card)) {
452
493
  return;
453
494
  }
454
- const box = this.resized({ height: card.height, width: card.width, x: card.x, y: card.y }, 'bottom-right', along * NUDGE, down * NUDGE);
495
+ const step = this.snap;
496
+ const edge = { x: card.x + card.width, y: card.y + card.height };
497
+ const box = this.resized({ height: card.height, width: card.width, x: card.x, y: card.y }, 'bottom-right', step ? stepTo(edge.x, along, step) - edge.x : along * NUDGE, step ? stepTo(edge.y, down, step) - edge.y : down * NUDGE);
455
498
  const detail = { nodes: [{ name: card.name, ...box }] };
456
499
  if (this.requestMove(detail)) {
457
500
  this.dispatchEvent(new HelixMoveEvent(detail));
501
+ this.say(formatWords(this, 'resizedLabel', {
502
+ height: box.height,
503
+ name: this.nameOf(card.name),
504
+ width: box.width,
505
+ }));
458
506
  }
459
507
  return;
460
508
  }
@@ -465,7 +513,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
465
513
  }
466
514
  if ((event.metaKey || event.ctrlKey) && (event.key === 'a' || event.key === 'A')) {
467
515
  event.preventDefault();
468
- this.choose(this.walk.map((one) => one.key));
516
+ this.choose(this.walk.map((one) => one.key), true);
469
517
  return;
470
518
  }
471
519
  if (event.key === 'Escape') {
@@ -477,7 +525,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
477
525
  this.focusStop(back);
478
526
  return;
479
527
  }
480
- this.choose(undefined);
528
+ this.choose(undefined, true);
481
529
  this.partNamed('region')?.focus();
482
530
  return;
483
531
  }
@@ -553,6 +601,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
553
601
  return;
554
602
  }
555
603
  this.refocus = undefined;
604
+ this.focusedCard = card;
556
605
  this.stop = edge ?? card?.name;
557
606
  if (!this.pointing && this.stop !== undefined && !this.picked.includes(this.stop)) {
558
607
  this.choose(this.stop);
@@ -568,6 +617,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
568
617
  };
569
618
  this.handleFocusOut = (event) => {
570
619
  const next = event.relatedTarget;
620
+ this.forget(this.cardOf(event), next);
571
621
  const linking = this.linking;
572
622
  if (!linking ||
573
623
  linking.pointer !== undefined ||
@@ -593,7 +643,28 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
593
643
  if (key !== undefined) {
594
644
  event.preventDefault();
595
645
  this.editStop(key);
646
+ return;
647
+ }
648
+ const viewport = this.partNamed('viewport');
649
+ if (!viewport || !this.gestureAllowed(event)) {
650
+ return;
651
+ }
652
+ const box = viewport.getBoundingClientRect();
653
+ const inside = event.clientX >= box.left &&
654
+ event.clientX <= box.right &&
655
+ event.clientY >= box.top &&
656
+ event.clientY <= box.bottom;
657
+ const onControls = path.some((one) => one instanceof Element && (one.getAttribute('part') ?? '').split(' ').includes('controls'));
658
+ if (!inside || onControls) {
659
+ return;
596
660
  }
661
+ event.preventDefault();
662
+ this.touched = true;
663
+ this.direct = false;
664
+ this.zoomAbout(event.shiftKey ? 1 / 2 : 2, {
665
+ x: event.clientX - box.left,
666
+ y: event.clientY - box.top,
667
+ });
597
668
  };
598
669
  this.handleEditorKeydown = (event) => {
599
670
  event.stopPropagation();
@@ -610,10 +681,14 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
610
681
  this.requestUpdate();
611
682
  };
612
683
  }
684
+ static { this.words = 'helix-canvas'; }
613
685
  static { this.shadowRootOptions = {
614
686
  ...HelixElement.shadowRootOptions,
615
687
  slotAssignment: 'manual',
616
688
  }; }
689
+ say(words) {
690
+ this.said = words !== '' && words === this.said ? `${words}\u00a0` : words;
691
+ }
617
692
  get box() {
618
693
  const viewport = this.renderRoot?.querySelector('[part="viewport"]');
619
694
  return {
@@ -719,17 +794,6 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
719
794
  zoomEvent(detail) {
720
795
  return new HelixCanvasZoomEvent(detail);
721
796
  }
722
- get restingControlsLabel() {
723
- return 'Board controls';
724
- }
725
- get restingGestureLabels() {
726
- return {
727
- activate: 'Press the board to use it',
728
- twoFinger: 'Use two fingers to move the board',
729
- using: 'Using the board. Press Escape to scroll the page again.',
730
- wheel: 'Use {key} and scroll to zoom the board',
731
- };
732
- }
733
797
  get restingControls() {
734
798
  return 'zoom fullscreen';
735
799
  }
@@ -752,6 +816,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
752
816
  this.direct = false;
753
817
  this.touched = true;
754
818
  this.zoomAbout(by > 0 ? 1.25 : 1 / 1.25, { x: this.box.width / 2, y: this.box.height / 2 });
819
+ this.say(formatWords(this, 'zoomedLabel', { zoom: formatPercent(this.at.zoom, wordsLocale(this)) }));
755
820
  super.zoom(by);
756
821
  }
757
822
  show(name) {
@@ -815,13 +880,20 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
815
880
  y: origin.y + (event.clientY - (box?.top ?? 0) - this.at.y) / this.at.zoom,
816
881
  };
817
882
  }
818
- cardAt(point) {
819
- return this.nodes
883
+ cardAt(point, reach = 0) {
884
+ const under = this.nodes
820
885
  .filter((one) => point.x >= one.x &&
821
886
  point.x <= one.x + one.width &&
822
887
  point.y >= one.y &&
823
888
  point.y <= one.y + one.height)
824
889
  .sort((a, b) => a.width * a.height - b.width * b.height)[0];
890
+ if (under || reach <= 0) {
891
+ return under;
892
+ }
893
+ return this.nodes
894
+ .map((one) => ({ away: distanceTo(one, point), one }))
895
+ .filter(({ away }) => away <= reach)
896
+ .sort((a, b) => a.away - b.away)[0]?.one;
825
897
  }
826
898
  nameOf(id) {
827
899
  const node = this.byId.get(id);
@@ -829,7 +901,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
829
901
  }
830
902
  startLinking(from) {
831
903
  this.linking = { from };
832
- this.said = fillTemplate(this.connectingLabel, { from: this.nameOf(from) });
904
+ this.said = formatWords(this, 'connectingLabel', { from: this.nameOf(from) });
833
905
  }
834
906
  arrival(name) {
835
907
  const card = this.cardNamed(name);
@@ -850,7 +922,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
850
922
  this.said = linking ? this.stoppedLabel : '';
851
923
  return;
852
924
  }
853
- this.said = fillTemplate(this.connectedLabel, {
925
+ this.said = formatWords(this, 'connectedLabel', {
854
926
  from: this.nameOf(linking.from),
855
927
  to: this.nameOf(arriving),
856
928
  });
@@ -880,7 +952,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
880
952
  };
881
953
  this.said = pointer
882
954
  ? ''
883
- : fillTemplate(this.reconnectingLabel, {
955
+ : formatWords(this, 'reconnectingLabel', {
884
956
  from: this.nameOf(edge.fromNode),
885
957
  to: this.nameOf(edge.toNode),
886
958
  });
@@ -930,7 +1002,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
930
1002
  this.rekey(linking.edge, this.keyOfElement(element));
931
1003
  }
932
1004
  if (linking.pointer === undefined) {
933
- this.said = fillTemplate(this.connectedLabel, {
1005
+ this.said = formatWords(this, 'connectedLabel', {
934
1006
  from: this.nameOf(detail.from),
935
1007
  to: this.nameOf(detail.to),
936
1008
  });
@@ -966,12 +1038,8 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
966
1038
  };
967
1039
  const gone = new Set([...asked, ...leaving.map((edge) => this.keyOf(edge))]);
968
1040
  const at = Math.min(...asked.map((one) => walk.findIndex((stop) => stop.key === one)));
969
- const next = walk.slice(at + 1).find((one) => !gone.has(one.key)) ??
970
- walk
971
- .slice(0, Math.max(at, 0))
972
- .reverse()
973
- .find((one) => !gone.has(one.key));
974
- this.refocus = { gone: [...gone], next: next?.key };
1041
+ const next = neighborOf(walk.map((one) => one.key), at, (key) => !gone.has(key));
1042
+ this.refocus = { gone: [...gone], next };
975
1043
  this.dispatchEvent(new HelixRemoveEvent(detail));
976
1044
  }
977
1045
  clicked(key, event) {
@@ -1099,7 +1167,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1099
1167
  .map((one) => this.keyNamed(one.trim()))
1100
1168
  .filter((one) => one !== undefined));
1101
1169
  }
1102
- choose(keys) {
1170
+ choose(keys, said = false) {
1103
1171
  const list = keys === undefined ? [] : typeof keys === 'string' ? [keys] : [...new Set(keys)];
1104
1172
  const value = list.map((one) => this.publicName(one)).join(',');
1105
1173
  if (value === this.selected) {
@@ -1107,11 +1175,14 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1107
1175
  }
1108
1176
  if (this.dispatchEvent(new HelixSelectEvent({ value }))) {
1109
1177
  this.selected = value;
1178
+ if (said) {
1179
+ this.say(formatWords(this, 'selectionLabel', { count: list.length }));
1180
+ }
1110
1181
  }
1111
1182
  }
1112
1183
  toggle(key) {
1113
1184
  const picked = this.picked;
1114
- this.choose(picked.includes(key) ? picked.filter((one) => one !== key) : [...picked, key]);
1185
+ this.choose(picked.includes(key) ? picked.filter((one) => one !== key) : [...picked, key], true);
1115
1186
  }
1116
1187
  get pickedCards() {
1117
1188
  const picked = new Set(this.picked);
@@ -1138,6 +1209,26 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1138
1209
  this.requestUpdate();
1139
1210
  return true;
1140
1211
  }
1212
+ panCarrying(by) {
1213
+ const last = this.carryPointer;
1214
+ if (!last) {
1215
+ this.edgePan.stop();
1216
+ return;
1217
+ }
1218
+ this.touched = true;
1219
+ this.direct = true;
1220
+ this.at = { ...this.at, x: this.at.x - by.x, y: this.at.y - by.y };
1221
+ for (const gesture of [this.carrying, this.sizing]) {
1222
+ if (gesture) {
1223
+ gesture.from = { x: gesture.from.x - by.x, y: gesture.from.y - by.y };
1224
+ }
1225
+ }
1226
+ this.handlePointerMove(last);
1227
+ }
1228
+ carryOn(event) {
1229
+ this.carryPointer = event;
1230
+ this.edgePan.follow({ x: event.clientX, y: event.clientY });
1231
+ }
1141
1232
  picksUp(gesture, event, from) {
1142
1233
  if (gesture.held || this.putting || event.type === 'pointercancel') {
1143
1234
  return false;
@@ -1200,11 +1291,46 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1200
1291
  this.letGo();
1201
1292
  }
1202
1293
  letGo() {
1294
+ this.edgePan.stop();
1295
+ this.carryPointer = undefined;
1203
1296
  this.holding = false;
1204
1297
  this.toggleState('holding', false);
1205
1298
  document.removeEventListener('keydown', this.handleHeldKey, true);
1206
1299
  document.removeEventListener('pointerdown', this.handleHeldOutside, true);
1207
1300
  }
1301
+ forget(card, to) {
1302
+ if (!card || card !== this.focusedCard) {
1303
+ return;
1304
+ }
1305
+ if (to) {
1306
+ this.focusedCard = undefined;
1307
+ return;
1308
+ }
1309
+ queueMicrotask(() => {
1310
+ if (card.isConnected && this.focusedCard === card) {
1311
+ this.focusedCard = undefined;
1312
+ }
1313
+ });
1314
+ }
1315
+ handOn() {
1316
+ const gone = this.focusedCard;
1317
+ if (!gone || this.cards.includes(gone)) {
1318
+ return;
1319
+ }
1320
+ this.focusedCard = undefined;
1321
+ const active = this.ownerDocument.activeElement;
1322
+ if (active !== null && active !== this.ownerDocument.body) {
1323
+ return;
1324
+ }
1325
+ const keys = new Set(this.walk.map((one) => one.key));
1326
+ const next = neighborOf(this.walked.map((one) => one.key), this.walked.findIndex((one) => one.key === gone.name), (key) => keys.has(key));
1327
+ if (next === undefined) {
1328
+ this.partNamed('region')?.focus();
1329
+ }
1330
+ else {
1331
+ this.focusStop(next);
1332
+ }
1333
+ }
1208
1334
  reveal(id) {
1209
1335
  const node = this.byId.get(id);
1210
1336
  const origin = this.origin;
@@ -1289,7 +1415,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1289
1415
  const drawn = edge ? this.geometryOf(edge, origin) : undefined;
1290
1416
  if (drawn) {
1291
1417
  at = drawn.mid;
1292
- named = fillTemplate(this.connectionLabel, {
1418
+ named = formatWords(this, 'connectionLabel', {
1293
1419
  from: this.textOf(drawn.from),
1294
1420
  to: this.textOf(drawn.to),
1295
1421
  });
@@ -1307,7 +1433,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1307
1433
  }
1308
1434
  return html `<input
1309
1435
  part="label-editor"
1310
- aria-label=${fillTemplate(this.labelEditorLabel, { name: named })}
1436
+ aria-label=${formatWords(this, 'labelEditorLabel', { name: named })}
1311
1437
  data-target=${editing.target}
1312
1438
  style=${`--_canvas-editor-x: ${at.x}px; --_canvas-editor-y: ${at.y}px`}
1313
1439
  type="text"
@@ -1394,19 +1520,17 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1394
1520
  leads.set(edge.fromNode, [...(leads.get(edge.fromNode) ?? []), named(edge.toNode)]);
1395
1521
  from.set(edge.toNode, [...(from.get(edge.toNode) ?? []), named(edge.fromNode)]);
1396
1522
  }
1397
- const lang = this.closest('[lang]')?.getAttribute('lang') || undefined;
1398
- const list = new Intl.ListFormat(lang, { type: 'conjunction' });
1523
+ const list = new Intl.ListFormat(wordsLocale(this), { type: 'conjunction' });
1399
1524
  return new Map(this.nodes.map((one) => {
1400
1525
  const out = leads.get(one.id) ?? [];
1401
1526
  const into = from.get(one.id) ?? [];
1527
+ const leadsTo = out.length > 0 ? formatWords(this, 'leadsToLabel', { cards: list.format(out) }) : '';
1528
+ const comesFrom = into.length > 0 ? formatWords(this, 'comesFromLabel', { cards: list.format(into) }) : '';
1402
1529
  return [
1403
1530
  one.id,
1404
- [
1405
- out.length > 0 ? fillTemplate(this.leadsToLabel, { cards: list.format(out) }) : '',
1406
- into.length > 0 ? fillTemplate(this.comesFromLabel, { cards: list.format(into) }) : '',
1407
- ]
1408
- .filter(Boolean)
1409
- .join('; '),
1531
+ leadsTo && comesFrom
1532
+ ? formatWords(this, 'linkedLabel', { comesFrom, leadsTo })
1533
+ : leadsTo || comesFrom,
1410
1534
  ];
1411
1535
  }));
1412
1536
  }
@@ -1565,6 +1689,8 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1565
1689
  this.focusStop(refocus.next !== undefined && keys.has(refocus.next) ? refocus.next : this.walk[0]?.key);
1566
1690
  }
1567
1691
  }
1692
+ this.handOn();
1693
+ this.walked = this.walk;
1568
1694
  this.watchBox();
1569
1695
  if (!this.touched) {
1570
1696
  this.fitInto(true);
@@ -1655,6 +1781,8 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1655
1781
  if (this.held) {
1656
1782
  this.putBack();
1657
1783
  }
1784
+ this.edgePan.stop();
1785
+ this.carryPointer = undefined;
1658
1786
  this.sizes?.disconnect();
1659
1787
  this.watched = undefined;
1660
1788
  this.words?.disconnect();
@@ -1719,6 +1847,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1719
1847
  card.meaning = card.tone ? (this.toneLabels[card.tone] ?? '') : '';
1720
1848
  card.current = card.name === stop;
1721
1849
  card.selected = picked.has(card.name);
1850
+ card.status = card.selected ? this.selectedLabel : '';
1722
1851
  card.resizable = alone === card.name && !this.fixed(card);
1723
1852
  card.movable = picked.has(card.name) && !this.fixed(card);
1724
1853
  card.connectable = !this.fixed(card);
@@ -1807,8 +1936,8 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1807
1936
  const ends = heads(edge);
1808
1937
  return svg `<path
1809
1938
  part="edge-target"
1810
- aria-description=${[element?.tone ? this.toneLabels[element.tone] : undefined, edge.label].filter(Boolean).join(', ') || nothing}
1811
- aria-label=${fillTemplate(this.connectionLabel, { from: this.textOf(from), to: this.textOf(to) })}
1939
+ aria-description=${descriptionOf(wordsLocale(this), [pickedKeys.has(key) ? this.selectedLabel : '', element?.tone ? this.toneLabels[element.tone] : '', edge.label]) || nothing}
1940
+ aria-label=${formatWords(this, 'connectionLabel', { from: this.textOf(from), to: this.textOf(to) })}
1812
1941
  d=${drawn.d}
1813
1942
  data-edge=${key}
1814
1943
  fill="none"
@@ -1855,25 +1984,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1855
1984
  }
1856
1985
  return;
1857
1986
  }
1858
- const root = this.renderRoot;
1859
- const rest = [];
1860
- const named = new Map();
1861
- for (const child of this.knownChildren) {
1862
- const name = placed.get(child) ?? child.getAttribute('slot') ?? undefined;
1863
- if (name === undefined) {
1864
- rest.push(child);
1865
- }
1866
- else {
1867
- named.set(name, [...(named.get(name) ?? []), child]);
1868
- }
1869
- }
1870
- for (const slot of root?.querySelectorAll?.('slot') ?? []) {
1871
- const wanted = slot.name === '' ? rest : (named.get(slot.name) ?? []);
1872
- const had = slot.assignedNodes();
1873
- if (had.length !== wanted.length || had.some((one, at) => one !== wanted[at])) {
1874
- slot.assign?.(...wanted);
1875
- }
1876
- }
1987
+ assignSlots(this.renderRoot, this.knownChildren, (child) => placed.get(child));
1877
1988
  }
1878
1989
  renderLabels(origin) {
1879
1990
  return this.edges.map((edge) => {
@@ -1939,7 +2050,7 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
1939
2050
  return html `<div
1940
2051
  part="region"
1941
2052
  role="group"
1942
- aria-label=${this.label || 'Canvas'}
2053
+ aria-label=${this.label || this.fallbackLabel}
1943
2054
  aria-keyshortcuts="ArrowUp ArrowDown ArrowLeft ArrowRight Plus Minus"
1944
2055
  tabindex="0"
1945
2056
  @focusin=${this.idle.stir}
@@ -2001,26 +2112,52 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
2001
2112
  }
2002
2113
  };
2003
2114
  __decorate([
2115
+ words,
2116
+ property({ attribute: 'activate-hint-label' })
2117
+ ], HelixHeadlessCanvas.prototype, "activateHintLabel", void 0);
2118
+ __decorate([
2119
+ words,
2004
2120
  property({ attribute: 'comes-from-label' })
2005
2121
  ], HelixHeadlessCanvas.prototype, "comesFromLabel", void 0);
2006
2122
  __decorate([
2123
+ words,
2007
2124
  property({ attribute: 'connected-label' })
2008
2125
  ], HelixHeadlessCanvas.prototype, "connectedLabel", void 0);
2009
2126
  __decorate([
2127
+ words,
2010
2128
  property({ attribute: 'connecting-label' })
2011
2129
  ], HelixHeadlessCanvas.prototype, "connectingLabel", void 0);
2012
2130
  __decorate([
2131
+ words,
2013
2132
  property({ attribute: 'connection-label' })
2014
2133
  ], HelixHeadlessCanvas.prototype, "connectionLabel", void 0);
2134
+ __decorate([
2135
+ words,
2136
+ property({ attribute: 'controls-label' })
2137
+ ], HelixHeadlessCanvas.prototype, "controlsLabel", void 0);
2138
+ __decorate([
2139
+ words,
2140
+ property({ attribute: 'fallback-label' })
2141
+ ], HelixHeadlessCanvas.prototype, "fallbackLabel", void 0);
2015
2142
  __decorate([
2016
2143
  property()
2017
2144
  ], HelixHeadlessCanvas.prototype, "label", void 0);
2018
2145
  __decorate([
2146
+ words,
2019
2147
  property({ attribute: 'label-editor-label' })
2020
2148
  ], HelixHeadlessCanvas.prototype, "labelEditorLabel", void 0);
2021
2149
  __decorate([
2150
+ words,
2022
2151
  property({ attribute: 'leads-to-label' })
2023
2152
  ], HelixHeadlessCanvas.prototype, "leadsToLabel", void 0);
2153
+ __decorate([
2154
+ words,
2155
+ property({ attribute: 'linked-label' })
2156
+ ], HelixHeadlessCanvas.prototype, "linkedLabel", void 0);
2157
+ __decorate([
2158
+ words,
2159
+ property({ attribute: 'moved-label' })
2160
+ ], HelixHeadlessCanvas.prototype, "movedLabel", void 0);
2024
2161
  __decorate([
2025
2162
  property({ reflect: true })
2026
2163
  ], HelixHeadlessCanvas.prototype, "order", void 0);
@@ -2031,20 +2168,53 @@ __decorate([
2031
2168
  property({ attribute: 'readonly', reflect: true, type: Boolean })
2032
2169
  ], HelixHeadlessCanvas.prototype, "readOnly", void 0);
2033
2170
  __decorate([
2171
+ words,
2034
2172
  property({ attribute: 'reconnecting-label' })
2035
2173
  ], HelixHeadlessCanvas.prototype, "reconnectingLabel", void 0);
2174
+ __decorate([
2175
+ words,
2176
+ property({ attribute: 'resized-label' })
2177
+ ], HelixHeadlessCanvas.prototype, "resizedLabel", void 0);
2036
2178
  __decorate([
2037
2179
  property()
2038
2180
  ], HelixHeadlessCanvas.prototype, "selected", void 0);
2181
+ __decorate([
2182
+ words,
2183
+ property({ attribute: 'selected-label' })
2184
+ ], HelixHeadlessCanvas.prototype, "selectedLabel", void 0);
2185
+ __decorate([
2186
+ words,
2187
+ property({ attribute: 'selection-label' })
2188
+ ], HelixHeadlessCanvas.prototype, "selectionLabel", void 0);
2189
+ __decorate([
2190
+ property({ type: Number })
2191
+ ], HelixHeadlessCanvas.prototype, "snap", void 0);
2039
2192
  __decorate([
2040
2193
  state()
2041
2194
  ], HelixHeadlessCanvas.prototype, "editing", void 0);
2042
2195
  __decorate([
2196
+ words,
2043
2197
  property({ attribute: 'stopped-label' })
2044
2198
  ], HelixHeadlessCanvas.prototype, "stoppedLabel", void 0);
2045
2199
  __decorate([
2046
2200
  property({ attribute: 'tone-labels', converter: wordsConverter })
2047
2201
  ], HelixHeadlessCanvas.prototype, "toneLabels", void 0);
2202
+ __decorate([
2203
+ words,
2204
+ property({ attribute: 'two-finger-hint-label' })
2205
+ ], HelixHeadlessCanvas.prototype, "twoFingerHintLabel", void 0);
2206
+ __decorate([
2207
+ words,
2208
+ property({ attribute: 'using-label' })
2209
+ ], HelixHeadlessCanvas.prototype, "usingLabel", void 0);
2210
+ __decorate([
2211
+ words,
2212
+ property({ attribute: 'wheel-hint-label' })
2213
+ ], HelixHeadlessCanvas.prototype, "wheelHintLabel", void 0);
2214
+ __decorate([
2215
+ words,
2216
+ property({ attribute: 'zoomed-label' })
2217
+ ], HelixHeadlessCanvas.prototype, "zoomedLabel", void 0);
2048
2218
  __decorate([
2049
2219
  state()
2050
2220
  ], HelixHeadlessCanvas.prototype, "stop", void 0);