@fusion.dev/helix-headless 0.142.1 → 0.144.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 (285) hide show
  1. package/custom-elements.json +25381 -1202
  2. package/dist/accordion/item/accordion-item.d.ts +38 -2
  3. package/dist/accordion/item/accordion-item.js +38 -6
  4. package/dist/accordion/root/accordion-root.d.ts +23 -1
  5. package/dist/accordion/root/accordion-root.js +39 -3
  6. package/dist/announcement/root/announcement-root.d.ts +11 -7
  7. package/dist/announcement/root/announcement-root.js +1 -1
  8. package/dist/app-header/root/app-header-root.d.ts +21 -0
  9. package/dist/app-header/root/app-header-root.js +31 -5
  10. package/dist/area-chart/root/area-chart-root.d.ts +12 -4
  11. package/dist/area-chart/root/area-chart-root.js +39 -11
  12. package/dist/avatar/group/avatar-group.d.ts +24 -3
  13. package/dist/avatar/group/avatar-group.js +34 -2
  14. package/dist/avatar/root/avatar-root.d.ts +17 -1
  15. package/dist/avatar/root/avatar-root.js +31 -10
  16. package/dist/badge/root/badge-root.d.ts +12 -0
  17. package/dist/badge/root/badge-root.js +1 -1
  18. package/dist/bar-chart/root/bar-chart-root.d.ts +30 -5
  19. package/dist/bar-chart/root/bar-chart-root.js +58 -21
  20. package/dist/blockquote/root/blockquote-root.d.ts +12 -7
  21. package/dist/blockquote/root/blockquote-root.js +6 -4
  22. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
  23. package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
  24. package/dist/button/root/button-root.d.ts +84 -1
  25. package/dist/button/root/button-root.js +81 -3
  26. package/dist/callout/root/callout-root.d.ts +32 -6
  27. package/dist/callout/root/callout-root.js +26 -7
  28. package/dist/canvas/root/canvas-root.d.ts +1 -0
  29. package/dist/canvas/root/canvas-root.js +10 -1
  30. package/dist/card/root/card-root.d.ts +30 -1
  31. package/dist/card/root/card-root.js +38 -5
  32. package/dist/carousel/root/carousel-root.d.ts +47 -5
  33. package/dist/carousel/root/carousel-root.js +53 -21
  34. package/dist/chat/composer/chat-composer.d.ts +13 -11
  35. package/dist/chat/composer/chat-composer.js +6 -12
  36. package/dist/chat/message/chat-message.js +8 -1
  37. package/dist/chat/root/chat-root.d.ts +1 -0
  38. package/dist/chat/root/chat-root.js +2 -1
  39. package/dist/checkbox/root/checkbox-root.d.ts +7 -0
  40. package/dist/checkbox/root/checkbox-root.js +9 -3
  41. package/dist/checkbox-group/root/checkbox-group-root.d.ts +116 -33
  42. package/dist/checkbox-group/root/checkbox-group-root.js +141 -44
  43. package/dist/code/root/code-root.d.ts +1 -1
  44. package/dist/code-block/lines.d.ts +13 -0
  45. package/dist/code-block/lines.js +2 -0
  46. package/dist/code-block/root/code-block-root.d.ts +49 -0
  47. package/dist/code-block/root/code-block-root.js +44 -3
  48. package/dist/color-input/root/color-input-root.d.ts +60 -2
  49. package/dist/color-input/root/color-input-root.js +55 -7
  50. package/dist/color-picker/channels.d.ts +26 -0
  51. package/dist/color-picker/channels.js +84 -0
  52. package/dist/color-picker/root/color-picker-root.d.ts +118 -12
  53. package/dist/color-picker/root/color-picker-root.js +183 -13
  54. package/dist/combobox/root/combobox-root.d.ts +126 -3
  55. package/dist/combobox/root/combobox-root.js +224 -21
  56. package/dist/command/root/command-root.d.ts +47 -10
  57. package/dist/command/root/command-root.js +45 -4
  58. package/dist/copy-button/from.d.ts +22 -0
  59. package/dist/copy-button/from.js +28 -0
  60. package/dist/copy-button/root/copy-button-root.d.ts +48 -7
  61. package/dist/copy-button/root/copy-button-root.js +54 -8
  62. package/dist/data-table/root/data-table-root.d.ts +164 -10
  63. package/dist/data-table/root/data-table-root.js +488 -57
  64. package/dist/date-input/root/date-input-root.d.ts +123 -9
  65. package/dist/date-input/root/date-input-root.js +147 -45
  66. package/dist/date-picker/root/date-picker-root.d.ts +229 -18
  67. package/dist/date-picker/root/date-picker-root.js +342 -46
  68. package/dist/dialog/description.d.ts +9 -0
  69. package/dist/dialog/description.js +14 -0
  70. package/dist/dialog/root/dialog-root.d.ts +101 -10
  71. package/dist/dialog/root/dialog-root.js +83 -4
  72. package/dist/donut-chart/root/donut-chart-root.d.ts +61 -16
  73. package/dist/donut-chart/root/donut-chart-root.js +48 -13
  74. package/dist/drawer/root/drawer-root.d.ts +93 -7
  75. package/dist/drawer/root/drawer-root.js +126 -5
  76. package/dist/drawer/swipe-start.d.ts +9 -0
  77. package/dist/drawer/swipe-start.js +12 -0
  78. package/dist/drilldown/item/drilldown-item.d.ts +16 -13
  79. package/dist/drilldown/item/drilldown-item.js +6 -2
  80. package/dist/drilldown/root/drilldown-root.d.ts +21 -5
  81. package/dist/drilldown/root/drilldown-root.js +26 -10
  82. package/dist/element-events.generated.js +42 -13
  83. package/dist/empty/root/empty-root.d.ts +1 -1
  84. package/dist/file-input/root/file-input-root.d.ts +65 -1
  85. package/dist/file-input/root/file-input-root.js +76 -12
  86. package/dist/file-input/screen.d.ts +35 -0
  87. package/dist/file-input/screen.js +49 -0
  88. package/dist/filter-input/menu/filter-menu.d.ts +9 -0
  89. package/dist/filter-input/menu/filter-menu.js +8 -0
  90. package/dist/filter-input/root/filter-input-root.d.ts +43 -6
  91. package/dist/filter-input/root/filter-input-root.js +89 -10
  92. package/dist/filter-input/suggest.d.ts +17 -0
  93. package/dist/filter-input/suggest.js +23 -0
  94. package/dist/format-date/options.d.ts +33 -0
  95. package/dist/format-date/options.js +42 -0
  96. package/dist/format-date/root/format-date-root.d.ts +62 -3
  97. package/dist/format-date/root/format-date-root.js +78 -37
  98. package/dist/graph/root/graph-root.d.ts +24 -3
  99. package/dist/graph/root/graph-root.js +66 -12
  100. package/dist/heatmap/root/buckets.d.ts +2 -1
  101. package/dist/heatmap/root/buckets.js +5 -1
  102. package/dist/heatmap/root/heatmap-root.d.ts +47 -9
  103. package/dist/heatmap/root/heatmap-root.js +46 -18
  104. package/dist/icon/index.d.ts +2 -0
  105. package/dist/icon/index.js +2 -0
  106. package/dist/icon/registry.d.ts +37 -0
  107. package/dist/icon/registry.js +83 -0
  108. package/dist/icon/root/icon-root.d.ts +53 -6
  109. package/dist/icon/root/icon-root.js +72 -4
  110. package/dist/icon/root/index.d.ts +2 -0
  111. package/dist/icon/root/index.js +2 -0
  112. package/dist/icon/set.d.ts +1 -0
  113. package/dist/icon/set.js +3 -0
  114. package/dist/icon-button/root/icon-button-root.d.ts +1 -1
  115. package/dist/image/root/image-root.d.ts +23 -2
  116. package/dist/image/root/image-root.js +23 -4
  117. package/dist/input/root/input-root.d.ts +62 -9
  118. package/dist/input/root/input-root.js +61 -5
  119. package/dist/kbd/root/kbd-root.d.ts +26 -11
  120. package/dist/kbd/root/kbd-root.js +35 -38
  121. package/dist/kbd/shortcut.d.ts +18 -0
  122. package/dist/kbd/shortcut.js +35 -0
  123. package/dist/legend/hidden-series.d.ts +8 -0
  124. package/dist/legend/hidden-series.js +13 -0
  125. package/dist/legend/root/legend-root.d.ts +63 -0
  126. package/dist/legend/root/legend-root.js +61 -7
  127. package/dist/lightbox/item/lightbox-item.d.ts +17 -1
  128. package/dist/lightbox/item/lightbox-item.js +10 -1
  129. package/dist/lightbox/root/lightbox-root.d.ts +77 -6
  130. package/dist/lightbox/root/lightbox-root.js +116 -5
  131. package/dist/line-chart/root/line-chart-root.d.ts +29 -4
  132. package/dist/line-chart/root/line-chart-root.js +58 -17
  133. package/dist/list/item/list-item.d.ts +11 -5
  134. package/dist/list/item/list-item.js +5 -6
  135. package/dist/listbox/range.d.ts +17 -0
  136. package/dist/listbox/range.js +5 -0
  137. package/dist/listbox/root/listbox-root.d.ts +184 -4
  138. package/dist/listbox/root/listbox-root.js +229 -23
  139. package/dist/loader/busy.d.ts +17 -0
  140. package/dist/loader/busy.js +24 -0
  141. package/dist/loader/root/loader-root.d.ts +37 -0
  142. package/dist/loader/root/loader-root.js +52 -3
  143. package/dist/map/root/map-root.d.ts +19 -4
  144. package/dist/map/root/map-root.js +36 -7
  145. package/dist/megamenu/root/megamenu-root.d.ts +10 -1
  146. package/dist/megamenu/root/megamenu-root.js +10 -1
  147. package/dist/menu/item/menu-item.d.ts +41 -12
  148. package/dist/menu/item/menu-item.js +46 -3
  149. package/dist/menu/root/menu-root.d.ts +32 -2
  150. package/dist/menu/root/menu-root.js +48 -8
  151. package/dist/meter/root/meter-root.d.ts +13 -0
  152. package/dist/meter/root/meter-root.js +24 -5
  153. package/dist/navigation/root/navigation-root.d.ts +10 -2
  154. package/dist/navigation/root/navigation-root.js +13 -2
  155. package/dist/notifications/feed-keys.d.ts +10 -0
  156. package/dist/notifications/feed-keys.js +14 -0
  157. package/dist/notifications/group/notification-group.d.ts +1 -0
  158. package/dist/notifications/notification/notification.d.ts +29 -0
  159. package/dist/notifications/notification/notification.js +51 -3
  160. package/dist/notifications/root/notifications-root.d.ts +49 -0
  161. package/dist/notifications/root/notifications-root.js +76 -2
  162. package/dist/number-input/root/number-input-root.d.ts +109 -7
  163. package/dist/number-input/root/number-input-root.js +109 -21
  164. package/dist/object-inspector/root/object-inspector-root.d.ts +49 -5
  165. package/dist/object-inspector/root/object-inspector-root.js +92 -12
  166. package/dist/option/root/option-root.d.ts +58 -6
  167. package/dist/option/root/option-root.js +35 -5
  168. package/dist/outline/root/outline-root.d.ts +13 -2
  169. package/dist/outline/root/outline-root.js +4 -2
  170. package/dist/pagination/root/pagination-root.d.ts +19 -1
  171. package/dist/pagination/root/pagination-root.js +49 -9
  172. package/dist/pagination/size/pagination-size.d.ts +13 -3
  173. package/dist/pagination/size/pagination-size.js +7 -0
  174. package/dist/pin-input/format.d.ts +7 -0
  175. package/dist/pin-input/format.js +16 -0
  176. package/dist/pin-input/root/pin-input-root.d.ts +37 -0
  177. package/dist/pin-input/root/pin-input-root.js +48 -7
  178. package/dist/popover/root/popover-root.d.ts +78 -3
  179. package/dist/popover/root/popover-root.js +74 -5
  180. package/dist/progress/root/progress-root.d.ts +23 -1
  181. package/dist/progress/root/progress-root.js +40 -10
  182. package/dist/qr-code/export.d.ts +31 -0
  183. package/dist/qr-code/export.js +10 -0
  184. package/dist/qr-code/root/qr-code-root.d.ts +45 -0
  185. package/dist/qr-code/root/qr-code-root.js +78 -3
  186. package/dist/radio/group/radio-group.d.ts +64 -0
  187. package/dist/radio/group/radio-group.js +66 -12
  188. package/dist/radio/root/radio-root.d.ts +8 -5
  189. package/dist/radio/root/radio-root.js +1 -2
  190. package/dist/rating/root/rating-root.d.ts +49 -1
  191. package/dist/rating/root/rating-root.js +69 -10
  192. package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
  193. package/dist/scatter-chart/root/scatter-chart-root.js +40 -14
  194. package/dist/select/root/select-root.d.ts +93 -3
  195. package/dist/select/root/select-root.js +111 -13
  196. package/dist/skeleton/root/skeleton-root.d.ts +39 -3
  197. package/dist/skeleton/root/skeleton-root.js +33 -4
  198. package/dist/skip-link/root/skip-link-root.d.ts +10 -0
  199. package/dist/skip-link/root/skip-link-root.js +15 -1
  200. package/dist/slider/root/slider-root.d.ts +59 -2
  201. package/dist/slider/root/slider-root.js +82 -8
  202. package/dist/sparkline/root/sparkline-root.d.ts +9 -10
  203. package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
  204. package/dist/speed-dial/item/speed-dial-item.js +7 -2
  205. package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
  206. package/dist/speed-dial/root/speed-dial-root.js +19 -5
  207. package/dist/splitter/root/splitter-root.d.ts +28 -6
  208. package/dist/splitter/root/splitter-root.js +35 -1
  209. package/dist/stat/root/stat-root.d.ts +9 -1
  210. package/dist/stat/root/stat-root.js +15 -2
  211. package/dist/steps/root/steps-root.js +1 -1
  212. package/dist/steps/step/step.d.ts +1 -0
  213. package/dist/steps/step/step.js +1 -1
  214. package/dist/switch/root/switch-root.d.ts +14 -2
  215. package/dist/switch/root/switch-root.js +7 -1
  216. package/dist/table/cell/table-cell.d.ts +24 -4
  217. package/dist/table/cell/table-cell.js +21 -1
  218. package/dist/table/column/table-column.d.ts +32 -6
  219. package/dist/table/column/table-column.js +36 -6
  220. package/dist/table/root/table-root.d.ts +94 -3
  221. package/dist/table/root/table-root.js +128 -5
  222. package/dist/table/row/table-row.d.ts +7 -0
  223. package/dist/table/row/table-row.js +9 -1
  224. package/dist/tabs/root/tabs-root.d.ts +6 -1
  225. package/dist/tabs/root/tabs-root.js +6 -2
  226. package/dist/tag/group/tag-group.d.ts +107 -0
  227. package/dist/tag/group/tag-group.js +157 -0
  228. package/dist/tag/index.d.ts +1 -0
  229. package/dist/tag/index.js +1 -0
  230. package/dist/tag/root/tag-root.d.ts +83 -1
  231. package/dist/tag/root/tag-root.js +87 -17
  232. package/dist/tag/selection.d.ts +10 -0
  233. package/dist/tag/selection.js +12 -0
  234. package/dist/textarea/grow.d.ts +22 -0
  235. package/dist/textarea/grow.js +20 -0
  236. package/dist/textarea/root/textarea-root.d.ts +13 -0
  237. package/dist/textarea/root/textarea-root.js +10 -2
  238. package/dist/time-input/root/time-input-root.d.ts +71 -6
  239. package/dist/time-input/root/time-input-root.js +110 -44
  240. package/dist/time-picker/root/time-picker-root.d.ts +155 -26
  241. package/dist/time-picker/root/time-picker-root.js +192 -63
  242. package/dist/toast/hotkey.d.ts +22 -0
  243. package/dist/toast/hotkey.js +23 -0
  244. package/dist/toast/item/toast-item.d.ts +16 -1
  245. package/dist/toast/item/toast-item.js +41 -13
  246. package/dist/toast/root/toast-root.d.ts +105 -8
  247. package/dist/toast/root/toast-root.js +209 -4
  248. package/dist/toggle/group/toggle-group.d.ts +95 -16
  249. package/dist/toggle/group/toggle-group.js +99 -13
  250. package/dist/toggle/root/toggle-root.d.ts +26 -11
  251. package/dist/toggle/root/toggle-root.js +14 -6
  252. package/dist/toolbar/root/toolbar-root.d.ts +55 -15
  253. package/dist/toolbar/root/toolbar-root.js +99 -16
  254. package/dist/tooltip/focus-target.d.ts +6 -0
  255. package/dist/tooltip/focus-target.js +9 -0
  256. package/dist/tooltip/root/tooltip-root.d.ts +73 -15
  257. package/dist/tooltip/root/tooltip-root.js +96 -7
  258. package/dist/tour/naming.d.ts +30 -0
  259. package/dist/tour/naming.js +10 -0
  260. package/dist/tour/root/tour-root.d.ts +67 -3
  261. package/dist/tour/root/tour-root.js +105 -17
  262. package/dist/tour/stop/tour-stop.d.ts +65 -3
  263. package/dist/tour/stop/tour-stop.js +61 -11
  264. package/dist/tour/wait.d.ts +11 -0
  265. package/dist/tour/wait.js +19 -0
  266. package/dist/tree/item/tree-item.d.ts +21 -5
  267. package/dist/tree/item/tree-item.js +14 -4
  268. package/dist/tree/root/tree-root.d.ts +29 -5
  269. package/dist/tree/root/tree-root.js +64 -8
  270. package/dist/trend/root/trend-root.d.ts +36 -1
  271. package/dist/trend/root/trend-root.js +41 -15
  272. package/dist/video/root/keys.d.ts +5 -0
  273. package/dist/video/root/keys.js +13 -1
  274. package/dist/video/root/video-root.d.ts +19 -0
  275. package/dist/video/root/video-root.js +48 -4
  276. package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
  277. package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
  278. package/dist/video-playlist/root/video-playlist-root.js +6 -3
  279. package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
  280. package/dist/virtual-list/root/virtual-list-root.js +103 -21
  281. package/lint.json +1 -1
  282. package/package.json +5 -5
  283. package/types/jsx.d.ts +9140 -1149
  284. package/types/svelte.d.ts +1 -0
  285. package/types/vue.d.ts +2089 -267
