@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,9 +4,10 @@ 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, MixinCollection, splitValues } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, fillTemplate, HelixElement, HelixSortEvent, MixinCollection, requestChange, splitValues, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
- import { property } from 'lit/decorators.js';
9
+ import { property, state } from 'lit/decorators.js';
10
+ import { cycle, format, parse, sort } from '../../data-table/root/order.js';
10
11
  import { edgeOf } from '../column/table-column.js';
11
12
  const tracksOf = (list, wanted) => {
12
13
  const words = splitValues(list, ' ');
@@ -38,12 +39,36 @@ const tracksOf = (list, wanted) => {
38
39
  const SHORT = 32;
39
40
  const FLOOR = '14ch';
40
41
  const SAMPLE = 200;
41
- const lengthOf = (element) => (element?.textContent ?? '').replace(/\s+/g, ' ').trim().length;
42
+ const textOf = (element) => (element?.textContent ?? '').replace(/\s+/g, ' ').trim();
43
+ const lengthOf = (element) => textOf(element).length;
44
+ const numberOf = (value) => Number(value.replaceAll(',', ''));
42
45
  let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixElement) {
43
46
  constructor() {
44
47
  super(...arguments);
48
+ this.ascendingLabel = 'ascending';
45
49
  this.columns = '';
50
+ this.defaultSort = '';
51
+ this.descendingLabel = 'descending';
46
52
  this.label = '';
53
+ this.sortedLabel = 'Sorted by {column}, {order}';
54
+ this.unsortedLabel = 'Not sorted';
55
+ this.sortState = undefined;
56
+ this.aria = new AriaForwardController(this, {
57
+ label: true,
58
+ target: () => this.partNamed('table'),
59
+ });
60
+ this.heardSort = undefined;
61
+ this.handleHeadClick = (event) => {
62
+ const path = event.composedPath();
63
+ if (!path.some((node) => node instanceof Element && node.getAttribute('part') === 'sort')) {
64
+ return;
65
+ }
66
+ const columns = this.tableColumns;
67
+ const column = path.find((node) => columns.includes(node));
68
+ if (column?.canSort) {
69
+ this.toggleSort(column.field);
70
+ }
71
+ };
47
72
  this.handleSlotChange = () => {
48
73
  this.requestUpdate();
49
74
  };
@@ -51,6 +76,76 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
51
76
  this.alignment = undefined;
52
77
  this.aligned = '';
53
78
  }
79
+ get sort() {
80
+ return this.sortState ?? this.defaultSort;
81
+ }
82
+ set sort(next) {
83
+ const previous = this.sort;
84
+ this.sortState = next;
85
+ this.requestUpdate('sort', previous);
86
+ }
87
+ requestSort(next) {
88
+ return requestChange({
89
+ apply: (value) => {
90
+ const previous = this.sort;
91
+ this.sortState = value;
92
+ this.requestUpdate('sort', previous);
93
+ },
94
+ event: (value) => new HelixSortEvent({ value }),
95
+ host: this,
96
+ next,
97
+ });
98
+ }
99
+ toggleSort(field) {
100
+ return this.requestSort(format(cycle(parse(this.sort), field)));
101
+ }
102
+ get arrangedRows() {
103
+ const rows = this.slotted;
104
+ const spec = parse(this.sort);
105
+ const declared = this.tableColumns;
106
+ const index = spec
107
+ ? declared.findIndex((column) => column.canSort && column.field === spec.field)
108
+ : -1;
109
+ if (!spec || index < 0) {
110
+ return rows;
111
+ }
112
+ const records = rows.map((element) => ({ element, value: textOf(element.children[index]) }));
113
+ const numeric = records.every(({ value }) => value === '' || Number.isFinite(numberOf(value)));
114
+ const order = numeric
115
+ ? (row) => (row.value === '' ? '' : numberOf(row.value))
116
+ : (row) => row.value;
117
+ const sorted = sort(records, spec, [{ field: spec.field, order }]);
118
+ return sorted.map((record) => record.element);
119
+ }
120
+ news() {
121
+ const current = this.sort;
122
+ let said = this.announced;
123
+ if (this.hasUpdated && current !== this.heardSort) {
124
+ const parsed = parse(current);
125
+ const column = parsed
126
+ ? this.tableColumns.find((one) => one.field === parsed.field)
127
+ : undefined;
128
+ said = parsed
129
+ ? fillTemplate(this.sortedLabel, {
130
+ column: column?.textContent?.trim() || parsed.field,
131
+ order: parsed.direction === 'asc' ? this.ascendingLabel : this.descendingLabel,
132
+ })
133
+ : this.unsortedLabel;
134
+ }
135
+ this.heardSort = current;
136
+ return said;
137
+ }
138
+ markSorted() {
139
+ const current = parse(this.sort);
140
+ for (const column of this.tableColumns) {
141
+ column.sorted =
142
+ current && column.canSort && column.field === current.field
143
+ ? current.direction === 'asc'
144
+ ? 'ascending'
145
+ : 'descending'
146
+ : undefined;
147
+ }
148
+ }
54
149
  get tableColumns() {
55
150
  return this.knownChildren.filter((child) => 'isTableColumn' in child && child.isTableColumn === true);
56
151
  }
@@ -96,11 +191,13 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
96
191
  super.connectedCallback();
97
192
  this.watcher = new MutationObserver(() => this.requestUpdate());
98
193
  this.watcher.observe(this, { characterData: true, childList: true, subtree: true });
194
+ this.addEventListener('click', this.handleHeadClick);
99
195
  }
100
196
  disconnectedCallback() {
101
197
  super.disconnectedCallback();
102
198
  this.watcher?.disconnect();
103
199
  this.watcher = undefined;
200
+ this.removeEventListener('click', this.handleHeadClick);
104
201
  }
105
202
  static { this.shadowRootOptions = {
106
203
  ...HelixElement.shadowRootOptions,
@@ -123,7 +220,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
123
220
  return;
124
221
  }
125
222
  head.assign(...this.tableColumns);
126
- body.assign(...this.slotted);
223
+ body.assign(...this.arrangedRows);
127
224
  }
128
225
  alignCells() {
129
226
  if (typeof CSSStyleSheet === 'undefined' || !('replaceSync' in CSSStyleSheet.prototype)) {
@@ -146,10 +243,15 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
146
243
  }
147
244
  }
148
245
  }
