@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
@@ -0,0 +1,60 @@
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 } from '@fusion.dev/helix-core';
8
+ import { html, nothing } from 'lit';
9
+ import { property, state } from 'lit/decorators.js';
10
+ let HelixHeadlessMenuSection = class HelixHeadlessMenuSection extends HelixElement {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.label = '';
14
+ this.onPage = true;
15
+ this.isMenuSection = true;
16
+ this.heading = false;
17
+ this.readHeading = (event) => {
18
+ this.heading = event.target.assignedNodes().length > 0;
19
+ };
20
+ }
21
+ willUpdate(changed) {
22
+ super.willUpdate(changed);
23
+ if (this.childrenKnown) {
24
+ this.heading = this.knownChildren.some((child) => child.slot === 'heading');
25
+ }
26
+ }
27
+ firstUpdated(changed) {
28
+ super.firstUpdated(changed);
29
+ this.finishHydration();
30
+ }
31
+ render() {
32
+ if (!this.onPage) {
33
+ return nothing;
34
+ }
35
+ return html `<div part="section" role="group" aria-labelledby="heading">
36
+ <div
37
+ id="heading"
38
+ part="heading"
39
+ role="presentation"
40
+ ?hidden=${this.label === '' && !this.heading}
41
+ >
42
+ <slot name="heading" @slotchange=${this.readHeading}>${this.label}</slot>
43
+ </div>
44
+ <slot></slot>
45
+ </div>`;
46
+ }
47
+ };
48
+ __decorate([
49
+ property()
50
+ ], HelixHeadlessMenuSection.prototype, "label", void 0);
51
+ __decorate([
52
+ property({ attribute: false })
53
+ ], HelixHeadlessMenuSection.prototype, "onPage", void 0);
54
+ __decorate([
55
+ state()
56
+ ], HelixHeadlessMenuSection.prototype, "heading", void 0);
57
+ HelixHeadlessMenuSection = __decorate([
58
+ customElement('helix-headless-menu-section')
59
+ ], HelixHeadlessMenuSection);
60
+ export { HelixHeadlessMenuSection };
@@ -1,4 +1,4 @@
1
- import { AriaForwardController, HelixElement } 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
  /**
4
4
  * @summary A set of destinations, with a marker on the current one.
@@ -22,6 +22,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
22
22
  * Set `orientation="vertical"` to stack the destinations in a column, for a
23
23
  * sidebar.
24
24
  *
25
+ * Set `arrows` and the arrow keys move focus between the destinations, as
26
+ * Radix's navigation menu does: left and right along a row, up and down a
27
+ * column, Home and End to the ends. A `Megamenu` among them is reached at its
28
+ * trigger. Tab still stops at every link, since a navigation is a list of
29
+ * links and not a single control, and the keys across the other axis are
30
+ * left to the page and to an open panel.
31
+ *
25
32
  * @since 0.1.0
26
33
  * @status stable
27
34
  * @category navigation
@@ -35,6 +42,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
35
42
  */
