@fusion.dev/helix-headless 0.166.0 → 0.167.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 (38) hide show
  1. package/custom-elements.json +2658 -481
  2. package/dist/canvas/arrange.d.ts +32 -0
  3. package/dist/canvas/arrange.js +144 -0
  4. package/dist/canvas/paste.d.ts +25 -0
  5. package/dist/canvas/paste.js +58 -0
  6. package/dist/canvas/root/canvas-root.d.ts +60 -3
  7. package/dist/canvas/root/canvas-root.js +166 -2
  8. package/dist/chat/composer/chat-composer.js +5 -1
  9. package/dist/combobox/root/combobox-root.d.ts +6 -1
  10. package/dist/combobox/root/combobox-root.js +2 -2
  11. package/dist/date-input/root/date-input-root.d.ts +1 -1
  12. package/dist/element-events.generated.js +2 -0
  13. package/dist/file-input/root/file-input-root.d.ts +1 -1
  14. package/dist/file-input/root/file-input-root.js +1 -1
  15. package/dist/format-date/root/format-date-root.d.ts +10 -3
  16. package/dist/format-date/root/format-date-root.js +6 -1
  17. package/dist/listbox/root/listbox-root.d.ts +12 -1
  18. package/dist/listbox/root/listbox-root.js +13 -1
  19. package/dist/select/root/select-root.js +1 -1
  20. package/dist/table/grid-controller.d.ts +10 -0
  21. package/dist/table/grid-controller.js +7 -0
  22. package/dist/table/root/table-root.d.ts +71 -1
  23. package/dist/table/root/table-root.js +122 -7
  24. package/dist/table/row/table-row.d.ts +17 -0
  25. package/dist/table/row/table-row.js +23 -0
  26. package/dist/time-input/root/time-input-root.d.ts +2 -1
  27. package/dist/time-input/root/time-input-root.js +1 -1
  28. package/dist/time-picker/root/time-picker-root.d.ts +48 -1
  29. package/dist/time-picker/root/time-picker-root.js +79 -21
  30. package/dist/virtual-list/root/virtual-list-root.d.ts +70 -2
  31. package/dist/virtual-list/root/virtual-list-root.js +216 -32
  32. package/dist/virtual-list/sections.d.ts +27 -0
  33. package/dist/virtual-list/sections.js +43 -0
  34. package/lint.json +1 -1
  35. package/package.json +5 -5
  36. package/types/jsx.d.ts +454 -76
  37. package/types/vue.d.ts +89 -7
  38. package/types/words.d.ts +27 -0
