@fusion.dev/helix-headless 0.144.0 → 0.145.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 (155) hide show
  1. package/custom-elements.json +8312 -881
  2. package/dist/accordion/item/accordion-item.d.ts +48 -12
  3. package/dist/accordion/item/accordion-item.js +26 -5
  4. package/dist/accordion/root/accordion-root.d.ts +6 -0
  5. package/dist/accordion/root/accordion-root.js +7 -1
  6. package/dist/announcement/root/announcement-root.d.ts +21 -1
  7. package/dist/announcement/root/announcement-root.js +36 -1
  8. package/dist/app-header/root/app-header-root.d.ts +7 -0
  9. package/dist/app-header/root/app-header-root.js +5 -1
  10. package/dist/app-header/sectioning.d.ts +7 -0
  11. package/dist/app-header/sectioning.js +26 -0
  12. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +32 -1
  13. package/dist/breadcrumbs/root/breadcrumbs-root.js +25 -2
  14. package/dist/canvas/root/canvas-root.d.ts +38 -3
  15. package/dist/canvas/root/canvas-root.js +121 -40
  16. package/dist/carousel/root/carousel-root.d.ts +90 -0
  17. package/dist/carousel/root/carousel-root.js +134 -12
  18. package/dist/chat/composer/chat-composer.d.ts +38 -6
  19. package/dist/chat/composer/chat-composer.js +42 -9
  20. package/dist/chat/message/chat-message.d.ts +32 -1
  21. package/dist/chat/message/chat-message.js +25 -9
  22. package/dist/chat/naming.d.ts +22 -0
  23. package/dist/chat/naming.js +12 -0
  24. package/dist/chat/relative-clock.d.ts +39 -0
  25. package/dist/chat/relative-clock.js +31 -0
  26. package/dist/chat/root/chat-root.d.ts +36 -0
  27. package/dist/chat/root/chat-root.js +24 -1
  28. package/dist/code-block/root/code-block-root.d.ts +8 -1
  29. package/dist/code-block/root/code-block-root.js +5 -5
  30. package/dist/copy-button/root/copy-button-root.d.ts +21 -1
  31. package/dist/copy-button/root/copy-button-root.js +2 -2
  32. package/dist/data-table/root/data-table-root.d.ts +150 -2
  33. package/dist/data-table/root/data-table-root.js +303 -29
  34. package/dist/data-table/tree.d.ts +40 -0
  35. package/dist/data-table/tree.js +55 -0
  36. package/dist/description-list/item/description-list-item.d.ts +17 -2
  37. package/dist/description-list/item/description-list-item.js +15 -2
  38. package/dist/description-list/root/description-list-root.d.ts +27 -1
  39. package/dist/description-list/root/description-list-root.js +26 -1
  40. package/dist/drilldown/item/drilldown-item.d.ts +11 -6
  41. package/dist/drilldown/item/drilldown-item.js +8 -5
  42. package/dist/drilldown/root/drilldown-root.d.ts +11 -0
  43. package/dist/drilldown/root/drilldown-root.js +8 -3
  44. package/dist/element-events.generated.js +53 -8
  45. package/dist/filter-input/menu/filter-menu.d.ts +3 -0
  46. package/dist/filter-input/menu/filter-menu.js +8 -4
  47. package/dist/image/root/image-root.js +9 -1
  48. package/dist/input/root/input-root.d.ts +1 -1
  49. package/dist/input/root/input-root.js +2 -2
  50. package/dist/list/item/list-item.d.ts +68 -1
  51. package/dist/list/item/list-item.js +66 -4
  52. package/dist/list/numbering.d.ts +14 -0
  53. package/dist/list/numbering.js +8 -0
  54. package/dist/list/root/list-root.d.ts +106 -9
  55. package/dist/list/root/list-root.js +189 -4
  56. package/dist/list/selection.d.ts +19 -0
  57. package/dist/list/selection.js +21 -0
  58. package/dist/listbox/root/listbox-root.js +1 -2
  59. package/dist/map/root/map-root.d.ts +6 -2
  60. package/dist/map/root/map-root.js +5 -2
  61. package/dist/megamenu/root/megamenu-root.d.ts +21 -0
  62. package/dist/megamenu/root/megamenu-root.js +16 -2
  63. package/dist/menu/index.d.ts +1 -0
  64. package/dist/menu/index.js +1 -0
  65. package/dist/menu/item/menu-item.d.ts +38 -11
  66. package/dist/menu/item/menu-item.js +33 -1
  67. package/dist/menu/root/menu-root.d.ts +25 -1
  68. package/dist/menu/root/menu-root.js +63 -6
  69. package/dist/menu/section/menu-section.d.ts +55 -0
  70. package/dist/menu/section/menu-section.js +60 -0
  71. package/dist/navigation/root/navigation-root.d.ts +16 -1
  72. package/dist/navigation/root/navigation-root.js +27 -1
  73. package/dist/notifications/root/notifications-root.d.ts +18 -0
  74. package/dist/notifications/root/notifications-root.js +17 -1
  75. package/dist/object-inspector/root/object-inspector-root.d.ts +97 -16
  76. package/dist/object-inspector/root/object-inspector-root.js +179 -79
  77. package/dist/object-inspector/rows.d.ts +57 -0
  78. package/dist/object-inspector/rows.js +86 -0
  79. package/dist/outline/levels.d.ts +31 -0
  80. package/dist/outline/levels.js +23 -0
  81. package/dist/outline/root/outline-root.d.ts +68 -3
  82. package/dist/outline/root/outline-root.js +73 -8
  83. package/dist/pagination/size/pagination-size.d.ts +11 -2
  84. package/dist/pagination/size/pagination-size.js +19 -4
  85. package/dist/radio/group/radio-group.d.ts +4 -10
  86. package/dist/radio/group/radio-group.js +5 -10
  87. package/dist/rating/root/rating-root.d.ts +1 -1
  88. package/dist/rating/root/rating-root.js +2 -2
  89. package/dist/scroll-area/root/scroll-area-root.d.ts +113 -0
  90. package/dist/scroll-area/root/scroll-area-root.js +218 -3
  91. package/dist/scroll-area/scrollbar.d.ts +65 -0
  92. package/dist/scroll-area/scrollbar.js +24 -0
  93. package/dist/select/root/select-root.js +1 -1
  94. package/dist/splitter/root/splitter-root.d.ts +13 -0
  95. package/dist/splitter/root/splitter-root.js +20 -2
  96. package/dist/splitter/snap.d.ts +9 -0
  97. package/dist/splitter/snap.js +12 -0
  98. package/dist/steps/reach.d.ts +15 -0
  99. package/dist/steps/reach.js +12 -0
  100. package/dist/steps/root/steps-root.d.ts +30 -0
  101. package/dist/steps/root/steps-root.js +53 -0
  102. package/dist/steps/step/step.d.ts +38 -2
  103. package/dist/steps/step/step.js +28 -6
  104. package/dist/table/column/table-column.d.ts +11 -0
  105. package/dist/table/column/table-column.js +6 -1
  106. package/dist/table/root/table-root.d.ts +101 -0
  107. package/dist/table/root/table-root.js +166 -5
  108. package/dist/table/row/table-row.d.ts +47 -1
  109. package/dist/table/row/table-row.js +39 -2
  110. package/dist/tabs/panel/tab-panel.d.ts +9 -5
  111. package/dist/tabs/panel/tab-panel.js +3 -4
  112. package/dist/tabs/root/tabs-root.d.ts +25 -1
  113. package/dist/tabs/root/tabs-root.js +21 -3
  114. package/dist/tabs/tab/tab.d.ts +36 -4
  115. package/dist/tabs/tab/tab.js +46 -3
  116. package/dist/timeline/group/timeline-group.d.ts +46 -0
  117. package/dist/timeline/group/timeline-group.js +37 -0
  118. package/dist/timeline/index.d.ts +1 -0
  119. package/dist/timeline/index.js +1 -0
  120. package/dist/timeline/root/timeline-root.d.ts +10 -3
  121. package/dist/toast/item/toast-item.d.ts +10 -17
  122. package/dist/toast/item/toast-item.js +15 -36
  123. package/dist/toolbar/root/toolbar-root.d.ts +13 -0
  124. package/dist/toolbar/root/toolbar-root.js +15 -5
  125. package/dist/tree/item/tree-item.d.ts +54 -1
  126. package/dist/tree/item/tree-item.js +89 -20
  127. package/dist/tree/root/tree-root.d.ts +37 -0
  128. package/dist/tree/root/tree-root.js +51 -6
  129. package/dist/tree/selection.d.ts +24 -0
  130. package/dist/tree/selection.js +26 -0
  131. package/dist/video/media-events.d.ts +49 -0
  132. package/dist/video/media-events.js +39 -0
  133. package/dist/video/root/video-root.d.ts +99 -13
  134. package/dist/video/root/video-root.js +84 -47
  135. package/dist/video-playlist/menu/video-playlist-menu.d.ts +3 -0
  136. package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
  137. package/dist/video-playlist/order.d.ts +41 -0
  138. package/dist/video-playlist/order.js +34 -0
  139. package/dist/video-playlist/root/video-playlist-root.d.ts +70 -2
  140. package/dist/video-playlist/root/video-playlist-root.js +60 -16
  141. package/dist/virtual-list/controls.d.ts +4 -0
  142. package/dist/virtual-list/controls.js +30 -0
  143. package/dist/virtual-list/fill.d.ts +30 -0
  144. package/dist/virtual-list/fill.js +39 -0
  145. package/dist/virtual-list/keys.d.ts +15 -0
  146. package/dist/virtual-list/keys.js +24 -0
  147. package/dist/virtual-list/root/virtual-list-root.d.ts +155 -23
  148. package/dist/virtual-list/root/virtual-list-root.js +175 -34
  149. package/lint.json +1 -1
  150. package/package.json +5 -5
  151. package/types/jsx.d.ts +3778 -801
  152. package/types/svelte.d.ts +2 -0
  153. package/types/vue.d.ts +782 -215
  154. package/dist/listbox/range.d.ts +0 -17
  155. package/dist/listbox/range.js +0 -5
