@fusion.dev/helix-headless 0.145.0 → 0.146.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 (278) hide show
  1. package/custom-elements.json +7373 -3849
  2. package/dist/accordion/item/accordion-item.d.ts +14 -0
  3. package/dist/accordion/item/accordion-item.js +16 -6
  4. package/dist/accordion/root/accordion-root.d.ts +8 -5
  5. package/dist/announcement/root/announcement-root.d.ts +3 -2
  6. package/dist/announcement/root/announcement-root.js +3 -1
  7. package/dist/app-header/root/app-header-root.d.ts +7 -2
  8. package/dist/app-header/root/app-header-root.js +9 -1
  9. package/dist/app-header/sectioning.d.ts +3 -1
  10. package/dist/app-header/sectioning.js +3 -2
  11. package/dist/avatar/group/avatar-group.d.ts +20 -14
  12. package/dist/avatar/group/avatar-group.js +17 -19
  13. package/dist/badge/root/badge-root.d.ts +3 -1
  14. package/dist/badge/root/badge-root.js +2 -2
  15. package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
  16. package/dist/bar-chart/root/bar-chart-root.js +52 -15
  17. package/dist/bar-chart/stack.d.ts +15 -0
  18. package/dist/bar-chart/stack.js +19 -0
  19. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +25 -0
  20. package/dist/breadcrumbs/root/breadcrumbs-root.js +50 -3
  21. package/dist/button/root/button-root.d.ts +26 -0
  22. package/dist/button/root/button-root.js +38 -18
  23. package/dist/button-group/root/button-group-root.d.ts +2 -1
  24. package/dist/button-group/root/button-group-root.js +5 -1
  25. package/dist/canvas/node/canvas-node.d.ts +4 -3
  26. package/dist/canvas/node/canvas-node.js +3 -2
  27. package/dist/canvas/root/canvas-root.js +2 -2
  28. package/dist/card/root/card-root.d.ts +24 -3
  29. package/dist/card/root/card-root.js +20 -8
  30. package/dist/carousel/root/carousel-root.d.ts +43 -4
  31. package/dist/carousel/root/carousel-root.js +40 -12
  32. package/dist/carousel/stops.d.ts +20 -0
  33. package/dist/carousel/stops.js +30 -0
  34. package/dist/chat/message/chat-message.js +5 -4
  35. package/dist/chat/naming.d.ts +5 -1
  36. package/dist/chat/naming.js +4 -2
  37. package/dist/chat/root/chat-root.d.ts +25 -3
  38. package/dist/chat/root/chat-root.js +22 -5
  39. package/dist/checkbox/root/checkbox-root.d.ts +20 -0
  40. package/dist/checkbox/root/checkbox-root.js +14 -1
  41. package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
  42. package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
  43. package/dist/checkbox-group/select-all.d.ts +27 -0
  44. package/dist/checkbox-group/select-all.js +12 -0
  45. package/dist/code-block/highlight.d.ts +15 -0
  46. package/dist/code-block/highlight.js +4 -0
  47. package/dist/code-block/root/code-block-root.d.ts +49 -1
  48. package/dist/code-block/root/code-block-root.js +58 -3
  49. package/dist/color-input/root/color-input-root.d.ts +3 -0
  50. package/dist/color-input/root/color-input-root.js +6 -3
  51. package/dist/color-picker/root/color-picker-root.d.ts +33 -4
  52. package/dist/color-picker/root/color-picker-root.js +80 -21
  53. package/dist/color-picker/swatches.d.ts +12 -0
  54. package/dist/color-picker/swatches.js +26 -0
  55. package/dist/combobox/root/combobox-root.d.ts +43 -0
  56. package/dist/combobox/root/combobox-root.js +79 -15
  57. package/dist/command/root/command-root.d.ts +16 -1
  58. package/dist/command/root/command-root.js +22 -4
  59. package/dist/copy-button/root/copy-button-root.d.ts +5 -0
  60. package/dist/copy-button/root/copy-button-root.js +10 -3
  61. package/dist/data-table/index.d.ts +1 -1
  62. package/dist/data-table/index.js +1 -1
  63. package/dist/data-table/keys.d.ts +24 -0
  64. package/dist/data-table/keys.js +24 -0
  65. package/dist/data-table/root/data-table-root.d.ts +27 -18
  66. package/dist/data-table/root/data-table-root.js +20 -52
  67. package/dist/data-table/tree.d.ts +16 -1
  68. package/dist/data-table/tree.js +2 -3
  69. package/dist/date-input/root/date-input-root.d.ts +3 -1
  70. package/dist/date-input/root/date-input-root.js +18 -7
  71. package/dist/date-picker/root/date-picker-root.js +12 -6
  72. package/dist/dialog/description.js +15 -1
  73. package/dist/dialog/root/dialog-root.d.ts +8 -2
  74. package/dist/dialog/root/dialog-root.js +16 -1
  75. package/dist/divider/root/divider-root.d.ts +3 -0
  76. package/dist/divider/root/divider-root.js +2 -1
  77. package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
  78. package/dist/donut-chart/root/donut-chart-root.js +48 -1
  79. package/dist/drawer/reveal.d.ts +8 -0
  80. package/dist/drawer/reveal.js +1 -0
  81. package/dist/drawer/root/drawer-root.d.ts +59 -0
  82. package/dist/drawer/root/drawer-root.js +63 -4
  83. package/dist/drilldown/item/drilldown-item.js +1 -1
  84. package/dist/drilldown/root/drilldown-root.d.ts +21 -3
  85. package/dist/drilldown/root/drilldown-root.js +21 -3
  86. package/dist/element-events.generated.js +31 -5
  87. package/dist/empty/root/empty-root.d.ts +3 -1
  88. package/dist/empty/root/empty-root.js +3 -2
  89. package/dist/file-input/root/file-input-root.d.ts +69 -6
  90. package/dist/file-input/root/file-input-root.js +82 -19
  91. package/dist/file-input/screen.d.ts +2 -1
  92. package/dist/filter-input/menu/filter-menu.d.ts +2 -0
  93. package/dist/filter-input/menu/filter-menu.js +12 -4
  94. package/dist/filter-input/root/filter-input-root.d.ts +30 -6
  95. package/dist/filter-input/root/filter-input-root.js +1 -1
  96. package/dist/filter-input/suggest.d.ts +28 -3
  97. package/dist/filter-input/suggest.js +18 -8
  98. package/dist/format-date/root/format-date-root.d.ts +9 -16
  99. package/dist/format-date/root/format-date-root.js +10 -27
  100. package/dist/heatmap/root/heatmap-root.d.ts +24 -13
  101. package/dist/heatmap/root/heatmap-root.js +34 -12
  102. package/dist/icon/root/icon-root.d.ts +12 -1
  103. package/dist/icon/root/icon-root.js +21 -10
  104. package/dist/icon/settle.d.ts +7 -0
  105. package/dist/icon/settle.js +10 -0
  106. package/dist/icon-button/root/icon-button-root.d.ts +2 -0
  107. package/dist/image/root/image-root.d.ts +5 -1
  108. package/dist/image/root/image-root.js +1 -1
  109. package/dist/input/root/input-root.d.ts +12 -2
  110. package/dist/input/root/input-root.js +11 -2
  111. package/dist/kbd/root/kbd-root.d.ts +35 -1
  112. package/dist/kbd/root/kbd-root.js +23 -4
  113. package/dist/legend/root/legend-root.d.ts +55 -8
  114. package/dist/legend/root/legend-root.js +55 -13
  115. package/dist/lightbox/root/lightbox-root.d.ts +49 -6
  116. package/dist/lightbox/root/lightbox-root.js +86 -19
  117. package/dist/lightbox/zoom-controller.d.ts +59 -0
  118. package/dist/lightbox/zoom-controller.js +128 -0
  119. package/dist/lightbox/zoom.d.ts +22 -0
  120. package/dist/lightbox/zoom.js +16 -0
  121. package/dist/line-chart/root/line-chart-root.d.ts +22 -1
  122. package/dist/line-chart/root/line-chart-root.js +21 -1
  123. package/dist/list/item/list-item.d.ts +2 -0
  124. package/dist/list/item/list-item.js +11 -2
  125. package/dist/list/root/list-root.d.ts +62 -13
  126. package/dist/list/root/list-root.js +70 -13
  127. package/dist/list/selection.d.ts +37 -7
  128. package/dist/list/selection.js +16 -7
  129. package/dist/listbox/root/listbox-root.d.ts +37 -1
  130. package/dist/listbox/root/listbox-root.js +49 -3
  131. package/dist/loader/busy.d.ts +10 -0
  132. package/dist/loader/busy.js +11 -0
  133. package/dist/loader/root/loader-root.d.ts +9 -2
  134. package/dist/loader/root/loader-root.js +23 -3
  135. package/dist/megamenu/root/megamenu-root.d.ts +51 -10
  136. package/dist/megamenu/root/megamenu-root.js +76 -5
  137. package/dist/menu/item/menu-item.d.ts +51 -2
  138. package/dist/menu/item/menu-item.js +47 -23
  139. package/dist/menu/root/menu-root.d.ts +14 -0
  140. package/dist/menu/root/menu-root.js +2 -2
  141. package/dist/meter/root/meter-root.d.ts +20 -1
  142. package/dist/meter/root/meter-root.js +11 -15
  143. package/dist/navigation/root/navigation-root.d.ts +2 -1
  144. package/dist/navigation/root/navigation-root.js +2 -2
  145. package/dist/notifications/root/notifications-root.d.ts +10 -3
  146. package/dist/notifications/root/notifications-root.js +19 -7
  147. package/dist/number-input/root/number-input-root.d.ts +17 -8
  148. package/dist/number-input/root/number-input-root.js +2 -7
  149. package/dist/object-inspector/root/object-inspector-root.d.ts +75 -27
  150. package/dist/object-inspector/root/object-inspector-root.js +117 -76
  151. package/dist/object-inspector/rows.d.ts +18 -0
  152. package/dist/object-inspector/rows.js +33 -0
  153. package/dist/option/root/option-root.d.ts +5 -3
  154. package/dist/outline/root/outline-root.d.ts +18 -0
  155. package/dist/outline/root/outline-root.js +23 -5
  156. package/dist/pagination/size/pagination-size.d.ts +1 -0
  157. package/dist/pagination/size/pagination-size.js +1 -1
  158. package/dist/pin-input/code.d.ts +10 -0
  159. package/dist/pin-input/code.js +13 -0
  160. package/dist/pin-input/root/pin-input-root.d.ts +25 -1
  161. package/dist/pin-input/root/pin-input-root.js +10 -11
  162. package/dist/popover/hide-outside.d.ts +14 -0
  163. package/dist/popover/hide-outside.js +41 -0
  164. package/dist/popover/root/popover-root.d.ts +57 -7
  165. package/dist/popover/root/popover-root.js +58 -3
  166. package/dist/progress/root/progress-root.d.ts +20 -0
  167. package/dist/progress/root/progress-root.js +15 -15
  168. package/dist/qr-code/export.d.ts +26 -1
  169. package/dist/qr-code/export.js +14 -0
  170. package/dist/qr-code/root/qr-code-root.d.ts +19 -5
  171. package/dist/qr-code/root/qr-code-root.js +58 -9
  172. package/dist/quote/marks.d.ts +8 -0
  173. package/dist/quote/marks.js +5 -0
  174. package/dist/quote/root/quote-root.d.ts +14 -2
  175. package/dist/quote/root/quote-root.js +23 -1
  176. package/dist/radio/root/radio-root.d.ts +6 -2
  177. package/dist/radio/root/radio-root.js +6 -1
  178. package/dist/rating/root/rating-root.d.ts +9 -4
  179. package/dist/rating/root/rating-root.js +31 -7
  180. package/dist/rating/steps.d.ts +7 -0
  181. package/dist/rating/steps.js +9 -0
  182. package/dist/scatter-chart/fit.d.ts +15 -0
  183. package/dist/scatter-chart/fit.js +35 -0
  184. package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
  185. package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
  186. package/dist/scroll-area/root/scroll-area-root.d.ts +22 -51
  187. package/dist/scroll-area/root/scroll-area-root.js +57 -173
  188. package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
  189. package/dist/scroll-area/scrollbar-controller.js +172 -0
  190. package/dist/scroll-area/scrollbar.d.ts +27 -0
  191. package/dist/scroll-area/scrollbar.js +9 -0
  192. package/dist/select/root/select-root.d.ts +15 -0
  193. package/dist/select/root/select-root.js +18 -6
  194. package/dist/skeleton/root/skeleton-root.d.ts +3 -0
  195. package/dist/skeleton/root/skeleton-root.js +4 -2
  196. package/dist/skip-link/root/skip-link-root.js +2 -2
  197. package/dist/slider/root/slider-root.d.ts +41 -4
  198. package/dist/slider/root/slider-root.js +23 -3
  199. package/dist/sparkline/readings.d.ts +18 -0
  200. package/dist/sparkline/readings.js +19 -0
  201. package/dist/sparkline/root/sparkline-root.d.ts +78 -7
  202. package/dist/sparkline/root/sparkline-root.js +118 -23
  203. package/dist/speed-dial/root/speed-dial-root.js +2 -2
  204. package/dist/splitter/root/splitter-root.d.ts +7 -12
  205. package/dist/splitter/root/splitter-root.js +209 -204
  206. package/dist/stat/root/stat-root.d.ts +14 -5
  207. package/dist/stat/root/stat-root.js +21 -5
  208. package/dist/steps/reach.d.ts +5 -0
  209. package/dist/steps/reach.js +3 -0
  210. package/dist/steps/root/steps-root.d.ts +49 -3
  211. package/dist/steps/root/steps-root.js +44 -5
  212. package/dist/steps/step/step.d.ts +7 -0
  213. package/dist/steps/step/step.js +7 -2
  214. package/dist/switch/root/switch-root.d.ts +10 -0
  215. package/dist/table/column/table-column.d.ts +0 -10
  216. package/dist/table/column/table-column.js +3 -19
  217. package/dist/table/root/table-root.d.ts +31 -10
  218. package/dist/table/root/table-root.js +2 -13
  219. package/dist/tabs/panel/tab-panel.d.ts +16 -3
  220. package/dist/tabs/panel/tab-panel.js +34 -5
  221. package/dist/tabs/root/tabs-root.d.ts +12 -0
  222. package/dist/tabs/root/tabs-root.js +1 -1
  223. package/dist/tabs/tab/tab.d.ts +5 -0
  224. package/dist/tabs/tab/tab.js +5 -2
  225. package/dist/tag/group/tag-group.d.ts +31 -4
  226. package/dist/tag/group/tag-group.js +46 -7
  227. package/dist/tag/root/tag-root.js +9 -2
  228. package/dist/textarea/root/textarea-root.d.ts +28 -1
  229. package/dist/textarea/root/textarea-root.js +40 -1
  230. package/dist/time-input/root/time-input-root.d.ts +5 -1
  231. package/dist/time-input/root/time-input-root.js +16 -8
  232. package/dist/time-picker/root/time-picker-root.d.ts +18 -4
  233. package/dist/time-picker/root/time-picker-root.js +7 -10
  234. package/dist/time-picker/wheel-name.d.ts +9 -0
  235. package/dist/time-picker/wheel-name.js +15 -0
  236. package/dist/timeline/group/timeline-group.js +2 -2
  237. package/dist/toast/item/toast-item.d.ts +14 -1
  238. package/dist/toast/item/toast-item.js +22 -5
  239. package/dist/toast/root/toast-root.d.ts +6 -0
  240. package/dist/toast/root/toast-root.js +16 -1
  241. package/dist/toggle/group/toggle-group.d.ts +24 -3
  242. package/dist/toggle/group/toggle-group.js +34 -5
  243. package/dist/tooltip/root/tooltip-root.d.ts +13 -2
  244. package/dist/tooltip/root/tooltip-root.js +9 -1
  245. package/dist/tour/back.d.ts +10 -0
  246. package/dist/tour/back.js +8 -0
  247. package/dist/tour/root/tour-root.d.ts +30 -2
  248. package/dist/tour/root/tour-root.js +34 -8
  249. package/dist/tree/item/tree-item.d.ts +7 -3
  250. package/dist/tree/item/tree-item.js +3 -0
  251. package/dist/tree/root/tree-root.d.ts +24 -3
  252. package/dist/tree/root/tree-root.js +32 -13
  253. package/dist/tree/selection.js +2 -15
  254. package/dist/trend/root/trend-root.d.ts +43 -18
  255. package/dist/trend/root/trend-root.js +31 -6
  256. package/dist/video/media-events.d.ts +13 -18
  257. package/dist/video/media-events.js +1 -5
  258. package/dist/video/root/video-root.d.ts +18 -5
  259. package/dist/video/root/video-root.js +19 -10
  260. package/dist/video-playlist/menu/video-playlist-menu.d.ts +2 -0
  261. package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
  262. package/dist/video-playlist/root/video-playlist-root.d.ts +7 -1
  263. package/dist/virtual-list/fill.d.ts +0 -8
  264. package/dist/virtual-list/fill.js +1 -17
  265. package/dist/virtual-list/plan.d.ts +49 -0
  266. package/dist/virtual-list/plan.js +16 -0
  267. package/dist/virtual-list/root/virtual-list-root.d.ts +114 -13
  268. package/dist/virtual-list/root/virtual-list-root.js +183 -40
  269. package/lint.json +1 -1
  270. package/package.json +8 -8
  271. package/types/jsx.d.ts +4577 -835
  272. package/types/vue.d.ts +926 -168
  273. package/dist/chat/relative-clock.d.ts +0 -39
  274. package/dist/chat/relative-clock.js +0 -31
  275. package/dist/data-table/root/order.d.ts +0 -141
  276. package/dist/data-table/root/order.js +0 -76
  277. package/dist/tag/selection.d.ts +0 -10
  278. package/dist/tag/selection.js +0 -12
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { customElement, HelixElement, hostAria, MixinControllerActive, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
- import { canReach } from '../reach.js';
10
+ import { canReach, progressOf } from '../reach.js';
11
11
  let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(HelixElement) {
12
12
  constructor() {
13
13
  super(...arguments);
@@ -17,7 +17,8 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
17
17
  if (event.defaultPrevented || !this.steps.includes(event.target)) {
18
18
  return;
19
19
  }
20
- if (!this.reachable(this.steps.indexOf(event.target))) {
20
+ const index = this.steps.indexOf(event.target);
21
+ if (!this.reachable(index) || !this.valid(index)) {
21
22
  return;
22
23
  }
23
24
  this.requestActive(event.detail.value);
@@ -27,6 +28,9 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
27
28
  this.lock();
28
29
  };
29
30
  }
31
+ get progress() {
32
+ return progressOf(this.steps);
33
+ }
30
34
  get steps() {
31
35
  return [...this.querySelectorAll(':scope > *')].filter((one) => 'current' in one);
32
36
  }
@@ -46,11 +50,20 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
46
50
  index += delta;
47
51
  }
48
52
  const target = steps[index];
49
- if (!target || !this.reachable(index)) {
53
+ if (!target || !this.reachable(index) || !this.valid(index)) {
50
54
  return false;
51
55
  }
52
56
  return this.requestActive(target.value);
53
57
  }
58
+ valid(index) {
59
+ const from = this.steps[this.at];
60
+ if (!from || index <= this.at || !this.validate || from.optional) {
61
+ return true;
62
+ }
63
+ const valid = this.validate(from);
64
+ from.invalid = !valid;
65
+ return valid;
66
+ }
54
67
  reachable(index) {
55
68
  return !this.linear || canReach(this.steps, this.at, index);
56
69
  }
@@ -79,7 +92,10 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
79
92
  connectedCallback() {
80
93
  super.connectedCallback();
81
94
  this.addEventListener('helix-select', this.handleSelection);
82
- this.watcher = new MutationObserver(() => this.lock());
95
+ this.watcher = new MutationObserver(() => {
96
+ this.lock();
97
+ this.requestUpdate();
98
+ });
83
99
  this.watcher.observe(this, {
84
100
  attributeFilter: ['complete', 'current', 'optional'],
85
101
  attributes: true,
@@ -92,9 +108,18 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
92
108
  this.watcher?.disconnect();
93
109
  this.watcher = undefined;
94
110
  }
111
+ get known() {
112
+ return this.knownChildren.filter((one) => 'current' in one);
113
+ }
95
114
  willUpdate(changed) {
96
115
  super.willUpdate(changed);
97
116
  hostAria(this.internals, { label: this.label, role: 'list' });
117
+ const known = this.known;
118
+ this.toggleState('complete', known.length > 0 && known.every((step) => step.complete));
119
+ }
120
+ firstUpdated(changed) {
121
+ super.firstUpdated(changed);
122
+ this.finishHydration();
98
123
  }
99
124
  updated(changed) {
100
125
  super.updated(changed);
@@ -106,7 +131,18 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
106
131
  }
107
132
  }
108
133
  render() {
109
- return html `<slot @slotchange=${this.handleSlotChange}></slot>`;
134
+ const progress = progressOf(this.known);
135
+ return html `<slot @slotchange=${this.handleSlotChange}></slot>
136
+ <div
137
+ part="progress"
138
+ role="progressbar"
139
+ aria-label=${this.label}
140
+ aria-valuemin="0"
141
+ aria-valuemax="100"
142
+ aria-valuenow=${progress}
143
+ style="--steps-progress: ${progress}%"
144
+ hidden
145
+ ></div>`;
110
146
  }
111
147
  };
112
148
  __decorate([
@@ -118,6 +154,9 @@ __decorate([
118
154
  __decorate([
119
155
  property({ reflect: true })
120
156
  ], HelixHeadlessSteps.prototype, "orientation", void 0);
157
+ __decorate([
158
+ property({ attribute: false })
159
+ ], HelixHeadlessSteps.prototype, "validate", void 0);
121
160
  __decorate([
122
161
  property({ reflect: true })
123
162
  ], HelixHeadlessSteps.prototype, "variant", void 0);
@@ -50,6 +50,8 @@ import '../../button/index.js';
50
50
  * @csspart mark - The glyph inside the marker: a tick, a dot, or an empty ring.
51
51
  * @csspart marker - The shape carrying the number or the check.
52
52
  * @csspart state - The words that describe a finished stage's button. Hidden.
53
+ *
54
+ * @cssstate invalid - The sequence's `validate` last answered that this stage is not valid.
53
55
  */
54
56
  export declare class HelixHeadlessStep extends HelixElement {
55
57
  /**
@@ -69,6 +71,11 @@ export declare class HelixHeadlessStep extends HelixElement {
69
71
  * Whether the stage is disabled, so the user cannot go to it.
70
72
  */
71
73
  disabled: boolean;
74
+ /**
75
+ * @internal Set by the sequence: whether its `validate` last answered that
76
+ * this stage is not valid. Recorded as `:state(invalid)`.
77
+ */
78
+ invalid: boolean;
72
79
  /**
73
80
  * @internal Set by a linear sequence: whether the stage is out of reach
74
81
  * until the ones before it are finished. A property, because the sequence
@@ -4,7 +4,7 @@ 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, drawStatus, HelixElement, HelixSelectEvent, hostAria, StatusController, } from '@fusion.dev/helix-core';
7
+ import { customElement, drawStatus, HelixElement, HelixSelectEvent, hostAria, StatusController, slottedWords, } from '@fusion.dev/helix-core';
8
8
  import { check, circle, record } from '@fusion.dev/helix-icons';
9
9
  import { nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -18,6 +18,7 @@ let HelixHeadlessStep = class HelixHeadlessStep extends HelixElement {
18
18
  this.completeLabel = 'Complete';
19
19
  this.current = false;
20
20
  this.disabled = false;
21
+ this.invalid = false;
21
22
  this.locked = false;
22
23
  this.optional = false;
23
24
  this.value = '';
@@ -40,11 +41,12 @@ let HelixHeadlessStep = class HelixHeadlessStep extends HelixElement {
40
41
  willUpdate(changed) {
41
42
  super.willUpdate(changed);
42
43
  hostAria(this.internals, { role: 'listitem' });
44
+ this.toggleState('invalid', this.invalid);
43
45
  }
44
46
  updated(changed) {
45
47
  super.updated(changed);
46
48
  if (changed.get('complete') === false && this.complete) {
47
- const name = (this.textContent ?? '').replace(/\s+/g, ' ').trim();
49
+ const name = slottedWords(this, ['']);
48
50
  this.status.say(name === '' ? this.completeLabel : `${name}, ${this.completeLabel}`);
49
51
  }
50
52
  }
@@ -84,6 +86,9 @@ __decorate([
84
86
  __decorate([
85
87
  property({ reflect: true, type: Boolean })
86
88
  ], HelixHeadlessStep.prototype, "disabled", void 0);
89
+ __decorate([
90
+ property({ attribute: false })
91
+ ], HelixHeadlessStep.prototype, "invalid", void 0);
87
92
  __decorate([
88
93
  property({ attribute: false })
89
94
  ], HelixHeadlessStep.prototype, "locked", void 0);
@@ -18,6 +18,16 @@ declare const HelixHeadlessSwitch_base: (new (...args: any[]) => import("@fusion
18
18
  * press, the same as a checkbox. The hint and the message go below the row,
19
19
  * because the switch and its label share one line.
20
20
  *
21
+ * **Keyboard.** The switch is one tab stop.
22
+ *
23
+ * | Key | What it does |
24
+ * |---|---|
25
+ * | Space | Turns the switch on or off, as a native checkbox does. |
26
+ *
27
+ * The input carries `role="switch"`, so a screen reader says "on" or "off".
28
+ * `aria-readonly` is set under `readonly`, and `aria-invalid` and
29
+ * `aria-describedby` point at the message while one shows.
30
+ *
21
31
  * @since 0.1.0
22
32
  * @status stable
23
33
  * @category forms
@@ -10,16 +10,6 @@ import { type PropertyValues, type TemplateResult } from 'lit';
10
10
  * `undefined` falls back to the field.
11
11
  */
12
12
  export type CellReader = (row: Readonly<Record<string, unknown>>) => unknown;
13
- /**
14
- * A dot path resolved against a row.
15
- *
16
- * Written here rather than taken from a library, because the whole of what is
17
- * needed is "walk the keys and stop at the first thing that is not an object".
18
- * Returns `undefined` for a path that does not resolve, which the table renders
19
- * as an empty cell: a missing key is a hole in the data and drawing `undefined`
20
- * into a table tells a reader the software is broken rather than the row is.
21
- */
22
- export declare const at: (row: Readonly<Record<string, unknown>>, path: string) => unknown;
23
13
  /**
24
14
  * The edge a column names, where it names one of the three.
25
15
  *
@@ -5,27 +5,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  var HelixHeadlessTableColumn_1;
8
- import { customElement, fillTemplate, HelixBeforeResizeEvent, HelixElement, HelixResizedEvent, hostAria, inlineStep, isRtl, requestChange, } from '@fusion.dev/helix-core';
8
+ import { customElement, fillTemplate, HelixBeforeResizeEvent, HelixElement, HelixResizedEvent, hostAria, inlineStep, isRtl, requestChange, valueAt, } from '@fusion.dev/helix-core';
9
9
  import { dotsThreeVertical } from '@fusion.dev/helix-icons';
10
10
  import { html, nothing } from 'lit';
11
11
  import { property, state } from 'lit/decorators.js';
12
12
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
13
- export const at = (row, path) => {
14
- if (path === '') {
15
- return undefined;
16
- }
17
- if (!path.includes('.')) {
18
- return row[path];
19
- }
20
- let cursor = row;
21
- for (const key of path.split('.')) {
22
- if (cursor === null || typeof cursor !== 'object') {
23
- return undefined;
24
- }
25
- cursor = cursor[key];
26
- }
27
- return cursor;
28
- };
29
13
  const EDGES = new Set(['center', 'end', 'start']);
30
14
  export const edgeOf = (align) => align && EDGES.has(align) ? align : undefined;
31
15
  let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixElement {
@@ -96,11 +80,11 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
96
80
  }
97
81
  read(row) {
98
82
  const rendered = this.cell?.(row);
99
- return rendered === undefined ? at(row, this.field) : rendered;
83
+ return rendered === undefined ? valueAt(row, this.field) : rendered;
100
84
  }
101
85
  order(row) {
102
86
  const compared = this.compare?.(row);
103
- return compared === undefined ? at(row, this.field) : compared;
87
+ return compared === undefined ? valueAt(row, this.field) : compared;
104
88
  }
105
89
  willUpdate(changed) {
106
90
  super.willUpdate(changed);
@@ -17,21 +17,42 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
17
17
  * `rowheader` for a `header` cell in a row of values. Rows are
18
18
  * `display: contents`, so their cells become items of the one grid.
19
19
  *
20
- * A column with `sortable` and a `field` sorts the rows by the text of its
21
- * cells, numbers by their value. Your markup is not reordered: the table draws
22
- * the rows in the sorted order. `helix-sort` asks first, so you can refuse it
23
- * and reorder the rows yourself.
20
+ * **Sorting.** A column with `sortable` and a `field` draws its heading as a
21
+ * button that sorts the rows by the text of its cells, numbers by their value.
22
+ * Your markup is not reordered: the table draws the rows in the sorted order.
23
+ *
24
+ * 1. Each press cycles the column through ascending, descending, and the
25
+ * order the rows were written in, which keeps a server's own ranking
26
+ * reachable.
27
+ * 2. `helix-sort` asks first, with `field:direction`, or empty for the written
28
+ * order. Refuse it to keep the order, or to sort the rows yourself and set
29
+ * `sort`.
30
+ * 3. `helix-sorted` follows once the order stands, and `sort` holds it.
31
+ * 4. The heading carries `aria-sort`, and a screen reader hears `sorted-label`
32
+ * ("Sorted by Name, ascending") or `unsorted-label` from a polite region.
33
+ *
34
+ * Tab reaches each sort button, and Enter or Space presses it.
24
35
  *
25
36
  * The `heading` slot names the table: slot a heading or a line of text into
26
37
  * it, and the table is named by its words. An `aria-label` or `aria-labelledby` on the
27
38
  * host wins over it.
28
39
  *
29
- * `selectable` adds a column of checkboxes. Each row is known by its `value`,
30
- * and `selected` holds the chosen keys, comma separated, the same shape
31
- * `DataTable` uses. The checkbox in the heading selects every row. For a grid
32
- * a reader moves through with the arrow keys, with typeahead and range
33
- * selection, use `DataTable`. To act on one row, put a link or a button in a
34
- * cell.
40
+ * **Selecting.** `selectable` adds a column of checkboxes.
41
+ *
42
+ * 1. Each row is known by its `value`, or by its place among the rows where it
43
+ * has none, and `selected` holds the chosen keys, comma separated, the same
44
+ * shape `DataTable` uses. `default-selected` is where it starts.
45
+ * 2. A row's checkbox is named by `select-row-label` ("Select {row}") with the
46
+ * words of the row's first cell. The checkbox in the heading selects every
47
+ * row, and shows a dash while only some are chosen.
48
+ * 3. `helix-select` asks first, with every key the change would leave.
49
+ * Refuse it to keep the selection. `helix-selected` follows once it stands.
50
+ * 4. A chosen row takes `:state(selected)`, and a screen reader hears
51
+ * `selected-label` ("2 selected") from a polite region.
52
+ *
53
+ * Tab reaches each checkbox, and Space ticks it. For a grid a reader moves
54
+ * through with the arrow keys, with typeahead and range selection, use
55
+ * `DataTable`. To act on one row, put a link or a button in a cell.
35
56
  *
36
57
  * The CSS custom properties listed for this component are written by it and
37
58
  * read by the stylesheet that draws it. Do not set them. Each holds a number
@@ -4,12 +4,11 @@ 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 { AriaForwardController, commaList, customElement, fillTemplate, HelixElement, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, MixinCollection, reflectElements, requestChange, splitValues, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, commaList, customElement, cycle, fillTemplate, format, HelixElement, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, MixinCollection, parse, reflectElements, requestChange, sort, splitValues, toggleEvery, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
10
  import { html } from 'lit/static-html.js';
11
11
  import '../../checkbox/index.js';
12
- import { cycle, format, parse, sort } from '../../data-table/root/order.js';
13
12
  import { edgeOf } from '../column/table-column.js';
14
13
  const tracksOf = (list, wanted) => {
15
14
  const words = splitValues(list, ' ');
@@ -78,17 +77,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
78
77
  const keys = this.chosen;
79
78
  if (root === this.renderRoot) {
80
79
  event.preventDefault();
81
- const every = this.keyed.map(({ key }) => key);
82
- const all = every.length > 0 && every.every((key) => keys.has(key));
83
- for (const key of every) {
84
- if (all) {
85
- keys.delete(key);
86
- }
87
- else {
88
- keys.add(key);
89
- }
90
- }
91
- this.requestSelected(keys);
80
+ this.requestSelected(new Set(toggleEvery(keys, this.keyed.map(({ key }) => key))));
92
81
  return;
93
82
  }
94
83
  const found = this.keyed.find(({ row }) => row.shadowRoot === root);
@@ -10,8 +10,10 @@ import { type PropertyValues, type TemplateResult } from 'lit';
10
10
  *
11
11
  * The host is the `tabpanel` while its tab is selected, through
12
12
  * `ElementInternals`, so the tab's `aria-controls` can reach it from the tab's
13
- * shadow root. The box inside takes the focus, for a panel with nothing
14
- * focusable in it.
13
+ * shadow root. The box inside is a tab stop only while the panel holds nothing
14
+ * focusable, as the ARIA tabs pattern and React Aria's tab panel do: Tab from
15
+ * the tab list lands on the panel's first link or control where there is one,
16
+ * and on the panel itself where there is none.
15
17
  *
16
18
  * @since 0.1.0
17
19
  * @status stable
@@ -20,7 +22,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
20
22
  *
21
23
  * @slot - The panel's content.
22
24
  *
23
- * @csspart panel - The panel container, which takes the focus.
25
+ * @csspart panel - The panel container, which takes the focus while it holds nothing focusable.
24
26
  *
25
27
  * @cssstate selected - While its tab is the one selected.
26
28
  */
@@ -46,6 +48,17 @@ export declare class HelixHeadlessTabPanel extends HelixElement {
46
48
  * Pairs the panel with the tab of the same value.
47
49
  */
48
50
  value: string;
51
+ /**
52
+ * Whether the content holds a tab stop of its own, so the panel needs none.
53
+ * False on a server, which serves the panel as a stop: it cannot look.
54
+ */
55
+ private holdsStop;
56
+ /** Re-reads the content when it changes in a way that adds or removes a stop. */
57
+ private readonly watcher;
58
+ private readonly readStops;
59
+ connectedCallback(): void;
60
+ disconnectedCallback(): void;
61
+ protected updated(changed: PropertyValues): void;
49
62
  /**
50
63
  * Mirrors the chosen state where a stylesheet can select on it.
51
64
  *
@@ -4,15 +4,41 @@ 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, HelixElement, hostAria } from '@fusion.dev/helix-core';
8
- import { html } from 'lit';
9
- import { property } from 'lit/decorators.js';
7
+ import { customElement, focusableElements, HelixElement, hostAria } from '@fusion.dev/helix-core';
8
+ import { html, nothing } from 'lit';
9
+ import { property, state } from 'lit/decorators.js';
10
10
  let HelixHeadlessTabPanel = class HelixHeadlessTabPanel extends HelixElement {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  this.label = '';
14
14
  this.selected = false;
15
15
  this.value = '';
16
+ this.holdsStop = false;
17
+ this.watcher = typeof MutationObserver === 'undefined'
18
+ ? undefined
19
+ : new MutationObserver(() => this.readStops());
20
+ this.readStops = () => {
21
+ this.holdsStop = this.selected && focusableElements(this).length > 0;
22
+ };
23
+ }
24
+ connectedCallback() {
25
+ super.connectedCallback();
26
+ this.watcher?.observe(this, {
27
+ attributeFilter: ['contenteditable', 'disabled', 'hidden', 'href', 'tabindex'],
28
+ attributes: true,
29
+ childList: true,
30
+ subtree: true,
31
+ });
32
+ }
33
+ disconnectedCallback() {
34
+ super.disconnectedCallback();
35
+ this.watcher?.disconnect();
36
+ }
37
+ updated(changed) {
38
+ super.updated(changed);
39
+ if (changed.has('selected')) {
40
+ this.readStops();
41
+ }
16
42
  }
17
43
  willUpdate(changed) {
18
44
  super.willUpdate(changed);
@@ -23,9 +49,9 @@ let HelixHeadlessTabPanel = class HelixHeadlessTabPanel extends HelixElement {
23
49
  return html `<div
24
50
  part="panel"
25
51
  ?hidden=${!this.selected}
26
- tabindex="0"
52
+ tabindex=${this.holdsStop ? nothing : '0'}
27
53
  >
28
- <slot></slot>
54
+ <slot @slotchange=${this.readStops}></slot>
29
55
  </div>`;
30
56
  }
31
57
  };
@@ -38,6 +64,9 @@ __decorate([
38
64
  __decorate([
39
65
  property()
40
66
  ], HelixHeadlessTabPanel.prototype, "value", void 0);
67
+ __decorate([
68
+ state()
69
+ ], HelixHeadlessTabPanel.prototype, "holdsStop", void 0);
41
70
  HelixHeadlessTabPanel = __decorate([
42
71
  customElement('helix-headless-tab-panel')
43
72
  ], HelixHeadlessTabPanel);
@@ -28,6 +28,17 @@ declare const HelixHeadlessTabs_base: (new (...args: any[]) => import("@fusion.d
28
28
  * Each tab says which panel it controls through `aria-controls`, set as an
29
29
  * element reference to the panel's host, where the engine has reflection.
30
30
  *
31
+ * Keys, on the tab list: Left and Right Arrow move between tabs, and so do Up
32
+ * and Down; Home and End go to the first and the last. The horizontal arrows
33
+ * follow the reading direction, so on a right-to-left page Left moves on.
34
+ * Disabled tabs are passed over. Tab leaves the list for the selected panel,
35
+ * which is a tab stop only while it holds nothing focusable.
36
+ *
37
+ * The `indicator` part moves to the selected tab and carries its place and
38
+ * size, so a mark of your own can be drawn there: style the part, or slot an
39
+ * element into `indicator`, which sits inside the part and reads the same
40
+ * properties.
41
+ *
31
42
  * @since 0.1.0
32
43
  * @status stable
33
44
  * @category navigation
@@ -35,6 +46,7 @@ declare const HelixHeadlessTabs_base: (new (...args: any[]) => import("@fusion.d
35
46
  * @documentation https://fusion.dev/helix/components/tabs
36
47
  *
37
48
  * @slot - The tabs, as direct children of this element.
49
+ * @slot indicator - A mark of your own, drawn inside the `indicator` part, where `--indicator-x`, `--indicator-y`, `--indicator-inline-size` and `--indicator-block-size` reach it.
38
50
  * @slot panels - The panels, as direct children of this element. Panels inside a wrapper are not paired with tabs, because pairing reads only the direct children.
39
51
  *
40
52
  * @event {HelixActivateEvent} helix-activate - Fired after the active tab changes, so the element already holds the new value.
@@ -105,7 +105,7 @@ let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(He
105
105
  aria-orientation=${this.orientation === 'vertical' ? 'vertical' : nothing}
106
106
  >
107
107
  <slot @slotchange=${this.handleSlotChange}></slot>
108
- <span part="indicator" aria-hidden="true"></span>
108
+ <span part="indicator" aria-hidden="true"><slot name="indicator"></slot></span>
109
109
  </div>
110
110
  <div part="panels"><slot name="panels" @slotchange=${this.handleSlotChange}></slot></div>`;
111
111
  }
@@ -47,6 +47,11 @@ export declare class HelixHeadlessTab extends HelixHeadlessTab_base {
47
47
  * Where the link opens, such as `_blank`, for a tab with an `href`.
48
48
  */
49
49
  target?: string;
50
+ /**
51
+ * Moves focus to the tab's control, the button or the link inside it, so a
52
+ * script can focus the tab the way it focuses a native one.
53
+ */
54
+ focus(options?: FocusOptions): void;
50
55
  /**
51
56
  * Chooses the tab before the browser follows its link, and keeps the browser
52
57
  * from following where the choice was refused. A press with a modifier, or
@@ -4,7 +4,7 @@ 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, HelixElement, MixinSelectableItem, reflectElements, } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement, MixinSelectableItem, plainClick, reflectElements, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessTab = class HelixHeadlessTab extends MixinSelectableItem(HelixElement) {
@@ -13,7 +13,7 @@ let HelixHeadlessTab = class HelixHeadlessTab extends MixinSelectableItem(HelixE
13
13
  this.itemPart = 'tab';
14
14
  this.controls = undefined;
15
15
  this.handleLinkClick = (event) => {
16
- if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
16
+ if (!plainClick(event)) {
17
17
  return;
18
18
  }
19
19
  if (!this.select()) {
@@ -21,6 +21,9 @@ let HelixHeadlessTab = class HelixHeadlessTab extends MixinSelectableItem(HelixE
21
21
  }
22
22
  };
23
23
  }
24
+ focus(options) {
25
+ this.partNamed('tab')?.focus(options);
26
+ }
24
27
  updated(changed) {
25
28
  super.updated(changed);
26
29
  const control = this.renderRoot.querySelector('[part="tab"]');
@@ -1,7 +1,8 @@
1
- import { HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
1
+ import { HelixElement, KeyboardNavigationController, type SelectionMode } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import { HelixHeadlessTag } from '../root/tag-root.js';
4
- import { type TagSelectionMode } from '../selection.js';
4
+ /** How many tags a group lets a reader select: core's `SelectionMode`. */
5
+ export type TagSelectionMode = SelectionMode;
5
6
  /**
6
7
  * @summary A set of tags that the arrow keys move through, and that can be removed and selected from the keyboard.
7
8
  *
@@ -17,9 +18,16 @@ import { type TagSelectionMode } from '../selection.js';
17
18
  * `single` selects one at a time and `multiple` any number. `value` holds the
18
19
  * selected tags' values, separated by commas, and a change asks with
19
20
  * `helix-before-change` and tells with `change`. Enter on a tag with an
20
- * `href` follows its link. A `disabled` tag is passed over.
21
+ * `href` follows its link. A `disabled` tag is passed over. A selected tag
22
+ * that is removed leaves `value`, which then sends `change`.
21
23
  *
22
- * Name the set with `label`.
24
+ * Name the set with `label`. Each tag is named by its words alone, without
25
+ * its remove button.
26
+ *
27
+ * **Removing the last tag keeps focus in the group.** With no tags left the
28
+ * set is a `group`, and focus moves to its `empty` part,
29
+ * which holds the `empty` slot: put words there such as "No filters" for a
30
+ * reader to hear.
23
31
  *
24
32
  * @since 0.1.0
25
33
  * @status stable
@@ -27,10 +35,13 @@ import { type TagSelectionMode } from '../selection.js';
27
35
  * @documentation https://fusion.dev/helix/components/tag
28
36
  *
29
37
  * @slot - The tags, in the order they are read.
38
+ * @slot empty - Shown in place of the tags while there are none, such as "No filters".
30
39
  *
31
40
  * @event {Event} change - Fired once a press has changed which tags are selected.
32
41
  * @event {HelixBeforeChangeEvent} helix-before-change - Fired before a press changes which tags are selected, with the `value` it would leave. Cancelable.
33
42
  * @event {HelixDismissEvent} helix-dismiss - A tag's remove button was pressed, or Delete or Backspace on the focused tag. Bubbles from that tag, which is its `target`; remove the tag in response. Cancelable.
43
+ *
44
+ * @csspart empty - Holds the `empty` slot while the group has no tags, rendered only then. Takes focus when the last tag is removed.
34
45
  */
35
46
  export declare class HelixHeadlessTagGroup extends HelixElement {
36
47
  /**
@@ -93,9 +104,25 @@ export declare class HelixHeadlessTagGroup extends HelixElement {
93
104
  protected press(tag: HelixHeadlessTag): void;
94
105
  private readonly handleKeydown;
95
106
  private readonly handleClick;
107
+ /**
108
+ * What happens once a tag has asked to be removed and the page has had its
109
+ * turn: a selected tag that left takes its value out of `value`, and focus
110
+ * that the last tag took with it comes to the group's `empty` part.
111
+ *
112
+ * Asked after the event and again a frame later, as `MixinDismissible`
113
+ * asks, because a framework removes the tag on its next render, after the
114
+ * handler. A canceled dismissal changes nothing.
115
+ */
116
+ private readonly handleDismiss;
117
+ private readonly handleSlotchange;
96
118
  private readonly handleFocusin;
97
119
  connectedCallback(): void;
98
120
  disconnectedCallback(): void;
121
+ /**
122
+ * Whether the group is known to hold no tags, which a server and a
123
+ * hydrating render cannot know: there it holds whatever it was given.
124
+ */
125
+ private get empty();
99
126
  protected willUpdate(changed: PropertyValues<this>): void;
100
127
  protected updated(changed: PropertyValues<this>): void;
101
128
  protected render(): TemplateResult;