@@ -4,18 +4,31 @@ 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 { customElement, DisabledCascadeController, HelixBeforeChangeEvent, HelixFormElement, hostAria, MixinField, } from '@fusion.dev/helix-core';
8
- import { html } from 'lit';
7
+ var HelixHeadlessCheckboxGroup_1;
8
+ import { commaList, customElement, DisabledCascadeController, HelixBeforeChangeEvent, HelixFormElement, hostAria, MixinField, } from '@fusion.dev/helix-core';
9
+ import { nothing } from 'lit';
9
10
  import { property } from 'lit/decorators.js';
11
+ import { html } from 'lit/static-html.js';
10
12
  import { HelixHeadlessCheckbox } from '../../checkbox/root/checkbox-root.js';
11
- let HelixHeadlessCheckboxGroup = class HelixHeadlessCheckboxGroup extends MixinField(HelixFormElement) {
13
+ import '../../checkbox/index.js';
14
+ let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadlessCheckboxGroup extends MixinField(HelixFormElement) {
12
15
  constructor() {
13
16
  super(...arguments);
14
- this.value = '';
17
+ this.selectAll = false;
18
+ this.selectAllLabel = 'Select all';
19
+ this.declared = [];
20
+ this.pending = false;
21
+ this.watched = new Set();
22
+ this.member = {
23
+ hostUpdated: () => {
24
+ if (this.isConnected && (this.selectAll || this.value !== this.judged)) {
25
+ this.requestUpdate();
26
+ }
27
+ },
28
+ };
15
29
  this.cascade = new DisabledCascadeController(this, {
16
30
  items: () => this.boxes,
17
31
  });
18
- this.seeded = false;
19
32
  this.handleToggle = (event) => {
20
33
  const target = event.target;
21
34
  const changed = this.boxes.find((box) => box === target);
@@ -29,40 +42,93 @@ let HelixHeadlessCheckboxGroup = class HelixHeadlessCheckboxGroup extends MixinF
29
42
  const wanted = event.detail.checked;
30
43
  const next = this.boxes
31
44
  .filter((box) => (box === changed ? wanted : box.checked))
32
- .map((box) => box.value)
33
- .join(',');
34
- if (!this.dispatchEvent(new HelixBeforeChangeEvent({ value: next }))) {
45
+ .map((box) => box.value);
46
+ if (!this.dispatchEvent(new HelixBeforeChangeEvent({ value: next.join(',') }))) {
47
+ event.preventDefault();
35
48
  return;
36
49
  }
37
- this.value = next;
50
+ this.values = next;
38
51
  this.announceInput();
39
52
  this.announceChange();
40
53
  };
41
54
  this.handleMemberNative = (event) => {
42
- if (event.target !== this) {
55
+ if (event.target instanceof HelixHeadlessCheckbox && this.holds(event.target)) {
43
56
  event.stopImmediatePropagation();
44
57
  }
45
58
  };
59
+ this.handleSelectAll = (event) => {
60
+ event.preventDefault();
61
+ event.stopPropagation();
62
+ const enabled = this.boxes.filter((box) => !box.isDisabled);
63
+ const every = enabled.length > 0 && enabled.every((box) => box.checked);
64
+ const next = this.boxes
65
+ .filter((box) => (enabled.includes(box) ? !every : box.checked))
66
+ .map((box) => box.value);
67
+ if (!this.dispatchEvent(new HelixBeforeChangeEvent({ value: next.join(',') }))) {
68
+ return;
69
+ }
70
+ this.values = next;
71
+ this.announceInput();
72
+ this.announceChange();
73
+ };
74
+ }
75
+ get value() {
76
+ return this.values.join(',');
77
+ }
78
+ set value(next) {
79
+ this.values = commaList(next);
80
+ }
81
+ get values() {
82
+ if (this.pending || !this.hasUpdated || !this.childrenKnown) {
83
+ return [...this.declared];
84
+ }
85
+ const boxes = this.boxes;
86
+ return boxes.length === 0
87
+ ? [...this.declared]
88
+ : boxes.filter((box) => box.checked).map((box) => box.value);
89
+ }
90
+ set values(next) {
91
+ const previous = this.value;
92
+ this.declared = [...next];
93
+ this.pending = true;
94
+ this.requestUpdate('value', previous);
46
95
  }
47
96
  get boxes() {
48
- return [...this.children].filter((child) => child instanceof HelixHeadlessCheckbox);
97
+ return [...this.querySelectorAll('*')].filter((element) => element instanceof HelixHeadlessCheckbox && this.holds(element));
98
+ }
99
+ holds(box) {
100
+ let parent = box.parentElement;
101
+ while (parent && parent !== this) {
102
+ if (parent instanceof HelixHeadlessCheckboxGroup_1) {
103
+ return false;
104
+ }
105
+ parent = parent.parentElement;
106
+ }
107
+ return parent === this;
49
108
  }
50
109
  sync() {
51
- const wanted = new Set(this.value
52
- .split(',')
53
- .map((entry) => entry.trim())
54
- .filter(Boolean));
55
- for (const box of this.boxes) {
110
+ const boxes = this.boxes;
111
+ for (const box of boxes) {
56
112
  if (this.name !== '' && box.name === '') {
57
113
  box.name = this.name;
58
114
  }
59
- box.checked = wanted.has(box.value);
115
+ if (!this.watched.has(box)) {
116
+ box.addController(this.member);
117
+ this.watched.add(box);
118
+ }
60
119
  }
61
- }
62
- seed() {
63
- const checked = this.boxes.filter((box) => box.checked).map((box) => box.value);
64
- if (checked.length > 0) {
65
- this.value = checked.join(',');
120
+ for (const box of this.watched) {
121
+ if (!boxes.includes(box)) {
122
+ this.unwatch(box);
123
+ }
124
+ }
125
+ if (!this.pending || boxes.length === 0) {
126
+ return;
127
+ }
128
+ this.pending = false;
129
+ const wanted = new Set(this.declared);
130
+ for (const box of boxes) {
131
+ box.checked = wanted.has(box.value);
66
132
  }
67
133
  }
68
134
  connectedCallback() {
@@ -70,49 +136,71 @@ let HelixHeadlessCheckboxGroup = class HelixHeadlessCheckboxGroup extends MixinF
70
136
  this.addEventListener('helix-before-toggle', this.handleToggle);
71
137
  this.addEventListener('change', this.handleMemberNative);
72
138
  this.addEventListener('input', this.handleMemberNative);
139
+ this.observer = new MutationObserver(() => this.requestUpdate());
140
+ this.observer.observe(this, { childList: true, subtree: true });
73
141
  }
74
142
  disconnectedCallback() {
75
143
  super.disconnectedCallback();
76
144
  this.removeEventListener('helix-before-toggle', this.handleToggle);
77
145
  this.removeEventListener('change', this.handleMemberNative);
78
146
  this.removeEventListener('input', this.handleMemberNative);
147
+ this.observer?.disconnect();
148
+ this.observer = undefined;
149
+ for (const box of this.watched) {
150
+ this.unwatch(box);
151
+ }
152
+ }
153
+ unwatch(box) {
154
+ box.removeController(this.member);
155
+ this.watched.delete(box);
79
156
  }
80
157
  willUpdate(changed) {
81
158
  super.willUpdate(changed);
82
159
  hostAria(this.internals, { label: this.label, role: 'group' });
83
160
  this.internals.ariaRequired = this.required ? 'true' : null;
84
- if (!this.seeded && this.childrenKnown) {
85
- this.seeded = true;
86
- if (this.value === '') {
87
- this.seed();
88
- }
89
- }
90
- }
91
- firstUpdated(changed) {
92
- super.firstUpdated(changed);
93
- if (!this.seeded && this.children !== undefined) {
94
- this.seeded = true;
95
- if (this.value === '') {
96
- this.seed();
97
- }
98
- }
99
161
  }
100
162
  formResetCallback() {
101
163
  super.formResetCallback();
102
- this.value = this.getAttribute('value') ?? '';
103
- this.seeded = false;
164
+ const declared = this.getAttribute('value');
165
+ if (declared !== null) {
166
+ this.value = declared;
167
+ }
168
+ this.requestUpdate();
104
169
  }
105
170
  validate() {
106
- this.reportRequired(this.value === '', 'Choose at least one to continue.', 'items');
171
+ this.judged = this.value;
172
+ this.reportRequired(this.judged === '', 'Choose at least one to continue.', 'items');
107
173
  }
108
174
  updated(changed) {
109
175
  super.updated(changed);
110
- this.validate();
111
176
  this.sync();
177
+ this.validate();
112
178
  this.linkHost();
113
179
  }
180
+ renderSelectAll() {
181
+ if (!this.selectAll) {
182
+ return nothing;
183
+ }
184
+ const boxes = this.childrenKnown ? this.boxes : [];
185
+ const ticked = boxes.filter((box) => box.checked).length;
186
+ const every = boxes.length > 0 && ticked === boxes.length;
187
+ const box = this.tag('checkbox');
188
+ return html `<${box}
189
+ part="select-all"
190
+ exportparts="box: select-all-box, control: select-all-control,
191
+ feedback: select-all-feedback, field: select-all-field, hint: select-all-hint,
192
+ label: select-all-label, mark: select-all-mark, mark-checked: select-all-mark-checked,
193
+ mark-dash: select-all-mark-dash, mark-indeterminate: select-all-mark-indeterminate"
194
+ .checked=${every}
195
+ .indeterminate=${ticked > 0 && !every}
196
+ ?disabled=${this.isDisabled}
197
+ label=${this.selectAllLabel}
198
+ @helix-before-toggle=${this.handleSelectAll}
199
+ @input=${(event) => event.stopPropagation()}
200
+ ></${box}>`;
201
+ }
114
202
  render() {
115
- return html `${this.renderGroupLabel()}
203
+ return html `${this.renderGroupLabel()}${this.renderSelectAll()}
116
204
  <div part="items">
117
205
  ${''}
118
206
  <slot @slotchange=${() => this.requestUpdate()}></slot>
@@ -120,10 +208,19 @@ let HelixHeadlessCheckboxGroup = class HelixHeadlessCheckboxGroup extends MixinF
120
208
  ${this.renderHint()}${this.renderFeedback()}`;
121
209
  }
122
210
  };
211
+ __decorate([
212
+ property({ attribute: 'select-all', type: Boolean })
213
+ ], HelixHeadlessCheckboxGroup.prototype, "selectAll", void 0);
214
+ __decorate([
215
+ property({ attribute: 'select-all-label' })
216
+ ], HelixHeadlessCheckboxGroup.prototype, "selectAllLabel", void 0);
123
217
  __decorate([
124
218
  property()
125
- ], HelixHeadlessCheckboxGroup.prototype, "value", void 0);
126
- HelixHeadlessCheckboxGroup = __decorate([
219
+ ], HelixHeadlessCheckboxGroup.prototype, "value", null);
220
+ __decorate([
221
+ property({ attribute: false })
222
+ ], HelixHeadlessCheckboxGroup.prototype, "values", null);
223
+ HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = __decorate([
127
224
  customElement('helix-headless-checkbox-group')
128
225
  ], HelixHeadlessCheckboxGroup);
129
226
  export { HelixHeadlessCheckboxGroup };
@@ -15,7 +15,7 @@ import { type TemplateResult } from 'lit';
15
15
  * @since 0.1.0
16
16
  * @status stable
17
17
  * @category typography
18
- * @aliases Inline code, Kbd
18
+ * @aliases Inline code
19
19
  * @documentation https://fusion.dev/helix/components/code
20
20
  *
21
21
  * @slot - The code.
@@ -0,0 +1,13 @@
1
+ /**
2
+ * How many lines a block of code shows.
3
+ *
4
+ * A final line break ends the last line rather than starting another, which is
5
+ * how an editor counts a file and how the block draws one: `a\nb\n` is two
6
+ * lines. A Windows line break is one break. Empty code has no lines.
7
+ */
8
+ export declare const lineCount: (code: string) => number;
9
+ /**
10
+ * The numbers for a gutter of `count` lines, one to a line, as the text a
11
+ * `<pre>` draws beside the code. The stylesheet aligns them to the end.
12
+ */
13
+ export declare const gutterNumbers: (count: number) => string;
@@ -0,0 +1,2 @@
1
+ export const lineCount = (code) => code === '' ? 0 : code.replace(/\r?\n$/, '').split(/\r?\n/).length;
2
+ export const gutterNumbers = (count) => Array.from({ length: count }, (_, index) => String(index + 1)).join('\n');
@@ -14,6 +14,12 @@ import '../../copy-button/index.js';
14
14
  *
15
15
  * For a fragment of code inside a sentence, use `Code`.
16
16
  *
17
+ * Set `line-numbers` to number the lines in a gutter beside the code, hidden
18
+ * from the accessibility tree and left out of a copy. Set `highlight` to a
19
+ * function that turns the code into highlighted markup, such as one wrapping
20
+ * Shiki or Prism, and the block draws what it returns; the code stays in the
21
+ * slot, so the copy button and the page's own text are the code as written.
22
+ *
17
23
  * Set `diff` to show a change. Put a unified diff, the output of `git diff` or
18
24
  * `diff -u`, in the same slot, and the block draws the lines it added and
19
25
  * removed. The block never computes a diff itself. Line numbers come from the
@@ -42,6 +48,7 @@ import '../../copy-button/index.js';
42
48
  * @csspart context - In a diff, a line both versions share.
43
49
  * @csspart copy - The copy button. It sits in the header when there is one, and beside the code otherwise.
44
50
  * @csspart copy-button - The inner button.
51
+ * @csspart copy-live - The copy button's live region, which speaks while the button is pending.
45
52
  * @csspart copy-mark - The clipboard icon, and the check mark that replaces it after a copy.
46
53
  * @csspart copy-text - The words on that button, trimmed to their capitals and baseline.
47
54
  * @csspart copy-tooltip - The copy button's tooltip.
@@ -57,6 +64,7 @@ import '../../copy-button/index.js';
57
64
  * @csspart file - In a diff, one file's header and block.
58
65
  * @csspart filler - In a split diff, the empty row opposite a line the other side does not have.
59
66
  * @csspart frame - The code, and the copy button beside it where there is no header.
67
+ * @csspart gutter - The line numbers beside the code, shown when `line-numbers` is set.
60
68
  * @csspart header - The bar that holds the name and the copy button, shown when there is a name.
61
69
  * @csspart hunk - In a diff, a `@@` line saying where the lines under it are.
62
70
  * @csspart label - The file name or language, where one is given.
@@ -69,6 +77,14 @@ import '../../copy-button/index.js';
69
77
  * @csspart text - In a diff, a line's code.
70
78
  */
71
79
  export declare class HelixHeadlessCodeBlock extends HelixElement {
80
+ /**
81
+ * The copy button's name and tooltip text after a copy.
82
+ */
83
+ copiedLabel: string;
84
+ /**
85
+ * The copy button's name and tooltip text before a copy.
86
+ */
87
+ copyLabel: string;
72
88
  /**
73
89
  * Whether the content is a unified diff, drawn as the lines it changed.
74
90
  *
@@ -76,6 +92,19 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
76
92
  * `false` reflects as no attribute at all.
77
93
  */
78
94
  diff: boolean;
95
+ /**
96
+ * Turns the code into highlighted markup, which the block draws in place of
97
+ * the plain text.
98
+ *
99
+ * Called with the code as written and returning HTML, such as the output of
100
+ * Shiki's `codeToHtml` or Prism's `highlight`. **The markup is drawn as
101
+ * given**, so it has to escape the code it was handed, which those
102
+ * highlighters do. Bind the language in the function you pass. The code
103
+ * stays in the slot, so the copy button copies it as written and a reader
104
+ * without the script still has it. Not called on a server, which has no code
105
+ * to read, nor for a diff.
106
+ */
107
+ highlight?: (code: string) => string;
79
108
  /**
80
109
  * The block's name, usually a file name or a language.
81
110
  *
@@ -83,6 +112,15 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
83
112
  * carries no name of its own.
84
113
  */
85
114
  label: string;
115
+ /**
116
+ * Whether the lines are numbered in a gutter beside the code.
117
+ *
118
+ * The numbers are hidden from the accessibility tree and are not part of a
119
+ * copy, which takes the code alone. Reflected, because the stylesheet lays
120
+ * the gutter out beside the code. A diff numbers its lines from its hunks
121
+ * whether or not this is set.
122
+ */
123
+ lineNumbers: boolean;
86
124
  /**
87
125
  * Whether to leave the copy button off.
88
126
  *
@@ -133,6 +171,17 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
133
171
  * server sent, which rendered it empty.
134
172
  */
135
173
  private get text();
174
+ /**
175
+ * Watches the code for edits that change no slot assignment.
176
+ *
177
+ * A framework updating one string child writes the text node's data in
178
+ * place, which React does, and that fires no `slotchange`. The block showed
179
+ * the new code while its button copied the old, and a diff edited that way
180
+ * was not redrawn.
181
+ */
182
+ private observer;
183
+ connectedCallback(): void;
184
+ disconnectedCallback(): void;
136
185
  protected firstUpdated(changed: PropertyValues): void;
137
186
  protected render(): TemplateResult;
138
187
  /**
@@ -7,14 +7,19 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { customElement, HelixElement } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
10
11
  import { html } from 'lit/static-html.js';
11
12
  import '../../copy-button/index.js';
13
+ import { gutterNumbers, lineCount } from '../lines.js';
12
14
  import { pairLines, parsePatch } from '../patch.js';
13
15
  let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
14
16
  constructor() {
15
17
  super(...arguments);
18
+ this.copiedLabel = 'Copied';
19
+ this.copyLabel = 'Copy code';
16
20
  this.diff = false;
17
21
  this.label = '';
22
+ this.lineNumbers = false;
18
23
  this.noCopy = false;
19
24
  this.parsed = { files: [], text: '' };
20
25
  }
@@ -38,6 +43,17 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
38
43
  .map((node) => node.textContent ?? '')
39
44
  .join('');
40
45
  }
46
+ connectedCallback() {
47
+ super.connectedCallback();
48
+ if (typeof MutationObserver !== 'undefined') {
49
+ this.observer ??= new MutationObserver(() => this.requestUpdate());
50
+ this.observer.observe(this, { characterData: true, childList: true, subtree: true });
51
+ }
52
+ }
53
+ disconnectedCallback() {
54
+ super.disconnectedCallback();
55
+ this.observer?.disconnect();
56
+ }
41
57
  firstUpdated(changed) {
42
58
  super.firstUpdated(changed);
43
59
  this.finishHydration();
@@ -47,9 +63,21 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
47
63
  if (files.length > 0) {
48
64
  return this.renderDiff(files);
49
65
  }
66
+ const text = this.text;
67
+ const highlighted = this.highlight && text !== '' ? this.highlight(text) : undefined;
68
+ const code = highlighted === undefined
69
+ ? html `<code part="code"><slot @slotchange=${() => this.requestUpdate()}></slot></code>`
70
+ : html `<code part="code">${unsafeHTML(highlighted)}</code><slot
71
+ hidden
72
+ @slotchange=${() => this.requestUpdate()}
73
+ ></slot>`;
74
+ const lines = lineCount(text);
75
+ const gutter = this.lineNumbers
76
+ ? html `<span part="gutter" aria-hidden="true">${lines === 0 ? nothing : gutterNumbers(lines)}</span>`
77
+ : nothing;
50
78
  return html `${this.renderHeader(this.label)}
51
79
  <div part="frame">
52
- <pre part="block"><code part="code"><slot @slotchange=${() => this.requestUpdate()}></slot></code></pre>
80
+ <pre part="block">${gutter}${code}</pre>
53
81
  ${this.label ? nothing : this.renderCopy()}
54
82
  </div>`;
55
83
  }
@@ -64,12 +92,13 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
64
92
  renderCopyButton(value = this.text) {
65
93
  return html `<${this.tag('copy-button')}
66
94
  part="copy"
67
- exportparts="button: copy-button, text: copy-text, mark: copy-mark, tooltip: copy-tooltip,
95
+ exportparts="button: copy-button, text: copy-text, mark: copy-mark, live: copy-live, tooltip: copy-tooltip,
68
96
  tooltip-arrow: copy-tooltip-arrow, tooltip-arrow-bottom: copy-tooltip-arrow-bottom,
69
97
  tooltip-arrow-left: copy-tooltip-arrow-left, tooltip-arrow-right: copy-tooltip-arrow-right,
70
98
  tooltip-arrow-top: copy-tooltip-arrow-top, tooltip-bottom: copy-tooltip-bottom,
71
99
  tooltip-left: copy-tooltip-left, tooltip-right: copy-tooltip-right, tooltip-top: copy-tooltip-top"
72
- label="Copy code"
100
+ copied-label=${this.copiedLabel}
101
+ label=${this.copyLabel}
73
102
  .value=${value}
74
103
  ></${this.tag('copy-button')}>`;
75
104
  }
@@ -121,12 +150,24 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
121
150
  })}<slot hidden @slotchange=${() => this.requestUpdate()}></slot>`;
122
151
  }
123
152
  };
153
+ __decorate([
154
+ property({ attribute: 'copied-label' })
155
+ ], HelixHeadlessCodeBlock.prototype, "copiedLabel", void 0);
156
+ __decorate([
157
+ property({ attribute: 'copy-label' })
158
+ ], HelixHeadlessCodeBlock.prototype, "copyLabel", void 0);
124
159
  __decorate([
125
160
  property({ reflect: true, type: Boolean })
126
161
  ], HelixHeadlessCodeBlock.prototype, "diff", void 0);
162
+ __decorate([
163
+ property({ attribute: false })
164
+ ], HelixHeadlessCodeBlock.prototype, "highlight", void 0);
127
165
  __decorate([
128
166
  property()
129
167
  ], HelixHeadlessCodeBlock.prototype, "label", void 0);
168
+ __decorate([
169
+ property({ attribute: 'line-numbers', reflect: true, type: Boolean })
170
+ ], HelixHeadlessCodeBlock.prototype, "lineNumbers", void 0);
130
171
  __decorate([
131
172
  property({ attribute: 'no-copy', reflect: true, type: Boolean })
132
173
  ], HelixHeadlessCodeBlock.prototype, "noCopy", void 0);
@@ -1,4 +1,4 @@
1
- import { AriaForwardController, type ColorFormat, HelixFormElement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, type ColorFormat, type ColorWords, HelixFormElement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import '../../color-picker/index.js';
4
4
  declare const HelixHeadlessColorInput_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinPickerFieldInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
@@ -23,6 +23,15 @@ declare const HelixHeadlessColorInput_base: (new (...args: any[]) => import("@fu
23
23
  * not survive a round trip through a formatter. Date Input does the same with
24
24
  * dates.
25
25
  *
26
+ * Typing sends `input` on each keystroke and `change` when you leave the
27
+ * field, as a text field does, so the message about a color it cannot read
28
+ * waits until you are done. Dragging in the panel sends `input` as the color
29
+ * moves and `change` when it settles.
30
+ *
31
+ * The trigger and ArrowDown open the panel with focus in the square. Tab moves
32
+ * between the panel's controls without leaving it, and Escape closes it and
33
+ * returns focus to the field.
34
+ *
26
35
  * The component sets `--color-input-swatch`, so do not set it yourself. It
27
36
  * holds the resolved color, so the styled tier can paint the swatch without
28
37
  * parsing the value.
@@ -44,7 +53,7 @@ declare const HelixHeadlessColorInput_base: (new (...args: any[]) => import("@fu
44
53
  * @event {HelixBeforeCloseEvent} helix-before-close - The panel is about to close. Cancelable: cancel it to keep it open.
45
54
  * @event {HelixBeforeOpenEvent} helix-before-open - The panel is about to open. Cancelable: cancel it to keep it closed.
46
55
  * @event {Event} input - Fired as the value changes.
47
- * @event {Event} toggle - The panel opened or closed. The event carries `newState` and `oldState`.
56
+ * @event {ToggleEvent} toggle - The panel opened or closed. The event carries `newState` and `oldState`.
48
57
  *
49
58
  * @csspart control - The text input that holds the value. Absent in the `swatch` variant.
50
59
  * @csspart feedback - The message that says what is wrong with the value.
@@ -67,10 +76,16 @@ declare const HelixHeadlessColorInput_base: (new (...args: any[]) => import("@fu
67
76
  * @csspart picker-controls - The row under the square.
68
77
  * @csspart picker-eyedropper - The control that samples a color from the screen.
69
78
  * @csspart picker-eyedropper-button - The button inside `picker-eyedropper`.
79
+ * @csspart picker-eyedropper-live - The live region of the button inside `picker-eyedropper`, which says its pending label.
70
80
  * @csspart picker-eyedropper-text - The words on the button inside `picker-eyedropper`.
81
+ * @csspart picker-field - One channel's number field with its label, in `channel-fields`.
82
+ * @csspart picker-field-input - The number input in a channel's field.
83
+ * @csspart picker-field-label - The name above a channel's number input.
84
+ * @csspart picker-fields - The row of channel number fields, in `channel-fields`.
71
85
  * @csspart picker-footer - The row holding the value and the tools.
72
86
  * @csspart picker-format - The control that changes the syntax the value is written in.
73
87
  * @csspart picker-format-button - The button inside `picker-format`.
88
+ * @csspart picker-format-live - The live region of the button inside `picker-format`, which says its pending label.
74
89
  * @csspart picker-format-text - The words on the button inside `picker-format`.
75
90
  * @csspart picker-grid - The saturation and brightness square.
76
91
  * @csspart picker-grid-brightness - The range input for the square's vertical axis.
@@ -105,6 +120,20 @@ export declare class HelixHeadlessColorInput extends HelixHeadlessColorInput_bas
105
120
  * consumer who wants autofill can still ask.
106
121
  */
107
122
  autocomplete: string;
123
+ /**
124
+ * Whether the panel shows a number field for each channel of the color.
125
+ * Passed to the panel; see Color Picker's `channel-fields`.
126
+ */
127
+ channelFields: boolean;
128
+ /**
129
+ * The words a color's name is spoken in, as JSON keyed by their English,
130
+ * such as `{"red": "rot", "vibrant": "kräftiges"}`.
131
+ *
132
+ * Passed to the panel, whose square, hue ramp and presets say the color's
133
+ * name, and read by the swatch in `swatch`, which says it before the value.
134
+ * Color Picker lists the keys.
135
+ */
136
+ colorWords: Partial<ColorWords>;
108
137
  /**
109
138
  * The syntax the value is written in: `hex`, `rgb`, or `hsl`.
110
139
  *
@@ -125,6 +154,19 @@ export declare class HelixHeadlessColorInput extends HelixHeadlessColorInput_bas
125
154
  * The text the field shows before a color is entered.
126
155
  */
127
156
  placeholder: string;
157
+ /**
158
+ * Whether the color is locked. A read-only field still submits its value.
159
+ *
160
+ * The field can be read and copied from, and the panel does not open, as on
161
+ * Date Input and Time Input.
162
+ */
163
+ readOnly: boolean;
164
+ /** Typed, so a keystroke is announced as `input` alone. See `announcesInput`. */
165
+ protected readonly announcesInput = true;
166
+ /** Requests a new value. While `readOnly` is set, nothing changes. */
167
+ requestValue(next: string): boolean;
168
+ /** Requests the panel open or closed. While `readOnly` is set, it does not open. */
169
+ requestOpen(next: boolean): boolean;
128
170
  /**
129
171
  * Colors offered under the picker, as a comma-separated list.
130
172
  */
@@ -178,6 +220,15 @@ export declare class HelixHeadlessColorInput extends HelixHeadlessColorInput_bas
178
220
  protected get anchor(): HTMLElement | null;
179
221
  /** What the picker should show, which is only ever a color. */
180
222
  private get picked();
223
+ /**
224
+ * What the swatch says in `swatch`: the color's name and then the value, or
225
+ * the trigger's words where there is no color yet.
226
+ *
227
+ * The name first, because it is what a sighted reader takes from the block of
228
+ * color, and the value after it, because it is what the field holds and what
229
+ * a reader may need to copy.
230
+ */
231
+ private get swatchWords();
181
232
  /** What the trigger's swatch paints, which is only ever a color. */
182
233
  private get painted();
183
234
  /** Relayed under this element's name, so a consumer hears one control. */
@@ -193,6 +244,13 @@ export declare class HelixHeadlessColorInput extends HelixHeadlessColorInput_bas
193
244
  * not mean.
194
245
  */
195
246
  private readonly handlePickerChange;
247
+ /**
248
+ * The picker's `change`, said under this element's name.
249
+ *
250
+ * The picker sends it when a drag, a key or a preset settles the color, so
251
+ * this field does too, and a drag is one `change` rather than one a frame.
252
+ */
253
+ private readonly handlePickerSettled;
196
254
  /**
197
255
  * The picker is about to take the pointer over, so the panel gets out of the
198
256
  * way and comes back after.