246
+ willUpdate(changed) {
247
+ super.willUpdate(changed);
248
+ this.announced = this.news();
249
+ }
149
250
  updated(changed) {
150
251
  super.updated(changed);
151
252
  this.assign();
152
253
  this.alignCells();
254
+ this.markSorted();
153
255
  }
154
256
  render() {
155
257
  const template = this.template;
@@ -167,16 +269,37 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
167
269
  this.handleSlotChange();
168
270
  }}
169
271
  ></slot>
170
- ${this.renderStatus(this.hasRows)}
272
+ ${this.renderStatus(this.hasRows, 'cell')}
171
273
  </div>${this.renderLive(this.hasRows)}`;
172
274
  }
173
275
  };
276
+ __decorate([
277
+ property({ attribute: 'ascending-label' })
278
+ ], HelixHeadlessTable.prototype, "ascendingLabel", void 0);
174
279
  __decorate([
175
280
  property()
176
281
  ], HelixHeadlessTable.prototype, "columns", void 0);
282
+ __decorate([
283
+ property({ attribute: 'default-sort' })
284
+ ], HelixHeadlessTable.prototype, "defaultSort", void 0);
285
+ __decorate([
286
+ property({ attribute: 'descending-label' })
287
+ ], HelixHeadlessTable.prototype, "descendingLabel", void 0);
177
288
  __decorate([
178
289
  property()
179
290
  ], HelixHeadlessTable.prototype, "label", void 0);
291
+ __decorate([
292
+ property()
293
+ ], HelixHeadlessTable.prototype, "sort", null);
294
+ __decorate([
295
+ property({ attribute: 'sorted-label' })
296
+ ], HelixHeadlessTable.prototype, "sortedLabel", void 0);
297
+ __decorate([
298
+ property({ attribute: 'unsorted-label' })
299
+ ], HelixHeadlessTable.prototype, "unsortedLabel", void 0);
300
+ __decorate([
301
+ state()
302
+ ], HelixHeadlessTable.prototype, "sortState", void 0);
180
303
  HelixHeadlessTable = __decorate([
181
304
  customElement('helix-headless-table')
182
305
  ], HelixHeadlessTable);
@@ -32,6 +32,13 @@ export declare class HelixHeadlessTableRow extends HelixElement {
32
32
  */
33
33
  alignCells(rules: CSSStyleSheet): void;
34
34
  protected willUpdate(changed: PropertyValues): void;
35
+ /**
36
+ * Asks each cell to read its role again once the cells change.
37
+ *
38
+ * A `header` cell heads its row when a value sits beside it, and a cell that
39
+ * upgrades while its row is still being parsed has no value beside it yet.
40
+ */
41
+ private readonly handleSlotChange;
35
42
  protected render(): TemplateResult;
36
43
  }
37
44
  declare global {
@@ -11,6 +11,14 @@ let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
11
11
  super(...arguments);
12
12
  this.isTableRow = true;
13
13
  this.columnRules = undefined;
14
+ this.handleSlotChange = () => {
15
+ for (const cell of this.children) {
16
+ if ('isTableCell' in cell) {
17
+ ;
18
+ cell.requestUpdate();
19
+ }
20
+ }
21
+ };
14
22
  }
15
23
  alignCells(rules) {
16
24
  const root = this.renderRoot;
@@ -28,7 +36,7 @@ let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
28
36
  hostAria(this.internals, { role: 'row' });
29
37
  }
30
38
  render() {
31
- return html `<slot></slot>`;
39
+ return html `<slot @slotchange=${this.handleSlotChange}></slot>`;
32
40
  }
33
41
  };
34
42
  HelixHeadlessTableRow = __decorate([
@@ -1,4 +1,4 @@
1
- import { HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessTabs_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerActiveInterface) & typeof HelixElement;
4
4
  /**
@@ -36,8 +36,13 @@ declare const HelixHeadlessTabs_base: (new (...args: any[]) => import("@fusion.d
36
36
  export declare class HelixHeadlessTabs extends HelixHeadlessTabs_base {
37
37
  protected readonly keys: KeyboardNavigationController;
38
38
  private readonly indicator;
39
+ /** Carries a host `aria-label` and `aria-labelledby` to the tab list. */
40
+ protected readonly aria: AriaForwardController;
39
41
  /**
40
42
  * The tab list's name, read by screen readers.
43
+ *
44
+ * An `aria-label` or `aria-labelledby` on the host names the tab list too,
45
+ * and wins over this.
41
46
  */
42
47
  label: string;
43
48
  /**
@@ -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, IndicatorController, KeyboardNavigationController, MixinControllerActive, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, HelixElement, IndicatorController, KeyboardNavigationController, MixinControllerActive, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { HelixHeadlessTabPanel } from '../panel/tab-panel.js';
@@ -23,10 +23,14 @@ let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(He
23
23
  observe: () => this.tabs,
24
24
  surface: () => this.partNamed('tabs'),
25
25
  });
26
+ this.aria = new AriaForwardController(this, {
27
+ label: true,
28
+ target: () => this.partNamed('tabs'),
29
+ });
26
30
  this.label = 'Tabs';
27
31
  this.manual = false;
28
32
  this.handleSelection = (event) => {
29
- if (event.defaultPrevented) {
33
+ if (event.defaultPrevented || !this.tabs.includes(event.target)) {
30
34
  return;
31
35
  }
32
36
  this.requestActive(event.detail.value);
@@ -0,0 +1,107 @@
1
+ import { HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
2
+ import { type PropertyValues, type TemplateResult } from 'lit';
3
+ import { HelixHeadlessTag } from '../root/tag-root.js';
4
+ import { type TagSelectionMode } from '../selection.js';
5
+ /**
6
+ * @summary A set of tags that the arrow keys move through, and that can be removed and selected from the keyboard.
7
+ *
8
+ * @description
9
+ * A part of `Tag` that holds tags as one control: a grid of rows, one tab stop
10
+ * for the whole set. The arrow keys move between tags, Home and End go to the
11
+ * first and the last, and a typed letter goes to the next tag starting with
12
+ * it. Delete or Backspace removes the focused tag where it is `dismissible`,
13
+ * by sending its `helix-dismiss`: remove it from your list in the handler, and
14
+ * focus moves to the next tag, or the previous one after the last.
15
+ *
16
+ * `selection-mode` lets a reader select tags, with Space, Enter or a press:
17
+ * `single` selects one at a time and `multiple` any number. `value` holds the
18
+ * selected tags' values, separated by commas, and a change asks with
19
+ * `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
+ *
22
+ * Name the set with `label`.
23
+ *
24
+ * @since 0.1.0
25
+ * @status stable
26
+ * @aliases Tag list, Chip group, Token list
27
+ * @documentation https://fusion.dev/helix/components/tag
28
+ *
29
+ * @slot - The tags, in the order they are read.
30
+ *
31
+ * @event {Event} change - Fired once a press has changed which tags are selected.
32
+ * @event {HelixBeforeChangeEvent} helix-before-change - Fired before a press changes which tags are selected, with the `value` it would leave. Cancelable.
33
+ * @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.
34
+ */
35
+ export declare class HelixHeadlessTagGroup extends HelixElement {
36
+ /**
37
+ * The name of the set, such as "Filters", which a screen reader announces
38
+ * before its tags.
39
+ */
40
+ label: string;
41
+ /**
42
+ * How many tags a reader can select: `single`, `multiple`, or none.
43
+ *
44
+ * Absent selects nothing, and the tags carry no selected state at all.
45
+ */
46
+ selectionMode?: TagSelectionMode;
47
+ /**
48
+ * The selected tags' values, separated by commas, since a value may hold a
49
+ * space.
50
+ *
51
+ * Set it to start with tags selected. A tag's value is its `value`, or its
52
+ * words where it has none.
53
+ */
54
+ value: string;
55
+ /** The tag the reader was last on, which keeps the tab stop. */
56
+ private last;
57
+ /**
58
+ * The arrow keys, Home, End and typed letters, moving focus and choosing
59
+ * nothing. From the focused tag rather than the selection, since a reader
60
+ * moves through selected and unselected tags alike, and without wrapping, as
61
+ * a list of tags has a first and a last.
62
+ */
63
+ protected readonly keys: KeyboardNavigationController;
64
+ /** The tags the group holds, in order. */
65
+ get tags(): HelixHeadlessTag[];
66
+ /** The tags a key can land on, which are the ones that are not disabled. */
67
+ private get reachable();
68
+ /** A tag as the keyboard controller sees it: an item it moves focus to and never chooses. */
69
+ private navigable;
70
+ /**
71
+ * What a tag stands for in `value`: its own `value`, or its words.
72
+ *
73
+ * The words read off the tag's children here rather than through its
74
+ * `words`, which answers nothing until the tag's own first update: the
75
+ * group's first pass runs before that, and would match no tag.
76
+ */
77
+ private valueFor;
78
+ /**
79
+ * Tells every tag its place: whether it holds the one tab stop and whether
80
+ * it is selected. Through `whenHydrated`, so a tag a server rendered draws
81
+ * its served markup first.
82
+ */
83
+ private sync;
84
+ /** The tag a press or a key came from, read off the event's path. */
85
+ private tagOf;
86
+ /**
87
+ * Selects the tag, or lets it go, asking first.
88
+ *
89
+ * `helix-before-change` carries the `value` the press would leave, and a
90
+ * listener that refuses it keeps the selection. `change` follows once it
91
+ * has moved.
92
+ */
93
+ protected press(tag: HelixHeadlessTag): void;
94
+ private readonly handleKeydown;
95
+ private readonly handleClick;
96
+ private readonly handleFocusin;
97
+ connectedCallback(): void;
98
+ disconnectedCallback(): void;
99
+ protected willUpdate(changed: PropertyValues<this>): void;
100
+ protected updated(changed: PropertyValues<this>): void;
101
+ protected render(): TemplateResult;
102
+ }
103
+ declare global {
104
+ interface HTMLElementTagNameMap {
105
+ 'helix-headless-tag-group': HelixHeadlessTagGroup;
106
+ }
107
+ }
@@ -0,0 +1,157 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { commaList, customElement, HelixBeforeChangeEvent, HelixElement, hostAria, KeyboardNavigationController, requestChange, rovingStop, slottedWords, whenHydrated, } from '@fusion.dev/helix-core';
8
+ import { html } from 'lit';
9
+ import { property } from 'lit/decorators.js';
10
+ import { HelixHeadlessTag } from '../root/tag-root.js';
11
+ import { pressedValue } from '../selection.js';
12
+ let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
13
+ constructor() {
14
+ super(...arguments);
15
+ this.label = '';
16
+ this.value = '';
17
+ this.keys = new KeyboardNavigationController(this, {
18
+ items: () => this.reachable.map((tag) => this.navigable(tag)),
19
+ origin: 'focus',
20
+ selects: () => false,
21
+ typeahead: (item) => item.words,
22
+ wrap: false,
23
+ });
24
+ this.handleKeydown = (event) => {
25
+ const tag = this.tagOf(event);
26
+ if (!tag || tag.disabled || event.altKey || event.ctrlKey || event.metaKey) {
27
+ return;
28
+ }
29
+ if (event.key === 'Delete' || event.key === 'Backspace') {
30
+ if (tag.dismissible) {
31
+ event.preventDefault();
32
+ tag.dismiss();
33
+ }
34
+ return;
35
+ }
36
+ if (event.key === 'Enter' && tag.href !== '') {
37
+ event.preventDefault();
38
+ tag.renderRoot.querySelector('[part~="link"]')?.click();
39
+ return;
40
+ }
41
+ if ((event.key === ' ' || event.key === 'Enter') && this.selectionMode) {
42
+ event.preventDefault();
43
+ this.press(tag);
44
+ }
45
+ };
46
+ this.handleClick = (event) => {
47
+ const tag = this.tagOf(event);
48
+ const control = event
49
+ .composedPath()
50
+ .some((node) => node instanceof Element &&
51
+ /(^| )(dismiss|link)( |$)/.test(node.getAttribute('part') ?? ''));
52
+ if (tag && !control) {
53
+ this.press(tag);
54
+ }
55
+ };
56
+ this.handleFocusin = (event) => {
57
+ const tag = this.tagOf(event);
58
+ if (tag && tag !== this.last) {
59
+ this.last = tag;
60
+ this.sync();
61
+ }
62
+ };
63
+ }
64
+ get tags() {
65
+ return [...(this.children ?? [])].filter((child) => child instanceof HelixHeadlessTag);
66
+ }
67
+ get reachable() {
68
+ return this.tags.filter((tag) => !tag.disabled);
69
+ }
70
+ navigable(tag) {
71
+ return {
72
+ contains: (node) => tag.contains(node),
73
+ disabled: tag.disabled,
74
+ focusItem: () => tag.focusItem(),
75
+ select: () => { },
76
+ selected: false,
77
+ words: tag.words,
78
+ };
79
+ }
80
+ valueFor(tag) {
81
+ return tag.value || slottedWords(tag, ['start', '']);
82
+ }
83
+ sync() {
84
+ const mode = this.selectionMode ?? 'none';
85
+ const chosen = new Set(commaList(this.value));
86
+ const tags = this.tags;
87
+ const items = tags.map((tag) => ({
88
+ disabled: tag.disabled,
89
+ selected: chosen.has(this.valueFor(tag)),
90
+ tag,
91
+ }));
92
+ const holder = rovingStop(items, items.find((item) => item.tag === this.last), { disabled: (item) => item.disabled, selected: (item) => item.selected })?.tag;
93
+ for (const tag of tags) {
94
+ whenHydrated(tag, () => {
95
+ tag.focusable = tag === holder;
96
+ tag.selected = mode === 'none' ? undefined : chosen.has(this.valueFor(tag));
97
+ });
98
+ }
99
+ }
100
+ tagOf(event) {
101
+ return event
102
+ .composedPath()
103
+ .find((node) => node instanceof HelixHeadlessTag);
104
+ }
105
+ press(tag) {
106
+ const mode = this.selectionMode ?? 'none';
107
+ if (mode === 'none' || tag.disabled) {
108
+ return;
109
+ }
110
+ requestChange({
111
+ apply: (value) => {
112
+ this.value = value;
113
+ this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
114
+ },
115
+ event: (value) => new HelixBeforeChangeEvent({ value }),
116
+ host: this,
117
+ next: pressedValue(mode, this.value, this.valueFor(tag)),
118
+ });
119
+ }
120
+ connectedCallback() {
121
+ super.connectedCallback();
122
+ this.addEventListener('keydown', this.handleKeydown);
123
+ this.addEventListener('click', this.handleClick);
124
+ this.addEventListener('focusin', this.handleFocusin);
125
+ }
126
+ disconnectedCallback() {
127
+ super.disconnectedCallback();
128
+ this.removeEventListener('keydown', this.handleKeydown);
129
+ this.removeEventListener('click', this.handleClick);
130
+ this.removeEventListener('focusin', this.handleFocusin);
131
+ }
132
+ willUpdate(changed) {
133
+ super.willUpdate(changed);
134
+ hostAria(this.internals, { label: this.label, role: 'grid' });
135
+ this.internals.ariaMultiSelectable = this.selectionMode === 'multiple' ? 'true' : null;
136
+ }
137
+ updated(changed) {
138
+ super.updated(changed);
139
+ this.sync();
140
+ }
141
+ render() {
142
+ return html `<slot @slotchange=${() => this.sync()}></slot>`;
143
+ }
144
+ };
145
+ __decorate([
146
+ property()
147
+ ], HelixHeadlessTagGroup.prototype, "label", void 0);
148
+ __decorate([
149
+ property({ attribute: 'selection-mode' })
150
+ ], HelixHeadlessTagGroup.prototype, "selectionMode", void 0);
151
+ __decorate([
152
+ property()
153
+ ], HelixHeadlessTagGroup.prototype, "value", void 0);
154
+ HelixHeadlessTagGroup = __decorate([
155
+ customElement('helix-headless-tag-group')
156
+ ], HelixHeadlessTagGroup);
157
+ export { HelixHeadlessTagGroup };
@@ -1 +1,2 @@
1
+ export * from './group/tag-group.js';
1
2
  export * from './root/tag-root.js';