@@ -4,31 +4,74 @@ 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 } from '@fusion.dev/helix-core';
8
- import { html } from 'lit';
7
+ import { customElement, HelixElement, MixinSelectableItem, reflectElements, } from '@fusion.dev/helix-core';
8
+ import { html, nothing } from 'lit';
9
+ import { property } from 'lit/decorators.js';
9
10
  let HelixHeadlessTab = class HelixHeadlessTab extends MixinSelectableItem(HelixElement) {
10
11
  constructor() {
11
12
  super(...arguments);
12
13
  this.itemPart = 'tab';
14
+ this.controls = undefined;
15
+ this.handleLinkClick = (event) => {
16
+ if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
17
+ return;
18
+ }
19
+ if (!this.select()) {
20
+ event.preventDefault();
21
+ }
22
+ };
23
+ }
24
+ updated(changed) {
25
+ super.updated(changed);
26
+ const control = this.renderRoot.querySelector('[part="tab"]');
27
+ reflectElements(control, 'ariaControlsElements', this.controls ? [this.controls] : [], true);
13
28
  }
14
29
  firstUpdated(changed) {
15
30
  super.firstUpdated(changed);
16
31
  this.finishHydration();
17
32
  }
18
33
  render() {
34
+ const tabindex = this.selected || !this.childrenKnown ? '0' : '-1';
35
+ if ((this.href ?? '') !== '') {
36
+ return html `<a
37
+ part="tab"
38
+ role="tab"
39
+ href=${this.disabled ? nothing : (this.href ?? nothing)}
40
+ target=${this.target || nothing}
41
+ rel=${this.rel || nothing}
42
+ aria-selected=${this.selected ? 'true' : 'false'}
43
+ aria-disabled=${this.disabled ? 'true' : nothing}
44
+ tabindex=${this.disabled ? nothing : tabindex}
45
+ @click=${this.handleLinkClick}
46
+ >
47
+ <slot></slot>
48
+ </a>`;
49
+ }
19
50
  return html `<button
20
51
  part="tab"
21
52
  role="tab"
22
53
  type="button"
23
54
  aria-selected=${this.selected ? 'true' : 'false'}
24
55
  ?disabled=${this.disabled}
25
- tabindex=${this.selected || !this.childrenKnown ? '0' : '-1'}
56
+ tabindex=${tabindex}
26
57
  @click=${() => this.select()}
27
58
  >
28
59
  <slot></slot>
29
60
  </button>`;
30
61
  }
