@fusion.dev/helix-headless 0.156.0 → 0.157.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.
@@ -25,6 +25,16 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
25
25
  * `aria-haspopup`, the same way `Menu` marks a row with a submenu. The server
26
26
  * render leaves both out, because the server cannot see the children.
27
27
  *
28
+ * **A row with an `href` is a link.** The row itself renders as an `<a>`
29
+ * carrying `menuitem`, as `Menu.Item` does, so a middle click, a modified
30
+ * click and the status bar keep working. Enter follows it, and Space does too.
31
+ * Choosing it fires `helix-select` first: cancel the event and the link is not
32
+ * followed, so a router can take the navigation. A row that opens a page, or a
33
+ * disabled row, renders no link.
34
+ *
35
+ * A development build warns when a row has no words to be named by, such as a
36
+ * row holding only an icon with no label.
37
+ *
28
38
  * The row is named by its label alone. Words in `description`, a line under
29
39
  * the label, and in `end` describe it instead, through `aria-describedby`, as
30
40
  * `Menu.Item` does: a reader hears "Theme", then "Dark".
@@ -43,7 +53,7 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
43
53
  *
44
54
  * @event {HelixSelectEvent} helix-select - Fired when the row is chosen. Cancelable: canceling it stops the change and leaves the decision to you.
45
55
  *
46
- * @csspart item - The row itself.
56
+ * @csspart item - The row itself, which is an `<a>` where `href` is set.
47
57
  * @csspart label - The row's label.
48
58
  * @csspart mark - The caret at the end of a row that opens a page, after the `end` slot. The caret points, so a stylesheet mirrors it in a right-to-left document.
49
59
  */