36
43
  export declare class HelixHeadlessNavigation extends HelixElement {
37
44
  private readonly indicator;
45
+ /**
46
+ * Whether the arrow keys move focus between the destinations.
47
+ *
48
+ * Off by default, so a page whose readers scroll with the arrow keys while
49
+ * a link has focus keeps doing so.
50
+ */
51
+ arrows: boolean;
38
52
  /**
39
53
  * The landmark's name, read by screen readers.
40
54
  *
@@ -43,6 +57,7 @@ export declare class HelixHeadlessNavigation extends HelixElement {
43
57
  * second "Main".
44
58
  */
45
59
  label: string;
60
+ protected readonly keys: KeyboardNavigationController;
46
61
  /** Carries a host `aria-label` and `aria-labelledby` to the `<nav>`. */
47
62
  protected readonly aria: AriaForwardController;
48
63
  /**
@@ -4,9 +4,24 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { AriaForwardController, customElement, HelixElement, IndicatorController, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, focusableElements, HelixElement, IndicatorController, KeyboardNavigationController, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ const FOCUSABLE = 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])';
11
+ const navigable = (item) => {
12
+ const control = () => item.navigationControl ??
13
+ (item.matches(FOCUSABLE) ? item : focusableElements(item)[0]);
14
+ return {
15
+ contains: (node) => {
16
+ const target = control();
17
+ return target !== undefined && node !== null && (node === target || target.contains(node));
18
+ },
19
+ disabled: false,
20
+ focusItem: () => control()?.focus(),
21
+ select: () => { },
22
+ selected: false,
23
+ };
24
+ };
10
25
  let HelixHeadlessNavigation = class HelixHeadlessNavigation extends HelixElement {
11
26
  constructor() {
12
27
  super(...arguments);
@@ -23,7 +38,15 @@ let HelixHeadlessNavigation = class HelixHeadlessNavigation extends HelixElement
23
38
  observe: () => this.items,
24
39
  surface: () => this.partNamed('nav'),
25
40
  });
41
+ this.arrows = false;
26
42
  this.label = 'Main';
43
+ this.keys = new KeyboardNavigationController(this, {
44
+ items: () => (this.arrows ? this.items.map(navigable) : []),
45
+ origin: 'focus',
46
+ reserved: () => this.orientation === 'vertical' ? ['ArrowLeft', 'ArrowRight'] : ['ArrowDown', 'ArrowUp'],
47
+ selects: () => false,
48
+ wrap: false,
49
+ });
27
50
  this.aria = new AriaForwardController(this, {
28
51
  label: true,
29
52
  target: () => this.partNamed('nav'),
@@ -62,6 +85,9 @@ let HelixHeadlessNavigation = class HelixHeadlessNavigation extends HelixElement
62
85
  </nav>`;
63
86
  }
64
87
  };
88
+ __decorate([
89
+ property({ type: Boolean })
90
+ ], HelixHeadlessNavigation.prototype, "arrows", void 0);
65
91
  __decorate([
66
92
  property()
67
93
  ], HelixHeadlessNavigation.prototype, "label", void 0);
@@ -29,6 +29,11 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
29
29
  * the feed holds one page of a longer list, and each row says its place in the
30
30
  * whole of it.
31
31
  *
32
+ * **`load-more` adds a button after the list** that sends `helix-load-more`,
33
+ * for a feed that holds one page of a longer list. Append the next page, set
34
+ * `loading` while it is on its way, and take `load-more` off once there is
35
+ * nothing more. The button is hidden while the feed is loading.
36
+ *
32
37
  * @since 0.1.0
33
38
  * @status stable
34
39
  * @category feedback
@@ -40,6 +45,7 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
40
45
  * @slot header - Above the list, for a title and the mark-all control.
41
46
  *
42
47
  * @event {HelixDismissEvent} helix-dismiss - Fired when the user dismisses a row. The row dispatches it, and you can listen for it on the feed. Cancelable: cancel it to keep the row.
48
+ * @event {HelixLoadMoreEvent} helix-load-more - Fired when a reader presses the `load-more` button, asking for the next page of the feed.
43
49
  * @event {HelixReadEvent} helix-read - Fired by an item when it is marked read or unread, and by the feed when everything is marked read. Cancelable.
44
50
  *
45
51
  * @csspart empty - Shown when there is nothing in the feed.
@@ -49,6 +55,7 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
49
55
  * @csspart live - A copy of the empty and loading messages, in a live region that screen readers announce when they change. Visually hidden in the styled tier.
50
56
  * @csspart loading - Shown while the feed is loading.
51
57
  * @csspart mark-all - The control that marks everything read.
58
+ * @csspart more - The button after the list that asks for more, while `load-more` is set and the feed is not loading.
52
59
  *
53
60
  * @cssstate media - While a notification in the list holds something in its media slot, so every row keeps that column.
54
61
  */
@@ -67,6 +74,15 @@ export declare class HelixHeadlessNotifications extends HelixHeadlessNotificatio
67
74
  * The feed's name, read by screen readers.
68
75
  */
69
76
  label: string;
77
+ /**
78
+ * Whether to draw a button after the list that asks for the next page, by
79
+ * sending `helix-load-more`. Take it off once there is nothing more.
80
+ */
81
+ loadMore: boolean;
82
+ /**
83
+ * The text of the `load-more` button.
84
+ */
85
+ loadMoreLabel: string;
70
86
  /**
71
87
  * Whether to draw a control that marks everything read.
72
88
  */
@@ -244,6 +260,8 @@ export declare class HelixHeadlessNotifications extends HelixHeadlessNotificatio
244
260
  private markEmpty;
245
261
  protected updated(changed: PropertyValues): void;
246
262
  protected render(): TemplateResult;
263
+ /** Asks for the next page, for the `load-more` button. */
264
+ private readonly askForMore;
247
265
  /**
248
266
  * Marks everything read, and keeps focus in the feed.
249
267
  *
@@ -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, deepContains, focusableElements, HelixElement, HelixReadEvent, hostAria, MixinCollection, markRegion, rovingStop, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { customElement, deepContains, focusableElements, HelixElement, HelixLoadMoreEvent, HelixReadEvent, hostAria, MixinCollection, markRegion, rovingStop, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { feedStep } from '../feed-keys.js';
@@ -12,6 +12,8 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
12
12
  constructor() {
13
13
  super(...arguments);
14
14
  this.label = '';
15
+ this.loadMore = false;
16
+ this.loadMoreLabel = 'Load more';
15
17
  this.markAll = false;
16
18
  this.markAllLabel = 'Mark all as read';
17
19
  this.handleSlotChange = () => {
@@ -51,6 +53,9 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
51
53
  rowBox(next)?.focus();
52
54
  }
53
55
  };
56
+ this.askForMore = () => {
57
+ this.dispatchEvent(new HelixLoadMoreEvent());
58
+ };
54
59
  this.handleMarkAll = (event) => {
55
60
  const button = event.currentTarget;
56
61
  const focused = this.shadowRoot?.activeElement === button;
@@ -210,12 +215,23 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
210
215
  ${this.renderStatus(hasItems)}
211
216
  </div>
212
217
  ${this.renderLive(hasItems)}
218
+ ${this.loadMore && !this.loading
219
+ ? html `<button part="more" type="button" @click=${this.askForMore}>
220
+ ${this.loadMoreLabel}
221
+ </button>`
222
+ : nothing}
213
223
  <div part="footer"><slot name="footer"></slot></div>`;
214
224
  }
215
225
  };
216
226
  __decorate([
217
227
  property()
218
228
  ], HelixHeadlessNotifications.prototype, "label", void 0);
229
+ __decorate([
230
+ property({ attribute: 'load-more', type: Boolean })
231
+ ], HelixHeadlessNotifications.prototype, "loadMore", void 0);
232
+ __decorate([
233
+ property({ attribute: 'load-more-label' })
234
+ ], HelixHeadlessNotifications.prototype, "loadMoreLabel", void 0);
219
235
  __decorate([
220
236
  property({ attribute: 'mark-all', type: Boolean })
221
237
  ], HelixHeadlessNotifications.prototype, "markAll", void 0);
@@ -1,18 +1,7 @@
1
1
  import { AriaForwardController, HelixElement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import '../../copy-button/index.js';
4
- /** One visible line of the tree: a value, where it sits, and whether it is open. */
5
- interface Row {
6
- branch: boolean;
7
- depth: number;
8
- /** The property name or array index this value is under; absent for the root. */
9
- key?: string;
10
- open: boolean;
11
- path: string;
12
- position: number;
13
- siblings: number;
14
- value: unknown;
15
- }
4
+ import { type Row } from '../rows.js';
16
5
  /**
17
6
  * @summary A structured value shown as a tree, where you can close branches,
18
7
  * see how many entries each holds, and copy any part.
@@ -34,6 +23,22 @@ interface Row {
34
23
  * row. Each row carries its real level, position, and set size, including in
35
24
  * a windowed tree.
36
25
  *
26
+ * `active` is the active row's path, written the way a JSON Pointer writes it:
27
+ * the empty string for the root and `/meta/tags/0` for an entry under it.
28
+ * Moving to another row sends `helix-before-activate`, which you can cancel,
29
+ * and then `helix-activate`, both with the path. Writing `active` moves there
30
+ * and opens the branches around it, and sends nothing. `expanded` holds the
31
+ * open branches by path, and writing it opens those and closes the rest. A row
32
+ * that closes around the active one hands it to the nearest open branch.
33
+ *
34
+ * `filter` narrows the tree to the entries whose key or value holds the text,
35
+ * ignoring case, and the branches that lead to them, which it opens. A matched
36
+ * branch keeps everything under it. Each matched row carries `row-match`, and
37
+ * a screen reader hears how many entries matched from `result-label` and
38
+ * `results-label`. `filterable` adds a field that sets it: typing sends
39
+ * `helix-filter`, which you can cancel, and then `helix-filtered`, and Down
40
+ * moves from the field to the tree.
41
+ *
37
42
  * A new `value` keeps the branches a reader opened or closed, and the active
38
43
  * row, where the new value still has them. A branch the old value did not have
39
44
  * opens to `default-depth`.
@@ -53,7 +58,11 @@ interface Row {
53
58
  * @aliases JSON viewer, Object viewer, Inspector, Data explorer
54
59
  * @documentation https://fusion.dev/helix/components/object-inspector
55
60
  *
61
+ * @event {HelixActivateEvent} helix-activate - The active row moved, by a key or a click. The detail's `value` is its path.
62
+ * @event {HelixBeforeActivateEvent} helix-before-activate - The active row is about to move, with its new path. Cancelable: cancel it to keep the row where it is.
56
63
  * @event {HelixCopyEvent} helix-copy - A value was put on the clipboard, from the copy button or the keyboard.
64
+ * @event {HelixFilterEvent} helix-filter - Text was typed in the filter field, with what it now holds. Cancelable: cancel it to keep the filter as it was.
65
+ * @event {HelixFilteredEvent} helix-filtered - The filter field changed `filter`, which now holds the text.
57
66
  *
58
67
  * @csspart after - The space the rows below the drawn rows would take, when `windowed` is set.
59
68
  * @csspart before - The space the rows above the drawn rows would take, when `windowed` is set.
@@ -78,10 +87,13 @@ interface Row {
78
87
  * @csspart header - The bar that holds the label, when there is one.
79
88
  * @csspart key - A property name or an array index.
80
89
  * @csspart label - The label.
90
+ * @csspart live - How many entries a filter matched, in a region that screen readers announce when it changes. Drawn from the first filter on. Visually hidden in the styled tier.
81
91
  * @csspart null - A `null`.
82
92
  * @csspart number - A number.
83
93
  * @csspart row - One entry, as a tree item.
84
94
  * @csspart row-active - The entry the keyboard is on. Set alongside `row`.
95
+ * @csspart row-match - An entry whose key or value holds the filter. Set alongside `row`.
96
+ * @csspart search-field - The field that sets `filter`, with `filterable`.
85
97
  * @csspart string - A string, in quotes.
86
98
  * @csspart summary - The brackets that stand for a branch's contents.
87
99
  * @csspart toggle - The caret on a branch. It points down when the branch is open and sideways when it is closed.
@@ -90,6 +102,17 @@ interface Row {
90
102
  * @cssproperty --object-inspector-level - How deep a row is, from 0 at the root, for indenting it.
91
103
  */
92
104
  export declare class HelixHeadlessObjectInspector extends HelixElement {
105
+ /**
106
+ * The active row's path, such as `/meta/tags/0`, and the empty string for the
107
+ * root.
108
+ *
109
+ * Reading gives the row the keys are on. Writing moves there, opening the
110
+ * branches around it, and sends no event, the way a script's write to any
111
+ * current value sends none. A path the value does not hold moves to the
112
+ * nearest branch above it that it does.
113
+ */
114
+ get active(): string;
115
+ set active(path: string);
93
116
  /**
94
117
  * The copy button's accessible name on a row with a key, with the key filled
95
118
  * in as `{name}`.
@@ -109,6 +132,23 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
109
132
  * wall of text this exists to avoid.
110
133
  */
111
134
  defaultDepth: number;
135
+ /**
136
+ * The open branches, by path, in no set order.
137
+ *
138
+ * Writing opens exactly these and closes every other, keeping the active row
139
+ * where it stays visible. A property, never an attribute.
140
+ */
141
+ get expanded(): string[];
142
+ set expanded(paths: string[]);
143
+ /**
144
+ * Text the tree is narrowed to: the entries whose key or value holds it,
145
+ * ignoring case, and the branches that lead to them. Empty shows everything.
146
+ */
147
+ filter: string;
148
+ /** Whether to show a field that sets `filter`. */
149
+ filterable: boolean;
150
+ /** The filter field's placeholder and accessible name. */
151
+ filterLabel: string;
112
152
  /**
113
153
  * The id of a `<script type="application/json">` holding the value.
114
154
  *
@@ -143,6 +183,13 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
143
183
  * reach a value.
144
184
  */
145
185
  noCopy: boolean;
186
+ /** What a screen reader hears when a filter matches one entry. `{count}` is the count. */
187
+ resultLabel: string;
188
+ /**
189
+ * What a screen reader hears when a filter matches any other number of
190
+ * entries. `{count}` is the count. The two are chosen by `Intl.PluralRules`.
191
+ */
192
+ resultsLabel: string;
146
193
  /**
147
194
  * The tree's accessible name when `label` is empty and the host names it
148
195
  * with neither `aria-label` nor `aria-labelledby`.
@@ -169,7 +216,18 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
169
216
  /** Which branches are open, by path. */
170
217
  private opened;
171
218
  /** The row the arrow keys are on, by its place among the visible rows. */
172
- private active;
219
+ private cursor;
220
+ /** A path written to `active` and not yet found among the rows. */
221
+ private wanted;
222
+ /**
223
+ * The branches written to `expanded`, until the next update applies them.
224
+ *
225
+ * Its own field, because a property declared with an accessor is in the
226
+ * first update's changes whether or not anybody wrote it.
227
+ */
228
+ private declared;
229
+ /** The paths the filter matched, or nothing while there is no filter. */
230
+ private found;
173
231
  /** Set by a keyboard move, so the next render brings the active row into view. */
174
232
  private revealing;
175
233
  /** What has been typed toward a key, and when the last letter came. */
@@ -178,6 +236,8 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
178
236
  private branches;
179
237
  /** Carries a host `aria-label` and `aria-labelledby` to the tree, which is what takes focus. */
180
238
  protected readonly aria: AriaForwardController;
239
+ /** Says how many entries a filter matched. */
240
+ private readonly status;
181
241
  /**
182
242
  * How tall a row is taken to be before it has been drawn, in pixels.
183
243
  *
@@ -193,8 +253,6 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
193
253
  /** Every visible row, in order, worked out once per change rather than per read. */
194
254
  private rows;
195
255
  private readonly copier;
196
- /** Every visible row, in order, for the tree as it stands. */
197
- private flatten;
198
256
  /**
199
257
  * Opens every branch shallower than `defaultDepth`.
200
258
  *
@@ -205,7 +263,17 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
205
263
  * place on every update.
206
264
  */
207
265
  private seed;
266
+ /** Opens the branches around each path, where the value has them. */
267
+ private openAround;
208
268
  protected willUpdate(changed: PropertyValues): void;
269
+ /**
270
+ * Where the active row goes once the rows have moved: onto `path` where it
271
+ * is still shown, onto the first match where a filter just hid it, and
272
+ * otherwise onto the nearest branch around it that is.
273
+ */
274
+ private place;
275
+ /** Says how many entries the filter matched, and nothing for an empty one. */
276
+ private tell;
209
277
  protected firstUpdated(changed: PropertyValues): void;
210
278
  protected updated(changed: PropertyValues): void;
211
279
  private load;
@@ -225,6 +293,10 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
225
293
  /** What copying takes: a branch as indented JSON, a string as itself. */
226
294
  private copyable;
227
295
  private toggle;
296
+ /**
297
+ * Moves the active row, asking first: `helix-before-activate` with the path,
298
+ * then `helix-activate` once it has moved. Returns whether it is there.
299
+ */
228
300
  private move;
229
301
  private readonly handleKeydown;
230
302
  /** Opens every branch at the active row's level under the same parent, as `*` asks. */
@@ -237,7 +309,12 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
237
309
  * keys that start with it.
238
310
  */
239
311
  private typeahead;
312
+ /** A press opens or closes the row it lands on, once that row is the active one. */
240
313
  private handleRowClick;
314
+ /** Text typed in the filter field, asked for before the tree narrows to it. */
315
+ private readonly handleFilterInput;
316
+ /** Down from the filter field goes to the tree, where the matches are. */
317
+ private readonly handleFilterKeydown;
241
318
  private renderValue;
242
319
  /**
243
320
  * One entry, named for its state where it holds one.
@@ -248,6 +325,11 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
248
325
  * attribute would be a second spelling with no reader. The name is the one a
249
326
  * consumer can reach, nothing being able to follow `::part()` with an
250
327
  * attribute selector.
328
+ *
329
+ * **`aria-selected="false"` on every row**, because nothing here is chosen.
330
+ * Chromium takes the active descendant of a single-selection tree as selected
331
+ * when no row says otherwise, so every arrow press was also announced as a
332
+ * selection. An explicit false is the one thing that turns that off.
251
333
  */
252
334
  private renderRow;
253
335
  /** The copy button, behind the seam Code Block's uses, so each tier renders its own. */
@@ -259,4 +341,3 @@ declare global {
259
341
  'helix-headless-object-inspector': HelixHeadlessObjectInspector;
260
342
  }
261
343
  }
262
- export {};