31
62
  };
63
+ __decorate([
64
+ property({ attribute: false })
65
+ ], HelixHeadlessTab.prototype, "controls", void 0);
66
+ __decorate([
67
+ property()
68
+ ], HelixHeadlessTab.prototype, "href", void 0);
69
+ __decorate([
70
+ property()
71
+ ], HelixHeadlessTab.prototype, "rel", void 0);
72
+ __decorate([
73
+ property()
74
+ ], HelixHeadlessTab.prototype, "target", void 0);
32
75
  HelixHeadlessTab = __decorate([
33
76
  customElement('helix-headless-tab')
34
77
  ], HelixHeadlessTab);
@@ -0,0 +1,46 @@
1
+ import { HelixElement } from '@fusion.dev/helix-core';
2
+ import { type PropertyValues, type TemplateResult } from 'lit';
3
+ /**
4
+ * @summary A run of timeline entries under a heading, such as a day.
5
+ *
6
+ * @description
7
+ * Groups entries by date, such as "Today" and "Yesterday", in a timeline that
8
+ * holds many. The group is an entry of the timeline, and its entries are a
9
+ * list of their own, named by the heading. A screen reader lists the heading
10
+ * with the page's headings and hears how many entries each day holds.
11
+ *
12
+ * The heading's level is `heading-level`, and 3 where it is not set.
13
+ *
14
+ * Each group draws its own line, so the line stops at the last entry of one
15
+ * day and starts again at the first entry of the next.
16
+ *
17
+ * @since 0.1.0
18
+ * @status stable
19
+ * @aliases Day, Section, Date group
20
+ * @documentation https://fusion.dev/helix/components/timeline
21
+ *
22
+ * @slot - The entries.
23
+ * @slot heading - The heading, when it is more than text. Falls back to `label`.
24
+ *
25
+ * @csspart entries - The list that holds the entries.
26
+ * @csspart heading - The heading.
27
+ */
28
+ export declare class HelixHeadlessTimelineGroup extends HelixElement {
29
+ /**
30
+ * The level of the group's heading, from 1 to 6.
31
+ */
32
+ headingLevel?: number;
33
+ /**
34
+ * The heading, when it is plain text, such as "Today".
35
+ *
36
+ * The fallback of the `heading` slot, so slotted content replaces it.
37
+ */
38
+ label: string;
39
+ protected willUpdate(changed: PropertyValues): void;
40
+ protected render(): TemplateResult;
41
+ }
42
+ declare global {
43
+ interface HTMLElementTagNameMap {
44
+ 'helix-headless-timeline-group': HelixHeadlessTimelineGroup;
45
+ }
46
+ }
@@ -0,0 +1,37 @@
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 { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
8
+ import { html } from 'lit';
9
+ import { property } from 'lit/decorators.js';
10
+ const HEADING_ID = 'heading';
11
+ let HelixHeadlessTimelineGroup = class HelixHeadlessTimelineGroup extends HelixElement {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.label = '';
15
+ }
16
+ willUpdate(changed) {
17
+ super.willUpdate(changed);
18
+ hostAria(this.internals, { role: 'listitem' });
19
+ }
20
+ render() {
21
+ const level = Math.min(6, Math.max(1, Math.trunc(this.headingLevel ?? 3)));
22
+ return html `<div part="heading" id=${HEADING_ID} role="heading" aria-level=${level}>
23
+ <slot name="heading">${this.label}</slot>
24
+ </div>
25
+ <div part="entries" role="list" aria-labelledby=${HEADING_ID}><slot></slot></div>`;
26
+ }
27
+ };
28
+ __decorate([
29
+ property({ attribute: 'heading-level', type: Number })
30
+ ], HelixHeadlessTimelineGroup.prototype, "headingLevel", void 0);
31
+ __decorate([
32
+ property()
33
+ ], HelixHeadlessTimelineGroup.prototype, "label", void 0);
34
+ HelixHeadlessTimelineGroup = __decorate([
35
+ customElement('helix-headless-timeline-group')
36
+ ], HelixHeadlessTimelineGroup);
37
+ export { HelixHeadlessTimelineGroup };
@@ -1,2 +1,3 @@
1
+ export * from './group/timeline-group.js';
1
2
  export * from './item/timeline-item.js';