@@ -157,6 +157,12 @@ export declare class HelixHeadlessTableRow extends HelixElement {
157
157
  * table. Not a consumer's to set.
158
158
  */
159
159
  level: number;
160
+ /**
161
+ * @internal The row's place among the table's rows, the headings being 1,
162
+ * in a `windowed` table, which draws only some of them, and 0 otherwise.
163
+ * Written by the table. Not a consumer's to set.
164
+ */
165
+ rowIndex: number;
160
166
  /** @internal Whether rows sit under this one. Written by the table. */
161
167
  branch: boolean;
162
168
  /** @internal Whether the rows under this one are shown. Written by the table. */
@@ -177,6 +183,17 @@ export declare class HelixHeadlessTableRow extends HelixElement {
177
183
  */
178
184
  alignCells(rules: CSSStyleSheet): void;
179
185
  protected willUpdate(changed: PropertyValues): void;
186
+ /**
187
+ * Names the row by its header cell, the cell with `header` among cells of
188
+ * values, or by its first cell where it has none, as React Aria's rows are
189
+ * named.
190
+ *
191
+ * **Named from its contents, a row read out its checkbox's name too**, "Select
192
+ * 412 412 main Passed" in a `selectable` table, since the checkbox is a cell of
193
+ * the row's own. Not on a server, which has no cells to point at, and not
194
+ * where a page named the row itself.
195
+ */
196
+ private nameByHeader;
180
197
  connectedCallback(): void;
181
198
  disconnectedCallback(): void;
182
199
  /**
@@ -31,6 +31,7 @@ let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
31
31
  this.gridCell = false;
32
32
  this.selectStop = false;
33
33
  this.level = 0;
34
+ this.rowIndex = 0;
34
35
  this.branch = false;
35
36
  this.open = false;
36
37
  this.expandLabel = '';
@@ -53,6 +54,7 @@ let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
53
54
  followLink(this.ownerDocument, { href: this.href, rel: this.rel, target: this.target }, event);
54
55
  };
55
56
  this.handleSlotChange = () => {
57
+ this.requestUpdate();
56
58
  for (const cell of this.children) {
57
59
  if ('isTableCell' in cell) {
58
60
  ;
@@ -75,8 +77,10 @@ let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
75
77
  willUpdate(changed) {
76
78
  super.willUpdate(changed);
77
79
  hostAria(this.internals, { role: 'row' });
80
+ this.nameByHeader();
78
81
  this.internals.ariaSelected = this.gridCell && this.selectable ? String(this.selected) : null;
79
82
  this.internals.ariaDisabled = this.disabled ? 'true' : null;
83
+ this.internals.ariaRowIndex = this.rowIndex > 0 ? String(this.rowIndex) : null;
80
84
  const tree = this.gridCell && this.level > 0;
81
85
  this.internals.ariaLevel = tree ? String(this.level) : null;
82
86
  this.internals.ariaExpanded = tree && this.branch ? String(this.open) : null;
@@ -87,6 +91,22 @@ let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
87
91
  this.toggleState('drop-after', this.move === 'drop-after');
88
92
  this.toggleState('drop-before', this.move === 'drop-before');
89
93
  }
94
+ nameByHeader() {
95
+ const cells = this.childrenKnown
96
+ ? this.knownChildren.filter((child) => 'isTableCell' in child && !child.hasAttribute('hidden'))
97
+ : [];
98
+ const values = cells.some((cell) => !cell.hasAttribute('header'));
99
+ const header = (values ? cells.find((cell) => cell.hasAttribute('header')) : undefined) ?? cells[0];
100
+ const own = this.hasAttribute('aria-label') || this.hasAttribute('aria-labelledby');
101
+ if ('ariaLabelledByElements' in this.internals) {
102
+ hostAria(this.internals, { labelledBy: header && !own ? [header] : [] });
103
+ }
104
+ else {
105
+ hostAria(this.internals, {
106
+ label: header && !own ? (header.textContent ?? '').replace(/\s+/g, ' ').trim() : '',
107
+ });
108
+ }
109
+ }
90
110
  connectedCallback() {
91
111
  super.connectedCallback();
92
112
  this.addEventListener('click', this.handleClick);
@@ -210,6 +230,9 @@ __decorate([
210
230
  __decorate([
211
231
  state()
212
232
  ], HelixHeadlessTableRow.prototype, "level", void 0);
233
+ __decorate([
234
+ state()
235
+ ], HelixHeadlessTableRow.prototype, "rowIndex", void 0);
213
236
  __decorate([
214
237
  state()
215
238
  ], HelixHeadlessTableRow.prototype, "branch", void 0);
@@ -56,7 +56,7 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
56
56
  * | Home, End on a segment | Goes to the segment's first or last value. |
57
57
  * | Digits on a segment | Fill it, and move to the next once it can take no more. |
58
58
  * | A letter on the half of the day | Picks the half whose name starts with it, such as A for AM. |
59
- * | Backspace, Delete on a segment | Empty the segment. |
59
+ * | Backspace, Delete on a segment | Take off its last digit, or move to the segment before where it is empty. |
60
60
  * | Left, Right on a segment | Move to the previous or the next segment, along the line of text. |
61
61
  *
62
62
  * In the list, the keys are `TimePicker`'s.
@@ -123,6 +123,7 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
123
123
  * @csspart picker-list-loading - The text shown while the options load.
124
124
  * @csspart picker-list-search - The region that holds the filter field.
125
125
  * @csspart picker-list-search-field - The filter field.
126
+ * @csspart picker-now - The picker's button that chooses the current time, which Time Input does not draw.
126
127
  * @csspart picker-option - One time in the picker. Carries `data-between` inside a range.
127
128
  * @csspart picker-option-between - A time inside a chosen range, between its two ends. Set together with `picker-option`.
128
129
  * @csspart picker-option-description - The caption under the label, when there is one.
@@ -233,7 +233,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
233
233
  list-filter-icon: picker-list-filter-icon, list-filter-mark: picker-list-filter-mark,
234
234
  list-hint: picker-list-hint, list-items: picker-list-items, list-label: picker-list-label,
235
235
  list-live: picker-list-live, list-loading: picker-list-loading, list-search: picker-list-search,
236
- list-search-field: picker-list-search-field, option: picker-option,
236
+ list-search-field: picker-list-search-field, now: picker-now, option: picker-option,
237
237
  option-between: picker-option-between, option-item-active: picker-option-item-active,
238
238
  option-item-selected: picker-option-item-selected,
239
239
  option-description: picker-option-description, option-item: picker-option-item,
@@ -14,7 +14,9 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
14
14
  * between the wheels, and Tab does too.
15
15
  *
16
16
  * `hour-cycle` writes every time on a twelve or a twenty-four hour clock
17
- * whatever the locale, and `seconds` holds times to the second.
17
+ * whatever the locale, and `seconds` holds times to the second. `show-now`
18
+ * draws a button that chooses the current time, on the step and inside the
19
+ * bounds.
18
20
  *
19
21
  * The step keeps the list usable. At the default of 15 minutes a day is 96
20
22
  * rows, which people can scroll or type into. At 1 minute it is 1,440. Use the
@@ -103,6 +105,7 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
103
105
  * @csspart list-loading - The text shown while the options load.
104
106
  * @csspart list-search - The region that holds the filter field.
105
107
  * @csspart list-search-field - The filter field.
108
+ * @csspart now - The button that chooses the current time, drawn with `show-now`.
106
109
  * @csspart option - One time in the list. It carries `data-between` inside a range, and inside the run to the time under the pointer while a range waits for its second end.
107
110
  * @csspart option-between - A time inside a chosen range, excluding its ends, beside `option`.
108
111
  * @csspart option-description - The caption under the time's label, when there is one.
@@ -242,6 +245,11 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
242
245
  * whenever a mode is set.
243
246
  */
244
247
  mode?: 'multiple' | 'range';
248
+ /**
249
+ * The words on the button that chooses the current time, drawn with
250
+ * `show-now`.
251
+ */
252
+ nowLabel: string;
245
253
  /**
246
254
  * The validation message for a time after `max`. `{max}` is replaced with
247
255
  * `max`, written in `locale`.
@@ -322,6 +330,35 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
322
330
  * sequence.
323
331
  */
324
332
  private readonly handleChange;
333
+ /**
334
+ * Requests the times a pick announced, kept to what the mode allows, and
335
+ * returns whether the value changed.
336
+ */
337
+ private choose;
338
+ /**
339
+ * Chooses the current time, as a press on the `show-now` button does, and
340
+ * returns whether the value changed.
341
+ *
342
+ * The time is read off the reader's clock and moved to the nearest time on
343
+ * offer that is not barred, so it falls on the `step` and inside `min` and
344
+ * `max`. It is requested as a pick is, so `helix-before-change` can cancel
345
+ * it. With a `mode` the time joins the times held, and a range that holds
346
+ * two starts over from it, as a third pick does.
347
+ */
348
+ selectNow(): boolean;
349
+ /**
350
+ * Puts the list's highlight on the offered time nearest one held between two
351
+ * steps, so the arrows move from there.
352
+ *
353
+ * No row holds `14:07` at a step of 15, so the list had nothing to move
354
+ * from: Down went to the top of the list, and in a list that chooses as it
355
+ * moves, the value became 00:00. Down now goes to 14:15.
356
+ */
357
+ private highlightNearest;
358
+ private readonly handleListFocus;
359
+ private readonly handleNow;
360
+ /** The button that chooses the current time, drawn with `show-now`. */
361
+ private renderNow;
325
362
  /**
326
363
  * The time under the pointer while a range holds one end, which the list
327
364
  * bands the range to before it is chosen, as Date Picker does.
@@ -409,6 +446,16 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
409
446
  * the wheels.
410
447
  */
411
448
  seconds: boolean;
449
+ /**
450
+ * Draws a button under the times that chooses the current time, as
451
+ * `selectNow()` does.
452
+ *
453
+ * For a form about something happening now, such as a shift starting or a
454
+ * dose taken, where the reader would otherwise scroll to the time on the
455
+ * clock. The button is a tab stop after the times, and its words are
456
+ * `now-label`.
457
+ */
458
+ showNow: boolean;
412
459
  /**
413
460
  * How far apart the offered times are, in minutes, or in seconds with
414
461
  * `seconds`.
@@ -23,6 +23,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
23
23
  this.manual = false;
24
24
  this.max = '23:59';
25
25
  this.min = '00:00';
26
+ this.nowLabel = 'Now';
26
27
  this.rangeOverflowMessage = 'Choose a time at or before {max}.';
27
28
  this.rangeUnderflowMessage = 'Choose a time at or after {min}.';
28
29
  this.handleListInput = (event) => {
@@ -33,25 +34,13 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
33
34
  if (this.isDisabled) {
34
35
  return;
35
36
  }
36
- const announced = event.detail.value;
37
- if (announced.split(',').some((one) => this.barred(one.trim()))) {
38
- return;
39
- }
40
- if (this.mode !== 'range') {
41
- this.requestValue(announced);
42
- return;
43
- }
44
- const next = announced
45
- .split(',')
46
- .map((one) => one.trim())
47
- .filter(Boolean);
48
- if (next.length <= 2) {
49
- this.requestValue(next.sort().join(','));
50
- return;
51
- }
52
- const before = new Set(this.held);
53
- const added = next.find((one) => !before.has(one));
54
- this.requestValue(added ?? '');
37
+ this.choose(event.detail.value);
38
+ };
39
+ this.handleListFocus = () => {
40
+ this.highlightNearest();
41
+ };
42
+ this.handleNow = () => {
43
+ this.selectNow();
55
44
  };
56
45
  this.previewed = '';
57
46
  this.handleListHover = (event) => {
@@ -93,6 +82,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
93
82
  this.readOnly = false;
94
83
  this.required = false;
95
84
  this.seconds = false;
85
+ this.showNow = false;
96
86
  this.step = 15;
97
87
  this.stepMismatchMessage = 'Choose one of the times on offer.';
98
88
  this.unavailableMessage = 'Choose a time that is available.';
@@ -155,6 +145,65 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
155
145
  get held() {
156
146
  return commaList(this.value);
157
147
  }
148
+ choose(announced) {
149
+ if (announced.split(',').some((one) => this.barred(one.trim()))) {
150
+ return false;
151
+ }
152
+ if (this.mode !== 'range') {
153
+ return this.requestValue(announced);
154
+ }
155
+ const next = announced
156
+ .split(',')
157
+ .map((one) => one.trim())
158
+ .filter(Boolean);
159
+ if (next.length <= 2) {
160
+ return this.requestValue(next.sort().join(','));
161
+ }
162
+ const before = new Set(this.held);
163
+ const added = next.find((one) => !before.has(one));
164
+ return this.requestValue(added ?? '');
165
+ }
166
+ selectNow() {
167
+ if (this.isDisabled) {
168
+ return false;
169
+ }
170
+ const clock = new Date();
171
+ const at = clock.getHours() * 3600 + clock.getMinutes() * 60 + clock.getSeconds();
172
+ const open = this.times.filter((time) => !this.barredAt(time));
173
+ if (open.length === 0) {
174
+ return false;
175
+ }
176
+ const now = this.valueFor(nearestTime(open, at));
177
+ if (this.mode === undefined) {
178
+ return this.requestValue(now);
179
+ }
180
+ if (this.held.includes(now)) {
181
+ return false;
182
+ }
183
+ return this.choose([...this.held, now].join(','));
184
+ }
185
+ highlightNearest() {
186
+ const at = this.mode === undefined ? valueAsSeconds(this.value) : null;
187
+ if (at === null || this.times.includes(at)) {
188
+ return;
189
+ }
190
+ const open = this.times.filter((time) => !this.barredAt(time));
191
+ if (open.length === 0) {
192
+ return;
193
+ }
194
+ this.partNamed('list')?.highlightValue?.(this.valueFor(nearestTime(open, at)));
195
+ }
196
+ renderNow() {
197
+ if (!this.showNow) {
198
+ return nothing;
199
+ }
200
+ return html `<button
201
+ part="now"
202
+ type="button"
203
+ ?disabled=${this.isDisabled || this.readOnly}
204
+ @click=${this.handleNow}
205
+ >${this.nowLabel}</button>`;
206
+ }
158
207
  between(at) {
159
208
  if (this.mode !== 'range') {
160
209
  return false;
@@ -191,6 +240,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
191
240
  return;
192
241
  }
193
242
  if (this.variant !== 'wheels') {
243
+ this.highlightNearest();
194
244
  this.partNamed('list')?.reveal?.();
195
245
  return;
196
246
  }
@@ -421,6 +471,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
421
471
  ?manual=${this.manual}
422
472
  ?multiple=${this.mode !== undefined}
423
473
  .value=${this.value}
474
+ @focusin=${this.handleListFocus}
424
475
  @helix-before-change=${this.handleChange}
425
476
  @input=${this.handleListInput}
426
477
  @pointerleave=${this.handleListLeave}
@@ -446,9 +497,9 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
446
497
  }
447
498
  render() {
448
499
  if (this.variant === 'wheels' && this.mode === undefined) {
449
- return html `${this.renderSlottedLabel()}${this.renderSpinner()}${this.renderHint()}${this.renderPickerFeedback()}`;
500
+ return html `${this.renderSlottedLabel()}${this.renderSpinner()}${this.renderNow()}${this.renderHint()}${this.renderPickerFeedback()}`;
450
501
  }
451
- return html `${this.renderSlottedLabel()}${this.renderList()}${this.renderHint()}${this.renderPickerFeedback()}`;
502
+ return html `${this.renderSlottedLabel()}${this.renderList()}${this.renderNow()}${this.renderHint()}${this.renderPickerFeedback()}`;
452
503
  }
453
504
  get valueAsDate() {
454
505
  const at = valueAsSeconds(this.value);
@@ -512,6 +563,10 @@ __decorate([
512
563
  __decorate([
513
564
  property({ reflect: true })
514
565
  ], HelixHeadlessTimePicker.prototype, "mode", void 0);
566
+ __decorate([
567
+ words,
568
+ property({ attribute: 'now-label' })
569
+ ], HelixHeadlessTimePicker.prototype, "nowLabel", void 0);
515
570
  __decorate([
516
571
  words,
517
572
  property({ attribute: 'range-overflow-message' })
@@ -535,6 +590,9 @@ __decorate([
535
590
  __decorate([
536
591
  property({ type: Boolean })
537
592
  ], HelixHeadlessTimePicker.prototype, "seconds", void 0);
593
+ __decorate([
594
+ property({ attribute: 'show-now', type: Boolean })
595
+ ], HelixHeadlessTimePicker.prototype, "showNow", void 0);
538
596
  __decorate([
539
597
  property({ type: Number })
540
598
  ], HelixHeadlessTimePicker.prototype, "step", void 0);
@@ -8,6 +8,12 @@ import { type PropertyValues, type TemplateResult } from 'lit';
8
8
  * `const row: VirtualListRenderer<Person> = (person) => person.name`.
9
9
  */
10
10
  export type VirtualListRenderer<Item = unknown> = (item: Item, index: number) => unknown;
11
+ /**
12
+ * Draws one section's header, for a list given `sectionField`, given the
13
+ * section's name and its place among the sections. Returns anything Lit
14
+ * renders.
15
+ */
16
+ export type VirtualListSectionRenderer = (name: string, index: number) => unknown;
11
17
  /** Where `scrollToIndex` puts an item, and how it gets there. */
12
18
  export interface VirtualListScrollOptions {
13
19
  /**
@@ -55,12 +61,26 @@ export interface VirtualListRange {
55
61
  * smallest item size, and follows the box as it resizes. `gap` spaces the rows, and the columns
56
62
  * of a grid, by a number of pixels the list counts in each row's place.
57
63
  *
64
+ * **Across.** `orientation="horizontal"` lays the items out along a line and
65
+ * scrolls it sideways, as a strip of cards does, windowed the same way:
66
+ * `estimate` is then an item's width, and the box needs an inline size.
67
+ *
68
+ * **Sections.** `section-field` names the field of each item that says which
69
+ * section it is in, and the list draws a header before each section's items,
70
+ * as React Aria's list box sections do. Each section is an element with the
71
+ * `group` role, named by its header, which is its first child and carries
72
+ * `data-header`, so your stylesheet styles it, such as with `position:
73
+ * sticky`. A section starts wherever the field changes, so give the items in
74
+ * order. The window counts the headers with the items, and a section the
75
+ * window starts inside is drawn with its header. `renderSection` draws a
76
+ * header of your own.
77
+ *
58
78
  * **Keyboard.** The list is one tab stop.
59
79
  *
60
80
  * | Key | What it does |
61
81
  * |---|---|
62
82
  * | Down, Up | Moves to the next or the previous item, or in a grid to the item in the same column on the next or the previous line. |
63
- * | Right, Left | In a grid, moves to the next or the previous item along the line, the other way round on a right-to-left page. |
83
+ * | Right, Left | In a grid, moves to the next or the previous item along the line, the other way round on a right-to-left page. In a list that runs across, moves to the next or the previous item the same way, and Down and Up are left to the row. |
64
84
  * | Home, End | Moves to the first or the last item. |
65
85
  * | Page Down, Page Up | Moves by the number of items, or of lines in a grid, on screen. |
66
86
  * | A letter or a word | Moves to the next item whose text starts with what you typed. |
@@ -153,6 +173,7 @@ export interface VirtualListRange {
153
173
  * @csspart viewport - The scrolling box. On this tier, it needs only a block size.
154
174
  *
155
175
  * @cssstate empty - While the list has read its items and holds none.
176
+ * @cssstate horizontal - While the list runs across, with `orientation="horizontal"`.
156
177
  * @cssstate loading - While `loading` is set.
157
178
  */
158
179
  export declare class HelixHeadlessVirtualList extends HelixElement {
@@ -247,6 +268,13 @@ export declare class HelixHeadlessVirtualList extends HelixElement {
247
268
  * follows the box as it resizes, which `columns` then does not decide.
248
269
  */
249
270
  minColumnWidth: number;
271
+ /**
272
+ * Which way the list runs. `horizontal` lays the items out along a line
273
+ * and scrolls it sideways: Left and Right move between items, the other
274
+ * way round on a right-to-left page, and `estimate` is an item's width. A
275
+ * grid always runs down.
276
+ */
277
+ orientation: 'horizontal' | 'vertical';
250
278
  /**
251
279
  * Draws one item into its row, given the item and its index. Set it as a
252
280
  * property.
@@ -256,6 +284,20 @@ export declare class HelixHeadlessVirtualList extends HelixElement {
256
284
  * and place in the set. Where it is unset, the row `<template>` is used.
257
285
  */
258
286
  renderItem: VirtualListRenderer<any> | undefined;
287
+ /**
288
+ * Draws each section's header, given its name and its place among the
289
+ * sections, for a list given `section-field`. Set it as a property. Where
290
+ * it is unset, the header is the name as text.
291
+ */
292
+ renderSection: VirtualListSectionRenderer | undefined;
293
+ /**
294
+ * The field of each item that names its section, as a key or a path of
295
+ * keys. Set, the items are drawn in sections: a header, then the items, in
296
+ * an element with the `group` role that the header names. A section starts
297
+ * wherever the field changes, so give the items in order. A list of one
298
+ * column only.
299
+ */
300
+ sectionField: string;
259
301
  /**
260
302
  * What a press does to the items already chosen: `toggle` adds or takes out
261
303
  * the item, and `replace` selects it alone and lets the arrow keys carry the
@@ -358,6 +400,14 @@ export declare class HelixHeadlessVirtualList extends HelixElement {
358
400
  private watchWidth;
359
401
  /** The items a span of lines holds. */
360
402
  private itemsOn;
403
+ /** The line item `at` is on: its entry in a list with sections. */
404
+ private lineOf;
405
+ /** Whether the list runs across, which a grid never does. */
406
+ private get horizontal();
407
+ /** The sections and the items they were read from, kept until either changes. */
408
+ private sectionsRead;
409
+ /** The sections `section-field` divides the items into, in a list of one column. */
410
+ private get sections();
361
411
  /**
362
412
  * Scrolls the list to show the item at `index`.
363
413
  *
@@ -443,6 +493,8 @@ export declare class HelixHeadlessVirtualList extends HelixElement {
443
493
  private isDisabled;
444
494
  /** The item a row element drew, for an element that is one of the rows. */
445
495
  private indexOf;
496
+ /** Whether a node is one of the rows: a child, or a child of a section. */
497
+ private isRow;
446
498
  /** The row that holds the tab stop for item `index`, where it is drawn. */
447
499
  private rowFor;
448
500
  /**
@@ -541,7 +593,23 @@ export declare class HelixHeadlessVirtualList extends HelixElement {
541
593
  * buttons are in the tab order, and those of every other row wait.
542
594
  */
543
595
  private place;
544
- /** The spacers' heights: the window's, with the line kept for focus taking its own room. */
596
+ /** The sections the rows were last placed in. */
597
+ private placedSections;
598
+ /** The function the drawn headers were drawn by, so a new one draws them again. */
599
+ private headedBy;
600
+ /** Ties each header's id to this list. */
601
+ private readonly sectionId;
602
+ /**
603
+ * The section elements a pass draws rows into, by section, for the
604
+ * sections of the wanted items: each a `group` named by its header, which
605
+ * is its first child. The ones no wanted item is in leave, and all of them
606
+ * do when the sections change.
607
+ */
608
+ private groups;
609
+ /**
610
+ * The spacers' sizes: the window's, with the line kept for focus taking its
611
+ * own room, and so do the headers drawn with their sections from outside it.
612
+ */
545
613
  private spacerSizes;
546
614
  protected render(): TemplateResult;
547
615
  }