@@ -52,6 +62,11 @@ export declare class HelixHeadlessDrilldownItem extends HelixElement {
52
62
  * Whether the row can be reached at all.
53
63
  */
54
64
  disabled: boolean;
65
+ /**
66
+ * Whether the link downloads the file when the row is chosen. Only
67
+ * meaningful beside an `href`, and only for a file served from this origin.
68
+ */
69
+ download: boolean;
55
70
  /**
56
71
  * Whether this row holds the region's tab stop. Set by the drill-down.
57
72
  *
@@ -66,6 +81,16 @@ export declare class HelixHeadlessDrilldownItem extends HelixElement {
66
81
  * lands inside this shadow root instead.
67
82
  */
68
83
  focusable: boolean;
84
+ /**
85
+ * The URL the row links to. Setting it renders the row as a link, unless the
86
+ * row opens a page or is disabled.
87
+ */
88
+ href: string;
89
+ /**
90
+ * @internal Whether the row is a list item of a drilldown with
91
+ * `navigation`. Written by the stack.
92
+ */
93
+ listed: boolean;
69
94
  /**
70
95
  * @internal Read by a parent to identify its children across the light DOM,
71
96
  * which is cheaper than `instanceof` and is why this is public rather than
@@ -83,11 +108,19 @@ export declare class HelixHeadlessDrilldownItem extends HelixElement {
83
108
  * level. Written by the stack.
84
109
  */
85
110
  onPath: boolean;
111
+ /**
112
+ * The link's `rel`. Set it whenever you set `target="_blank"`.
113
+ */
114
+ rel: string;
86
115
  /**
87
116
  * @internal Whether this row's own page is the one showing. Written by the
88
117
  * stack.
89
118
  */
90
119
  showingPage: boolean;
120
+ /**
121
+ * Where the link opens, for rows that should open outside the current page.
122
+ */
123
+ target: string;
91
124
  /**
92
125
  * Identifies the row to your event listeners.
93
126
  */
@@ -113,6 +146,7 @@ export declare class HelixHeadlessDrilldownItem extends HelixElement {
113
146
  * that skipped.
114
147
  */
115
148
  protected willUpdate(changed: PropertyValues): void;
149
+ protected updated(changed: PropertyValues): void;
116
150
  protected firstUpdated(changed: PropertyValues): void;
117
151
  /**
118
152
  * Re-reads whether a page is slotted, from whichever `page` slot is current.
@@ -154,6 +188,20 @@ export declare class HelixHeadlessDrilldownItem extends HelixElement {
154
188
  get selected(): boolean;
155
189
  /** Fires `helix-select` for this row. */
156
190
  select(): void;
191
+ /** Fires `helix-select`, and returns whether the choice stood. */
192
+ private choose;
193
+ /**
194
+ * A press on the row. On a link, a refused `helix-select` stops the link
195
+ * from being followed, so a router can take the navigation.
196
+ */
197
+ private readonly handleClick;
198
+ /**
199
+ * Space on a link presses it, which an anchor does not do on its own. Enter
200
+ * is the anchor's, which fires a click and follows the link.
201
+ */
202
+ private readonly handleLinkKeydown;
203
+ /** Whether the row renders as a link. */
204
+ private get linked();
157
205
  /**
158
206
  * The caret of a row that opens a page, as the `chevron` slot's fallback, so
159
207
  * an icon of your own replaces it by being slotted.
@@ -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, deepActiveElement, HelixElement, HelixSelectEvent, slotFilled, slotNamed, } from '@fusion.dev/helix-core';
7
+ import { auditName, customElement, deepActiveElement, HelixElement, HelixSelectEvent, hostAria, slotFilled, slotNamed, } from '@fusion.dev/helix-core';
8
8
  import { caretRight } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -13,11 +13,16 @@ let HelixHeadlessDrilldownItem = class HelixHeadlessDrilldownItem extends HelixE
13
13
  constructor() {
14
14
  super(...arguments);
15
15
  this.disabled = false;
16
+ this.download = false;
16
17
  this.focusable = false;
18
+ this.href = '';
19
+ this.listed = false;
17
20
  this.isDrilldownItem = true;
18
21
  this.onPage = true;
19
22
  this.onPath = false;
23
+ this.rel = '';
20
24
  this.showingPage = false;
25
+ this.target = '';
21
26
  this.value = '';
22
27
  this.page = false;
23
28
  this.description = false;
@@ -30,9 +35,23 @@ let HelixHeadlessDrilldownItem = class HelixHeadlessDrilldownItem extends HelixE
30
35
  this.description = slotFilled(slotNamed(this.renderRoot, 'description'));
31
36
  this.end = slotFilled(slotNamed(this.renderRoot, 'end'));
32
37
  };
38
+ this.handleClick = (event) => {
39
+ if (!this.choose() && this.linked) {
40
+ event.preventDefault();
41
+ }
42
+ };
43
+ this.handleLinkKeydown = (event) => {
44
+ if (event.key !== ' ') {
45
+ return;
46
+ }
47
+ event.preventDefault();
48
+ event.currentTarget.click();
49
+ };
33
50
  }
34
51
  willUpdate(changed) {
35
52
  super.willUpdate(changed);
53
+ const item = this.listed && this.onPage && !this.showingPage && !this.onPath;
54
+ hostAria(this.internals, { role: item ? 'listitem' : '' });
36
55
  if (this.childrenKnown) {
37
56
  const named = (name) => this.knownChildren.some((child) => child.slot === name);
38
57
  this.page = named('page');
@@ -40,6 +59,12 @@ let HelixHeadlessDrilldownItem = class HelixHeadlessDrilldownItem extends HelixE
40
59
  this.end = named('end');
41
60
  }
42
61
  }
62
+ updated(changed) {
63
+ super.updated(changed);
64
+ if (this.partNamed('item')) {
65
+ auditName(this, () => this.partNamed('item'), 'Give the row words in its default slot, or a label on the icon it holds.');
66
+ }
67
+ }
43
68
  firstUpdated(changed) {
44
69
  super.firstUpdated(changed);
45
70
  this.finishHydration();
@@ -61,10 +86,16 @@ let HelixHeadlessDrilldownItem = class HelixHeadlessDrilldownItem extends HelixE
61
86
  return this.active;
62
87
  }
63
88
  select() {
89
+ this.choose();
90
+ }
91
+ choose() {
64
92
  if (this.disabled) {
65
- return;
93
+ return false;
66
94
  }
67
- this.dispatchEvent(new HelixSelectEvent({ value: this.value }));
95
+ return this.dispatchEvent(new HelixSelectEvent({ value: this.value }));
96
+ }
97
+ get linked() {
98
+ return this.href !== '' && !this.disabled && !this.page;
68
99
  }
69
100
  renderMark() {
70
101
  return html `<slot name="chevron" aria-hidden="true"
@@ -80,18 +111,7 @@ let HelixHeadlessDrilldownItem = class HelixHeadlessDrilldownItem extends HelixE
80
111
  if (!this.onPage) {
81
112
  return nothing;
82
113
  }
83
- return html `<button
84
- part="item"
85
- type="button"
86
- role="menuitem"
87
- aria-describedby=${this.describedBy}
88
- aria-disabled=${this.disabled ? 'true' : nothing}
89
- aria-haspopup=${this.page ? 'menu' : nothing}
90
- tabindex=${this.focusable ? '0' : '-1'}
91
- ?data-described=${this.description}
92
- @click=${() => this.select()}
93
- >
94
- <slot name="start"></slot>
114
+ const inside = html `<slot name="start"></slot>
95
115
  <span part="label"><slot></slot></span>
96
116
  <slot
97
117
  id="description"
@@ -101,26 +121,66 @@ let HelixHeadlessDrilldownItem = class HelixHeadlessDrilldownItem extends HelixE
101
121
  @slotchange=${this.readWords}
102
122
  ></slot>
103
123
  <slot id="end" name="end" aria-hidden="true" @slotchange=${this.readWords}></slot>
104
- ${this.page ? this.renderMark() : nothing}
105
- </button>
124
+ ${this.page ? this.renderMark() : nothing}`;
125
+ const row = this.linked
126
+ ? html `<a
127
+ part="item"
128
+ href=${this.href}
129
+ target=${this.target || nothing}
130
+ rel=${this.rel || nothing}
131
+ ?download=${this.download}
132
+ role=${this.listed ? nothing : 'menuitem'}
133
+ aria-describedby=${this.describedBy}
134
+ tabindex=${this.focusable ? '0' : '-1'}
135
+ ?data-described=${this.description}
136
+ @click=${this.handleClick}
137
+ @keydown=${this.handleLinkKeydown}
138
+ >${inside}</a>`
139
+ : html `<button
140
+ part="item"
141
+ type="button"
142
+ role=${this.listed ? nothing : 'menuitem'}
143
+ aria-describedby=${this.describedBy}
144
+ aria-disabled=${this.disabled ? 'true' : nothing}
145
+ aria-haspopup=${this.page && !this.listed ? 'menu' : nothing}
146
+ tabindex=${this.focusable ? '0' : '-1'}
147
+ ?data-described=${this.description}
148
+ @click=${this.handleClick}
149
+ >${inside}</button>`;
150
+ return html `${row}
106
151
  <div hidden><slot name="page" @slotchange=${this.readPage}></slot></div>`;
107
152
  }
108
153
  };
109
154
  __decorate([
110
155
  property({ reflect: true, type: Boolean })
111
156
  ], HelixHeadlessDrilldownItem.prototype, "disabled", void 0);
157
+ __decorate([
158
+ property({ type: Boolean })
159
+ ], HelixHeadlessDrilldownItem.prototype, "download", void 0);
112
160
  __decorate([
113
161
  property({ attribute: false })
114
162
  ], HelixHeadlessDrilldownItem.prototype, "focusable", void 0);
163
+ __decorate([
164
+ property()
165
+ ], HelixHeadlessDrilldownItem.prototype, "href", void 0);
166
+ __decorate([
167
+ property({ attribute: false })
168
+ ], HelixHeadlessDrilldownItem.prototype, "listed", void 0);
115
169
  __decorate([
116
170
  property({ attribute: false })
117
171
  ], HelixHeadlessDrilldownItem.prototype, "onPage", void 0);
118
172
  __decorate([
119
173
  property({ attribute: false })
120
174
  ], HelixHeadlessDrilldownItem.prototype, "onPath", void 0);
175
+ __decorate([
176
+ property()
177
+ ], HelixHeadlessDrilldownItem.prototype, "rel", void 0);
121
178
  __decorate([
122
179
  property({ attribute: false })
123
180
  ], HelixHeadlessDrilldownItem.prototype, "showingPage", void 0);
181
+ __decorate([
182
+ property()
183
+ ], HelixHeadlessDrilldownItem.prototype, "target", void 0);
124
184
  __decorate([
125
185
  property()
126
186
  ], HelixHeadlessDrilldownItem.prototype, "value", void 0);
@@ -20,6 +20,11 @@ declare const HelixHeadlessDrilldown_base: (new (...args: any[]) => import("@fus
20
20
  * and reads the rest from the DOM. The behavior lives in `DrilldownController`,
21
21
  * which `Menu` shares.
22
22
  *
23
+ * **`page` is the page showing**, as the `value` of the row that opens it,
24
+ * and empty on the top page. Set it to show a page, such as one a link to a
25
+ * settings screen names. A reader's move updates it, and `helix-navigate`
26
+ * comes first, so you can refuse the move or take it yourself.
27
+ *
23
28
  * After each move the host carries `data-direction`, `forward` into a page or
24
29
  * `back` out of one, and records `:state(forward)` or `:state(back)`, so a
25
30
  * stylesheet can slide the new page in from the side the reader is going. Both
@@ -27,13 +32,25 @@ declare const HelixHeadlessDrilldown_base: (new (...args: any[]) => import("@fus
27
32
  * page, two moves the same way included. The styled tier slides the page and
28
33
  * swaps it at once under `prefers-reduced-motion`.
29
34
  *
30
- * Keys, on a row: Up and Down Arrow move between the rows, Home and End go to
31
- * the first and the last, and a typed letter moves to the next row whose name
32
- * starts with it. Enter, Space, or Right Arrow opens a row's page, and Left
33
- * Arrow or Escape goes back, the two arrows swapping on a right-to-left page.
35
+ * **Keyboard.** The drilldown is one tab stop, on the row last focused.
36
+ *
37
+ * | Key | What it does |
38
+ * |---|---|
39
+ * | Down Arrow, Up Arrow | Moves to the next or the previous row. |
40
+ * | Home, End | Moves to the first or the last row. |
41
+ * | A letter | Moves to the next row whose name starts with it. |
42
+ * | Enter, Space | Chooses the row: opens its page, follows its link, or sends `helix-select`. |
43
+ * | Right Arrow | Opens the row's page. Left Arrow on a right-to-left page. |
44
+ * | Left Arrow, Escape | Goes back one page, with focus on the row that opened it. Right Arrow on a right-to-left page. |
34
45
  *
35
46
  * The rows of the page showing are a `menu`, named by `label` on the top page
36
- * and by the page's title below it. The back button and the title sit above
47
+ * and by the page's title below it.
48
+ *
49
+ * **`navigation` makes it a site's navigation.** The host is a `navigation`
50
+ * landmark named by `label`, each page is a list, and each row is a list item
51
+ * holding a link or a button, as the APG's disclosure navigation is built,
52
+ * so a reader meets places to go in place of a menu of commands. The keys stay
53
+ * the same. The back button and the title sit above
37
54
  * the menu. Disabled rows stay reachable with the arrow keys, and typing a
38
55
  * letter moves to the next row whose name starts with it.
39
56
  *
@@ -46,6 +63,7 @@ declare const HelixHeadlessDrilldown_base: (new (...args: any[]) => import("@fus
46
63
  * @slot - The rows of the top page.
47
64
  * @slot back-icon - Replaces the icon on the back button.
48
65
  *
66
+ * @event {HelixNavigateEvent} helix-navigate - Fired before a reader moves into a page or back out of one. `detail.value` is the `value` of the row whose page is about to show, empty for the top page. Cancelable: cancel it to stay on the page showing.
49
67
  * @event {HelixSelectEvent} helix-select - Fired when a row with no page is chosen. Cancelable: canceling it stops the change and leaves the decision to you.
50
68
  *
51
69
  * @csspart back - The button that goes back one page.
@@ -79,6 +97,18 @@ export declare class HelixHeadlessDrilldown extends HelixHeadlessDrilldown_base
79
97
  * The text of the back button.
80
98
  */
81
99
  backLabel: string;
100
+ /**
101
+ * Whether the drilldown is a site's navigation: a `navigation` landmark
102
+ * named by `label`, whose pages are lists of links. Without it, each page is
103
+ * a `menu`.
104
+ */
105
+ navigation: boolean;
106
+ /**
107
+ * The page showing, as the `value` of the row that opens it. Empty is the
108
+ * top page. Setting it shows that page, and a value no row with a page has
109
+ * shows the top page.
110
+ */
111
+ page: string;
82
112
  /**
83
113
  * Which way the last move went, for whatever animates the change.
84
114
  *
@@ -138,6 +168,13 @@ export declare class HelixHeadlessDrilldown extends HelixHeadlessDrilldown_base
138
168
  * actually showing.
139
169
  */
140
170
  private placeTabStop;
171
+ /**
172
+ * Asks before a reader's move to a page, the row's or the top one, and
173
+ * returns whether the move may go ahead.
174
+ */
175
+ private navigate;
176
+ /** The row whose page holds a row, or null for the top page. */
177
+ private holderOf;
141
178
  /** Shows a row's page, and puts focus on the first row of it. */
142
179
  private enter;
143
180
  /**
@@ -149,11 +186,14 @@ export declare class HelixHeadlessDrilldown extends HelixHeadlessDrilldown_base
149
186
  * list they have already read.
150
187
  */
151
188
  back(): boolean;
189
+ /** Shows the page of the row with a value, or the top page where no row with a page has it. */
190
+ private showPage;
152
191
  private readonly handleFocusIn;
153
192
  private readonly handleSelect;
154
193
  private readonly handleKeydown;
155
194
  connectedCallback(): void;
156
195
  disconnectedCallback(): void;
196
+ protected willUpdate(changed: PropertyValues): void;
157
197
  protected updated(changed: PropertyValues): void;
158
198
  /**
159
199
  * Writes which way the last move went. After a move, the marks come off and
@@ -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 { AriaForwardController, customElement, DrilldownController, HelixElement, inlineStep, KeyboardNavigationController, keyClaimed, MixinCollection, slottedWords, typeaheadByWords, words, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, DrilldownController, HelixElement, HelixNavigateEvent, hostAria, inlineStep, KeyboardNavigationController, keyClaimed, MixinCollection, slottedWords, typeaheadByWords, words, } from '@fusion.dev/helix-core';
8
8
  import { caretLeft } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -15,6 +15,8 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
15
15
  super(...arguments);
16
16
  this.label = 'Navigation';
17
17
  this.backLabel = 'Back';
18
+ this.navigation = false;
19
+ this.page = '';
18
20
  this.moved = false;
19
21
  this.drilldown = new DrilldownController(this, {
20
22
  isRow: (element) => 'isDrilldownItem' in element && element.isDrilldownItem === true,
@@ -97,24 +99,50 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
97
99
  item.focusable = item === stop;
98
100
  }
99
101
  }
102
+ navigate(to) {
103
+ return this.dispatchEvent(new HelixNavigateEvent({ value: to?.value ?? '' }));
104
+ }
105
+ holderOf(row) {
106
+ const parent = row.parentElement;
107
+ return row.slot === 'page' && parent instanceof HelixHeadlessDrilldownItem ? parent : null;
108
+ }
100
109
  enter(item) {
101
- if (!this.drilldown.enter(item)) {
110
+ if (!this.drilldown.hasPage(item) || !this.navigate(item) || !this.drilldown.enter(item)) {
102
111
  return;
103
112
  }
113
+ this.page = item.value;
104
114
  this.direction = 'forward';
105
115
  this.moved = true;
106
116
  this.updateComplete.then(() => this.items[0]?.focusItem());
107
117
  }
108
118
  back() {
109
119
  const leaving = this.drilldown.page;
110
- if (!this.drilldown.back()) {
120
+ if (leaving === null) {
121
+ return false;
122
+ }
123
+ const to = this.holderOf(leaving);
124
+ if (!this.navigate(to) || !this.drilldown.back()) {
111
125
  return false;
112
126
  }
127
+ this.page = to?.value ?? '';
113
128
  this.direction = 'back';
114
129
  this.moved = true;
115
130
  this.updateComplete.then(() => leaving?.focusItem());
116
131
  return true;
117
132
  }
133
+ showPage(value) {
134
+ const row = value === ''
135
+ ? undefined
136
+ : [...this.querySelectorAll('*')].find((one) => one instanceof HelixHeadlessDrilldownItem &&
137
+ one.value === value &&
138
+ this.drilldown.hasPage(one));
139
+ if (row) {
140
+ this.drilldown.enter(row);
141
+ }
142
+ else {
143
+ this.drilldown.reset();
144
+ }
145
+ }
118
146
  connectedCallback() {
119
147
  super.connectedCallback();
120
148
  this.addEventListener('helix-select', this.handleSelect, true);
@@ -127,6 +155,17 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
127
155
  this.removeEventListener('keydown', this.handleKeydown);
128
156
  this.removeEventListener('focusin', this.handleFocusIn);
129
157
  }
158
+ willUpdate(changed) {
159
+ super.willUpdate(changed);
160
+ if (changed.has('page') && (this.drilldown.page?.value ?? '') !== this.page) {
161
+ this.showPage(this.page);
162
+ this.page = this.drilldown.page?.value ?? '';
163
+ }
164
+ hostAria(this.internals, {
165
+ label: this.navigation ? this.label : '',
166
+ role: this.navigation ? 'navigation' : '',
167
+ });
168
+ }
130
169
  updated(changed) {
131
170
  super.updated(changed);
132
171
  const page = this.drilldown.page;
@@ -162,6 +201,7 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
162
201
  }
163
202
  mark(item, page, onPage) {
164
203
  item.onPage = onPage;
204
+ item.listed = this.navigation;
165
205
  item.showingPage = item === page;
166
206
  item.onPath = page !== null && item !== page && item.contains(page);
167
207
  for (const child of item.children) {
@@ -188,10 +228,10 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
188
228
  </div>`}
189
229
  <div
190
230
  aria-busy=${this.loading ? 'true' : nothing}
191
- aria-label=${this.drilldown.atRoot ? this.label || nothing : nothing}
231
+ aria-label=${this.drilldown.atRoot && !this.navigation ? this.label || nothing : nothing}
192
232
  aria-labelledby=${this.drilldown.atRoot ? nothing : 'title'}
193
233
  part="page"
194
- role="menu"
234
+ role=${this.navigation ? 'list' : 'menu'}
195
235
  >
196
236
  <slot @slotchange=${(event) => this.countRows(event)}></slot>
197
237
  ${this.renderStatus(this.hasRows)}
@@ -206,6 +246,12 @@ __decorate([
206
246
  words,
207
247
  property({ attribute: 'back-label' })
208
248
  ], HelixHeadlessDrilldown.prototype, "backLabel", void 0);
249
+ __decorate([
250
+ property({ type: Boolean })
251
+ ], HelixHeadlessDrilldown.prototype, "navigation", void 0);
252
+ __decorate([
253
+ property()
254
+ ], HelixHeadlessDrilldown.prototype, "page", void 0);
209
255
  __decorate([
210
256
  state()
211
257
  ], HelixHeadlessDrilldown.prototype, "direction", void 0);
@@ -93,7 +93,7 @@ registerElementEvents({
93
93
  'helix-headless-date-picker': ['change', 'helix-before-change', 'helix-navigate', 'input'],
94
94
  'helix-headless-dialog': ['close', 'helix-before-close', 'helix-before-open', 'toggle'],
95
95
  'helix-headless-drawer': ['close', 'helix-before-close', 'helix-before-open', 'toggle'],
96
- 'helix-headless-drilldown': ['helix-select'],
96
+ 'helix-headless-drilldown': ['helix-navigate', 'helix-select'],
97
97
  'helix-headless-drilldown-item': ['helix-select'],
98
98
  'helix-headless-file-input': ['change', 'helix-before-change', 'helix-reject', 'input'],
99
99
  'helix-headless-filter-chip': ['helix-dismiss'],
@@ -74,6 +74,7 @@ import '../../menu/index.js';
74
74
  * @csspart entry-shortcut-key - One key of the shortcut's chord.
75
75
  * @csspart entry-shortcut-separator - The `+` between two keys of the shortcut, where the platform writes one.
76
76
  * @csspart entry-start - The leading column.
77
+ * @csspart entry-surface - The panel a row's submenu opens in beside it. The filter menu's rows have none.
77
78
  * @csspart menu - The menu the fields are offered in.
78
79
  * @csspart menu-back - The button that goes back from a field's page.
79
80
  * @csspart menu-back-mark - The icon on the back button.
@@ -141,7 +141,7 @@ let HelixHeadlessFilterMenu = class HelixHeadlessFilterMenu extends HelixElement
141
141
  exportparts="end: entry-end, item: entry-item, mark: entry-mark, shortcut: entry-shortcut,
142
142
  shortcut-kbd: entry-shortcut-kbd,
143
143
  shortcut-key: entry-shortcut-key, shortcut-separator: entry-shortcut-separator,
144
- start: entry-start"
144
+ start: entry-start, surface: entry-surface"
145
145
  data-facet="field"
146
146
  data-field=${name}
147
147
  >
@@ -152,7 +152,7 @@ let HelixHeadlessFilterMenu = class HelixHeadlessFilterMenu extends HelixElement
152
152
  exportparts="end: entry-end, item: entry-item, mark: entry-mark, shortcut: entry-shortcut,
153
153
  shortcut-kbd: entry-shortcut-kbd,
154
154
  shortcut-key: entry-shortcut-key, shortcut-separator: entry-shortcut-separator,
155
- start: entry-start"
155
+ start: entry-start, surface: entry-surface"
156
156
  slot="submenu"
157
157
  data-facet="comparison"
158
158
  data-field=${name}
@@ -163,7 +163,7 @@ let HelixHeadlessFilterMenu = class HelixHeadlessFilterMenu extends HelixElement
163
163
  exportparts="end: entry-end, item: entry-item, mark: entry-mark, shortcut: entry-shortcut,
164
164
  shortcut-kbd: entry-shortcut-kbd,
165
165
  shortcut-key: entry-shortcut-key, shortcut-separator: entry-shortcut-separator,
166
- start: entry-start"
166
+ start: entry-start, surface: entry-surface"
167
167
  slot="submenu"
168
168
  checkable
169
169
  exclusive
@@ -188,7 +188,7 @@ let HelixHeadlessFilterMenu = class HelixHeadlessFilterMenu extends HelixElement
188
188
  exportparts="end: entry-end, item: entry-item, mark: entry-mark, shortcut: entry-shortcut,
189
189
  shortcut-kbd: entry-shortcut-kbd,
190
190
  shortcut-key: entry-shortcut-key, shortcut-separator: entry-shortcut-separator,
191
- start: entry-start"
191
+ start: entry-start, surface: entry-surface"
192
192
  slot="submenu"
193
193
  checkable
194
194
  ?exclusive=${using?.arity === 'one'}