2
3
  export * from './root/timeline-root.js';
@@ -1,2 +1,3 @@
1
+ export * from './group/timeline-group.js';
1
2
  export * from './item/timeline-item.js';
2
3
  export * from './root/timeline-root.js';
@@ -16,8 +16,15 @@ import { type PropertyValues, type TemplateResult } from 'lit';
16
16
  * The host has `role="list"`, because the entries are your elements in the
17
17
  * light DOM. `Steps` does the same.
18
18
  *
19
- * A timeline runs down the page and has no horizontal layout. For stages laid
20
- * out horizontally, use `Steps`, which is horizontal by default.
19
+ * **Group entries by date with `Timeline.Group`**, which puts a heading such as
20
+ * "Today" over its entries. The group is an entry of the timeline, and its
21
+ * entries are a list of their own named by the heading.
22
+ *
23
+ * **The reading order is the order you write the entries in**, in every layout
24
+ * the styled tier draws: down the page, either side of a line down the middle,
25
+ * or across the page. Inside each entry the time is read before what happened.
26
+ * Write the entries in the order the events happened, oldest or newest first,
27
+ * and the layout only moves where they are drawn.
21
28
  *
22
29
  * @since 0.1.0
23
30
  * @status stable
@@ -25,7 +32,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
25
32
  * @aliases Activity feed, History, Changelog, Audit trail