package/dist/tag/index.js CHANGED
@@ -1 +1,2 @@
1
+ export * from './group/tag-group.js';
1
2
  export * from './root/tag-root.js';
@@ -1,5 +1,5 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
- import { type TemplateResult } from 'lit';
2
+ import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.dev/helix-core").DismissibleElement) & typeof HelixElement;
4
4
  /**
5
5
  * @summary A short label that adds metadata to content.
@@ -12,6 +12,21 @@ declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.de
12
12
  * The remove button sends `helix-dismiss`. The tag does not remove itself,
13
13
  * because your code owns the list it is in, so remove it in your handler. A
14
14
  * listener can cancel `helix-dismiss`, and `dismiss()` then returns `false`.
15
+ * When the handler removes a tag whose remove button has focus, focus moves to
16
+ * the next tag's remove button, or to the previous one's after the last tag.
17
+ *
18
+ * The remove button is named for its tag, such as "Remove Apple", so a list of
19
+ * buttons says which tag each one removes. Write `{label}` in `dismiss-label`
20
+ * to put the tag's words somewhere else, such as `dismiss-label="{label}
21
+ * entfernen"`.
22
+ *
23
+ * `href` makes the label a link, and `disabled` takes the tag out of reach: its
24
+ * link and its remove button stop answering.
25
+ *
26
+ * **In a `Tag.Group` a tag is a row of a grid.** The group gives it its role,
27
+ * its place in the one tab stop and, where the group selects, whether it is
28
+ * selected. Its remove button leaves the tab order there, Delete and Backspace
29
+ * doing its job from the row.
15
30
  *
16
31
  * @since 0.1.0
17
32
  * @status stable
@@ -20,18 +35,85 @@ declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.de
20
35
  * @documentation https://fusion.dev/helix/components/tag
21
36
  *
22
37
  * @slot - The tag's label.
38
+ * @slot dismiss-icon - Replaces the glyph on the remove button.
23
39
  * @slot start - The category the label belongs to, shown before it in a heavier weight.
24
40
  *
25
41
  * @event {HelixDismissEvent} helix-dismiss - The remove button was pressed. The tag does not remove itself, so remove it in response. Cancelable.
26
42
  *
43
+ * @csspart cell - The grid cell around everything the tag shows, rendered only in a `Tag.Group`, where it takes focus.
27
44
  * @csspart dismiss - The button that removes the tag.
28
45
  * @csspart dismiss-mark - The icon on the remove button.
29
46
  * @csspart label - The label, which the styled tag trims to its capitals and baseline so the letters sit at the middle in any font.
47
+ * @csspart link - The link around the label, under `href`.
30
48
  * @csspart start - The category before the label.
49
+ *
50
+ * @cssstate selected - The tag is selected in a `Tag.Group` that selects.
31
51
  */