26
33
  * @documentation https://fusion.dev/helix/components/timeline
27
34
  *
28
- * @slot - The entries.
35
+ * @slot - The entries, and any groups of them.
29
36
  */
30
37
  export declare class HelixHeadlessTimeline extends HelixElement {
31
38
  /**
@@ -78,11 +78,16 @@ export declare class HelixHeadlessToastItem extends HelixHeadlessToastItem_base
78
78
  protected readonly swipes: SwipeController;
79
79
  /** Writes how far a swipe has moved the message toward the end of the line. */
80
80
  private slide;
81
- /** When the current run of the timer began, or nothing while it is paused. */
82
- private startedAt;
83
- /** What is left of the duration, so resuming continues rather than restarts. */
84
- private remaining;
85
- private timer;
81
+ /**
82
+ * The dismiss timer, which pauses while a reader is on the message and
83
+ * continues from what was left.
84
+ *
85
+ * Paused is said on the host so the indicator can freeze with the clock. A
86
+ * `data-` attribute rather than a property, because it is written after
87
+ * upgrade from a pointer moving: nothing declares it and no server rendered
88
+ * it, which is the same reason `Carousel` names its slides from here.
89
+ */
90
+ private readonly countdown;
86
91
  /**
87
92
  * The kind of message, which sets its mark and the mark's accessible name.
88
93
  *
@@ -104,21 +109,9 @@ export declare class HelixHeadlessToastItem extends HelixHeadlessToastItem_base
104
109
  pause(): void;
105
110
  /** Restarts the dismiss timer from where it paused. */
106
111
  resume(): void;
107
- /**
108
- * How many reasons there are to hold the clock, rather than whether there is
109
- * one.
110
- *
111
- * Hover and focus stop the same timer, and the two are genuinely independent:
112
- * a pointer can leave while focus stays, and focus can leave while the
113
- * pointer stays. Uncounted, a reader who tabs into a message and then moves
114
- * the pointer off it has the clock restarted underneath them, which is the
115
- * case the pause exists for. Only the last one out starts it again.
116
- */
117
- private holds;
118
112
  private readonly handlePause;
119
113
  private readonly handleResume;
120
114
  connectedCallback(): void;
121
- disconnectedCallback(): void;
122
115
  protected willUpdate(changed: PropertyValues): void;
123
116
  protected updated(changed: PropertyValues): void;
124
117
  protected firstUpdated(changed: PropertyValues): void;
@@ -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, drawDismiss, drawDismissGlyph, HelixElement, hostAria, isRtl, MixinDismissible, requestChange, SwipeController, settleSwipe, swipeEdge, toneMark, towardEdge, } from '@fusion.dev/helix-core';
7
+ import { CountdownController, customElement, drawDismiss, drawDismissGlyph, HelixElement, hostAria, isRtl, MixinDismissible, requestChange, SwipeController, settleSwipe, swipeEdge, toneMark, towardEdge, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
@@ -31,17 +31,20 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
31
31
  start: (_target, event) => event.pointerType !== 'mouse',
32
32
  surface: () => this.partNamed('item'),
33
33
  });
34
+ this.countdown = new CountdownController(this, {
35
+ done: () => {
36
+ this.dismiss();
37
+ },
38
+ paused: (paused) => {
39
+ this.toggleAttribute('data-paused', paused);
40
+ },
41
+ });
34
42
  this.openState = undefined;
35
- this.holds = 0;
36
43
  this.handlePause = () => {
37
- this.holds += 1;
38
- this.pause();
44
+ this.countdown.hold();
39
45
  };
40
46
  this.handleResume = () => {
41
- this.holds = Math.max(this.holds - 1, 0);
42
- if (this.holds === 0) {
43
- this.resume();
44
- }
47
+ this.countdown.release();
45
48
  };
46
49
  }
47
50
  get open() {
@@ -60,8 +63,7 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
60
63
  if (!this.open) {
61
64
  return true;
62
65
  }
63
- clearTimeout(this.timer);
64
- this.timer = undefined;
66
+ this.countdown.cancel();
65
67
  return requestChange({
66
68
  apply: () => {
67
69
  const previous = this.open;
@@ -74,25 +76,10 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
74
76
  });
75
77
  }
76
78
  pause() {
77
- if (this.timer === undefined || this.startedAt === undefined) {
78
- return;
79
- }
80
- clearTimeout(this.timer);
81
- this.timer = undefined;
82
- this.remaining = Math.max((this.remaining ?? 0) - (Date.now() - this.startedAt), 0);
83
- this.startedAt = undefined;
84
- this.toggleAttribute('data-paused', true);
79
+ this.countdown.pause();
85
80
  }
86
81
  resume() {
87
- if (this.timer !== undefined || this.remaining === undefined || this.remaining <= 0) {
88
- return;
89
- }
90
- this.startedAt = Date.now();
91
- this.toggleAttribute('data-paused', false);
92
- this.timer = setTimeout(() => {
93
- this.timer = undefined;
94
- this.dismiss();
95
- }, this.remaining);
82
+ this.countdown.resume();
96
83
  }
97
84
  connectedCallback() {
98
85
  super.connectedCallback();
@@ -100,11 +87,6 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
100
87
  this.resume();
101
88
  }
102
89
  }
103
- disconnectedCallback() {
104
- super.disconnectedCallback();
105
- this.pause();
106
- this.holds = 0;
107
- }
108
90
  willUpdate(changed) {
109
91
  super.willUpdate(changed);
110
92
  this.toggleAttribute('data-closed', !this.open);
@@ -122,10 +104,7 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
122
104
  }
123
105
  firstUpdated(changed) {
124
106
  super.firstUpdated(changed);
125
- if (this.duration !== undefined && this.duration > 0) {
126
- this.remaining = this.duration;
127
- this.resume();
128
- }
107
+ this.countdown.start(this.duration);
129
108
  }