32
52
  export declare class HelixHeadlessTag extends HelixHeadlessTag_base {
33
53
  dismissLabel: string;
54
+ /**
55
+ * Takes the tag out of reach: its link and its remove button stop
56
+ * answering, and in a `Tag.Group` the arrow keys pass over it and it cannot
57
+ * be selected or removed.
58
+ */
59
+ disabled: boolean;
60
+ /**
61
+ * Whether the tag holds its group's tab stop.
62
+ *
63
+ * Written by `Tag.Group` on every tag it holds, and unset outside one, which
64
+ * is how a tag knows it is a row. No attribute: it is coordination between
65
+ * elements, the same shape `Toggle.focusable` has.
66
+ */
67
+ focusable?: boolean;
68
+ /**
69
+ * Makes the label a link to this address.
70
+ */
71
+ href: string;
72
+ /**
73
+ * Whether the tag is selected, in a `Tag.Group` that selects.
74
+ *
75
+ * Written by the group from its own `value`, and unset where nothing can be
76
+ * selected, which is what keeps `aria-selected` off a set that does not
77
+ * select.
78
+ */
79
+ selected?: boolean | undefined;
80
+ /**
81
+ * What the tag stands for in its group's `value`.
82
+ *
83
+ * Absent is the tag's own words, its category first.
84
+ */
85
+ value: string;
86
+ /** The tag's words, its category first, or none where the children are not known yet. */
87
+ get words(): string;
88
+ /** Whether a `Tag.Group` holds this tag, which makes it a row. */
89
+ private get grouped();
90
+ /**
91
+ * Moves focus to the tag: its cell in a group, and otherwise its link or
92
+ * its remove button, whichever it has.
93
+ */
94
+ focusItem(): void;
95
+ protected get returnFocusTo(): HTMLElement | null;
96
+ protected willUpdate(changed: PropertyValues<this>): void;
97
+ /**
98
+ * The remove button's name: `dismissLabel` with the tag's own words.
99
+ *
100
+ * **Named for its tag**, because a set of tags each named "Remove" is a list
101
+ * of buttons that says nothing about which tag each one takes away. The
102
+ * words are the tag's slotted text, its category first, and `{label}` in
103
+ * `dismissLabel` says where they go. Without it they follow the verb, unless
104
+ * the label already holds them, which is what a page naming each button by
105
+ * hand wrote.
106
+ *
107
+ * Read from the children, so empty on a server and while hydrating, where
108
+ * the name is the verb alone until the update after.
109
+ */
110
+ private get removeName();
111
+ protected firstUpdated(changed: PropertyValues): void;
34
112
  protected render(): TemplateResult;
113
+ /** The label, inside a link under `href`, behind a seam a tier can move. */
114
+ protected renderLabel(): TemplateResult;
115
+ /** The remove button, behind a seam a tier can move. */
116
+ protected renderDismiss(): TemplateResult;
35
117
  }
36
118
  declare global {
37
119
  interface HTMLElementTagNameMap {