130
109
  renderIcon(mark) {
131
110
  return html `<slot name="icon">
@@ -12,6 +12,14 @@ import { type PropertyValues, type TemplateResult } from 'lit';
12
12
  * focus counts as a control, including your own elements. A child that takes no
13
13
  * focus, such as a divider, is skipped. A menu is reached at its trigger.
14
14
  *
15
+ * Controls inside a plain wrapper, such as a `Button Group`, are each a stop
16
+ * of the toolbar's own, as React Aria's toolbar flattens a group: the arrows
17
+ * walk through the group's buttons and on past it, and the group takes no tab
18
+ * stop of its own.
19
+ *
20
+ * The arrows wrap from the last control to the first. Set `stop-at-ends` to
21
+ * keep them at the ends, as Radix's `loop` set to false does.
22
+ *
15
23
  * A nested composite, such as a toggle group, is one stop on the toolbar's
16
24
  * axis: the toolbar's arrows move past it, and the arrows across the toolbar
17
25
  * move inside it. A composite with a `focusable` property, as Toggle Group
@@ -49,6 +57,11 @@ export declare class HelixHeadlessToolbar extends HelixElement {
49
57
  * The direction the arrow keys move focus in.
50
58
  */
51
59
  orientation?: 'horizontal' | 'vertical';
60
+ /**
61
+ * Whether the arrow keys stop at the first and the last control. Unset, they
62
+ * wrap around from one end to the other.
63
+ */
64
+ stopAtEnds: boolean;
52
65
  private watcher;
53
66
  /**
54
67
  * The children that take part in the toolbar, in document order, each with
@@ -31,6 +31,7 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
31
31
  target: () => this.partNamed('toolbar'),
32
32
  });
33
33
  this.wroteForeign = false;
34
+ this.stopAtEnds = false;
34
35
  this.handleFocusIn = (event) => {
35
36
  const control = this.origin(event);
36
37
  if (control) {
@@ -75,11 +76,14 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
75
76
  return;
76
77
  }
77
78
  let next = current;
79
+ const last = controls.length - 1;
78
80
  if (forward) {
79
- next = (current + 1) % controls.length;
81
+ next = this.stopAtEnds ? Math.min(current + 1, last) : (current + 1) % controls.length;
80
82
  }
81
83
  else if (back) {
82
- next = (current - 1 + controls.length) % controls.length;
84
+ next = this.stopAtEnds
85
+ ? Math.max(current - 1, 0)
86
+ : (current - 1 + controls.length) % controls.length;
83
87
  }
84
88
  else if (event.key === 'Home') {
85
89
  next = 0;
@@ -110,9 +114,12 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
110
114
  child.getAttribute('aria-hidden') === 'true') {
111
115
  continue;
112
116
  }
113
- const stops = takesFocus(child) ? this.inside(child) : this.within(child);
114
- if (stops.length > 0) {
115
- controls.push({ child, stops });
117
+ if (takesFocus(child)) {
118
+ controls.push({ child, stops: this.inside(child) });
119
+ continue;
120
+ }
121
+ for (const stop of this.within(child)) {
122
+ controls.push({ child: stop, stops: [stop] });
116
123
  }
117
124
  }
118
125
  return controls;
@@ -204,6 +211,9 @@ __decorate([
204
211
  __decorate([
205
212
  property({ reflect: true })
206
213
  ], HelixHeadlessToolbar.prototype, "orientation", void 0);
214
+ __decorate([
215
+ property({ attribute: 'stop-at-ends', type: Boolean })
216
+ ], HelixHeadlessToolbar.prototype, "stopAtEnds", void 0);
207
217
  HelixHeadlessToolbar = __decorate([
208
218
  customElement('helix-headless-toolbar')
209
219
  ], HelixHeadlessToolbar);
@@ -23,21 +23,33 @@ declare const HelixHeadlessTreeItem_base: (new (...args: any[]) => import("@fusi
23
23
  * a `value` is chosen as well and sends `helix-select`, unless the tree has
24
24
  * `nesting="heading"`, where a branch names the list under it.
25
25
  *
26
+ * A `disabled` item is reached by the arrow keys and announced as unavailable,
27
+ * and a press, Enter or Space on it does nothing.
28
+ *
29
+ * A `lazy` item is a branch whose children you load when it opens: opening it
30
+ * sends `helix-load`, the row says it is busy, and the children you add appear
31
+ * in it. Remove `lazy` once they are in.
32
+ *
26
33
  * @since 0.1.0
27
34
  * @status stable
28
35
  * @aliases TreeNode, Branch, Leaf
29
36
  * @documentation https://fusion.dev/helix/components/tree
30
37
  *
31
38
  * @slot - The item's label.
39
+ * @slot chevron - Replaces the expand and collapse mark of a branch, such as with your own icon.
32
40
  * @slot children - Nested items, which make this a branch.
33
41
  * @slot end - Content after the label, at the far side of the row, such as a count or a state.
34
42
  * @slot start - Content before the label and after the chevron, such as a mark for the item.
35
43
  *
36
44
  * @event {HelixBeforeCloseEvent} helix-before-close - Fired before a branch closes, and cancelable.
37
45
  * @event {HelixBeforeOpenEvent} helix-before-open - Fired before a branch opens, and cancelable.
46
+ * @event {HelixLoadEvent} helix-load - Fired when a `lazy` item opens, so you can load its children.
38
47
  * @event {HelixSelectEvent} helix-select - Fired when the item is chosen, and cancelable. Canceling it changes nothing.
39
48
  * @event {ToggleEvent} toggle - Sent when the branch opens or closes, with `newState` and `oldState`.
40
49
  *
50
+ * @csspart checkbox - The check mark's box, in a tree with `selection-mode="multiple"`.
51
+ * @csspart checkbox-checked - The check mark's box while the item is checked.
52
+ * @csspart checkbox-mixed - The check mark's box while some of a branch's items are checked.
41
53
  * @csspart group - The container for nested items.
42
54
  * @csspart item - The node, and the focus target unless `href` moves it to the row.
43
55
  * @csspart label - The label text.
@@ -46,10 +58,26 @@ declare const HelixHeadlessTreeItem_base: (new (...args: any[]) => import("@fusi
46
58
  *
47
59
  * @cssproperty --tree-level - How deep this row sits, counting from one as `aria-level` does, for the indent.
48
60
  *
61
+ * @cssstate loading - While a `lazy` item is open and its children have not arrived.
49
62
  * @cssstate open - While its children are shown.
50
63
  * @cssstate selected - While it is selected.
51
64
  */
52
65
  export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
66
+ /**
67
+ * @internal Set by the tree: whether the item draws a check mark and is
68
+ * checked rather than selected, as under `selection-mode="multiple"`.
69
+ */
70
+ checkable: boolean;
71
+ /**
72
+ * @internal Set by the tree in `selection-mode="multiple"`: whether the item
73
+ * is checked, `mixed` for a branch some of whose items are.
74
+ */
75
+ checked: boolean | 'mixed';
76
+ /**
77
+ * Whether the item cannot be chosen, opened or followed. The arrow keys still
78
+ * reach it, so a reader knows it is there.
79
+ */
80
+ disabled: boolean;
53
81
  /**
54
82
  * @internal Set by the tree: whether a branch heads the list under it, as
55
83
  * under `nesting="heading"`. Such a branch only opens and closes when it is
@@ -64,6 +92,13 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
64
92
  * current page on every item a consumer never asked to be one.
65
93
  */
66
94
  href: string;
95
+ /**
96
+ * Whether the item is a branch whose children are loaded when it opens.
97
+ *
98
+ * Opening it sends `helix-load`. Add the children to its `children` slot,
99
+ * and remove `lazy` once they are in, as Web Awesome's tree item does.
100
+ */
101
+ lazy: boolean;
67
102
  /**
68
103
  * The node's depth from the root. The tree counts it, so indentation needs no
69
104
  * nested CSS.
@@ -151,7 +186,7 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
151
186
  * row rather than the wrapper around it.
152
187
  */
153
188
  focusItem(): void;
154
- /** Selects this node and sends `helix-select`. */
189
+ /** Selects this node and sends `helix-select`. A disabled node sends nothing. */
155
190
  select(): void;
156
191
  /**
157
192
  * Chooses this node, as a press or Enter does.
@@ -163,6 +198,13 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
163
198
  * value and nothing listens for it.
164
199
  */
165
200
  activate(): void;
201
+ /**
202
+ * Opens or closes a branch, unless the item is disabled.
203
+ *
204
+ * Every press and key that opens a branch comes through here, so `disabled`
205
+ * holds for all of them. A script can still set `open`.
206
+ */
207
+ toggleOpen(): boolean;
166
208
  /**
167
209
  * Follows a link slotted into the name, if there is one.
168
210
  *
@@ -184,8 +226,17 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
184
226
  * its children.
185
227
  */
186
228
  private follow;
229
+ /** A press on the check mark checks the item and leaves a branch as it is. */
230
+ private readonly handleCheckClick;
187
231
  private readonly handleToggleClick;
188
232
  private readonly handleRowClick;
233
+ /**
234
+ * The expand and collapse mark of a branch, as the `chevron` slot's
235
+ * fallback, so an icon of your own replaces it by being slotted.
236
+ */
237
+ protected renderToggle(): TemplateResult;
238
+ /** The check mark, in a tree with `selection-mode="multiple"`. */
239
+ private renderCheckbox;
189
240
  /** Everything inside the row, which is the same whichever element it is. */
190
241
  private renderRow;
191
242
  /**
@@ -204,6 +255,8 @@ export declare class HelixHeadlessTreeItem extends HelixHeadlessTreeItem_base {
204
255
  * a consumer's markup means. What stops is the write back.
205
256
  */
206
257
  protected willUpdate(changed: PropertyValues): void;
258
+ /** Asks for a lazy branch's children when it opens. */
259
+ protected updated(changed: PropertyValues): void;
207
260
  protected render(): TemplateResult;
208
261
  }
209
262
  declare global {