@vollowx/seele 0.13.10 → 0.14.1

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 (80) hide show
  1. package/README.md +3 -3
  2. package/custom-elements.json +604 -359
  3. package/package.json +1 -1
  4. package/src/all.d.ts +2 -2
  5. package/src/all.js +2 -2
  6. package/src/base/autocomplete.d.ts +9 -33
  7. package/src/base/autocomplete.js +42 -65
  8. package/src/base/button.d.ts +0 -1
  9. package/src/base/button.js +7 -11
  10. package/src/base/checkbox.d.ts +0 -2
  11. package/src/base/checkbox.js +6 -13
  12. package/src/base/controllers/list-controller.d.ts +1 -0
  13. package/src/base/controllers/list-controller.js +6 -1
  14. package/src/base/dialog.d.ts +2 -2
  15. package/src/base/dialog.js +11 -2
  16. package/src/base/list-item.d.ts +1 -1
  17. package/src/base/list-item.js +11 -12
  18. package/src/base/list.d.ts +16 -33
  19. package/src/base/list.js +91 -173
  20. package/src/base/menu.d.ts +41 -61
  21. package/src/base/menu.js +184 -306
  22. package/src/base/{experimental/popup.d.ts → popup.d.ts} +7 -11
  23. package/src/base/{experimental/popup.js → popup.js} +45 -90
  24. package/src/base/radio.js +5 -5
  25. package/src/base/select.d.ts +7 -53
  26. package/src/base/select.js +45 -79
  27. package/src/base/tooltip.js +2 -2
  28. package/src/core/focus.d.ts +11 -0
  29. package/src/core/focus.js +53 -0
  30. package/src/m3/autocomplete/autocomplete-styles.css.js +1 -1
  31. package/src/m3/autocomplete/autocomplete.d.ts +1 -0
  32. package/src/m3/autocomplete/autocomplete.js +2 -1
  33. package/src/m3/button/common-button-styles.css.js +1 -1
  34. package/src/m3/button/icon-button-styles.css.js +1 -1
  35. package/src/m3/button/icon-button-toggle.js +1 -1
  36. package/src/m3/button/shared-button-styles.css.js +1 -1
  37. package/src/m3/button-group/standard-button-group.js +1 -1
  38. package/src/m3/checkbox/checkbox.js +1 -1
  39. package/src/m3/dialog/dialog.d.ts +2 -2
  40. package/src/m3/dialog/dialog.js +2 -2
  41. package/src/m3/field/field-styles.css.js +1 -1
  42. package/src/m3/field/field.js +2 -2
  43. package/src/m3/field/filled-field-styles.css.js +1 -1
  44. package/src/m3/field/filled-field.js +1 -1
  45. package/src/m3/field/outlined-field-styles.css.js +1 -1
  46. package/src/m3/focus-ring/focus-ring.js +1 -1
  47. package/src/m3/list/list-item.d.ts +2 -2
  48. package/src/m3/list/list-item.js +6 -6
  49. package/src/m3/menu/composed-menu.d.ts +19 -0
  50. package/src/m3/menu/composed-menu.js +42 -0
  51. package/src/m3/menu/menu-styles.css.js +1 -1
  52. package/src/m3/menu/menu.d.ts +1 -7
  53. package/src/m3/menu/menu.js +1 -13
  54. package/src/m3/navigation/navigation-rail-item-styles.css.js +1 -1
  55. package/src/m3/popup/popup-styles.css.js +2 -0
  56. package/src/m3/{experimental → popup}/popup.d.ts +2 -1
  57. package/src/m3/popup/popup.js +18 -0
  58. package/src/m3/radio/radio.js +1 -1
  59. package/src/m3/ripple/ripple.js +3 -3
  60. package/src/m3/select/filled-select.d.ts +2 -2
  61. package/src/m3/select/filled-select.js +5 -5
  62. package/src/m3/select/outlined-select.d.ts +2 -2
  63. package/src/m3/select/outlined-select.js +5 -5
  64. package/src/m3/select/select-styles.css.js +1 -1
  65. package/src/m3/select/select.d.ts +2 -5
  66. package/src/m3/select/select.js +3 -6
  67. package/src/m3/styles/color-default-dark.css +51 -0
  68. package/src/m3/styles/color-default-light.css +51 -0
  69. package/src/m3/switch/switch-styles.css.js +1 -1
  70. package/src/m3/switch/switch.js +1 -1
  71. package/src/m3/tab/tabs-styles.css.js +1 -1
  72. package/src/m3/tab/tabs.js +1 -1
  73. package/src/m3/text-field/filled-text-field.js +2 -2
  74. package/src/m3/text-field/outlined-text-field.js +2 -2
  75. package/src/m3/tooltip/tooltip-styles.css.js +1 -1
  76. package/src/core/focus-visible.d.ts +0 -2
  77. package/src/core/focus-visible.js +0 -13
  78. package/src/m3/experimental/popup-styles.css.js +0 -2
  79. package/src/m3/experimental/popup.js +0 -11
  80. /package/src/base/{experimental/popup-styles.css.js → popup-styles.css.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vollowx/seele",
3
- "version": "0.13.10",
3
+ "version": "0.14.1",
4
4
  "description": "A extensible Web Components library, with Material Design 3 components pre-provided.",
5
5
  "author": "vollowx",
6
6
  "license": "Apache-2.0",
package/src/all.d.ts CHANGED
@@ -17,8 +17,10 @@ import './m3/list/list-item.js';
17
17
  import './m3/loading-indicator/loading-indicator.js';
18
18
  import './m3/menu/menu.js';
19
19
  import './m3/menu/menu-item.js';
20
+ import './m3/menu/composed-menu.js';
20
21
  import './m3/navigation/navigation-rail.js';
21
22
  import './m3/navigation/navigation-rail-item.js';
23
+ import './m3/popup/popup.js';
22
24
  import './m3/radio/radio.js';
23
25
  import './m3/ripple/ripple.js';
24
26
  import './m3/select/filled-select.js';
@@ -35,5 +37,3 @@ import './m3/text-field/outlined-text-field.js';
35
37
  import './m3/toolbar/toolbar.js';
36
38
  import './m3/tooltip/tooltip.js';
37
39
  import './win98/button/button.js';
38
- import './base/experimental/popup.js';
39
- import './m3/experimental/popup.js';
package/src/all.js CHANGED
@@ -17,8 +17,10 @@ import './m3/list/list-item.js';
17
17
  import './m3/loading-indicator/loading-indicator.js';
18
18
  import './m3/menu/menu.js';
19
19
  import './m3/menu/menu-item.js';
20
+ import './m3/menu/composed-menu.js';
20
21
  import './m3/navigation/navigation-rail.js';
21
22
  import './m3/navigation/navigation-rail-item.js';
23
+ import './m3/popup/popup.js';
22
24
  import './m3/radio/radio.js';
23
25
  import './m3/ripple/ripple.js';
24
26
  import './m3/select/filled-select.js';
@@ -35,5 +37,3 @@ import './m3/text-field/outlined-text-field.js';
35
37
  import './m3/toolbar/toolbar.js';
36
38
  import './m3/tooltip/tooltip.js';
37
39
  import './win98/button/button.js';
38
- import './base/experimental/popup.js';
39
- import './m3/experimental/popup.js';
@@ -1,57 +1,33 @@
1
1
  import { LitElement, PropertyValues } from 'lit';
2
- import type { Placement, Strategy } from '@floating-ui/dom';
3
- import type { Menu, MenuSelectEvent } from './menu.js';
2
+ import type { Popup } from './popup.js';
3
+ import type { Menu, MenuActionEvent } from './menu.js';
4
4
  declare const Base: Constructor<import("./mixins/focus-delegated.js").FocusDelegatedInterface> & Constructor<import("./mixins/internals-attached.js").InternalsAttachedInterface> & typeof LitElement;
5
- type AutocompleteMode = 'none' | 'list' | 'both';
5
+ export type AutocompleteMode = 'none' | 'list' | 'both';
6
6
  /**
7
7
  * TODO: Check if manually dispatching input/change events on input is necessary
8
- * TODO: handle slotchange
9
8
  */
10
9
  export declare class Autocomplete extends Base {
10
+ #private;
11
11
  open: boolean;
12
- quick: boolean;
13
- offset: number;
14
- align: Placement;
15
- alignStrategy: Strategy;
16
- keepOpenSelect: boolean;
17
12
  mode: AutocompleteMode;
13
+ $popup: Popup;
18
14
  $menu: Menu;
19
15
  inputSlotElements: HTMLElement[];
20
16
  itemSlotElements: HTMLElement[];
21
17
  private get $input();
22
18
  render(): import("lit-html").TemplateResult<1>;
23
19
  /**
24
- * Example content:
25
- *
26
- * ```html
27
- * <your-menu
28
- * part="menu"
29
- * id="menu"
30
- * type="listbox"
31
- * data-tabindex="-1"
32
- * ?quick="${this.quick}"
33
- * .offset=${this.offset}
34
- * .align=${this.align}
35
- * .alignStrategy=${this.alignStrategy}
36
- * ?keep-open-select=${this.keepOpenSelect}
37
- * no-focus-control
38
- * ?open=${this.open}
39
- * @open="${() => (this.open = true)}"
40
- * @close="${() => (this.open = false)}"
41
- * @select=${this.handleMenuSelect}
42
- * >
43
- * <slot @slotchange=${this.handleItemsSlotChange}></slot>
44
- * </your-menu>
45
- * ```
20
+ * Check example content from the m3 implementation
46
21
  */
47
22
  renderMenu(): import("lit-html").TemplateResult<1>;
23
+ constructor();
48
24
  private handleInputSlotChange;
49
- protected handleItemsSlotChange(): void;
25
+ protected handleItemsSlotChange(): Promise<void>;
50
26
  private handleInput;
51
27
  private applyInlineAutoComplete;
52
28
  private filterOptions;
53
29
  private handleInputKeydown;
54
- protected handleMenuSelect(event: MenuSelectEvent): void;
30
+ protected handleMenuAction(event: MenuActionEvent): void;
55
31
  protected updated(changed: PropertyValues): void;
56
32
  }
57
33
  export {};
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from "tslib";
2
- import { LitElement, html } from 'lit';
2
+ import { LitElement, html, isServer } from 'lit';
3
3
  import { property, query, queryAssignedElements } from 'lit/decorators.js';
4
4
  import { ensureReady } from '../core/ensure-ready.js';
5
5
  import { InternalsAttached } from './mixins/internals-attached.js';
@@ -7,20 +7,8 @@ import { FocusDelegated } from './mixins/focus-delegated.js';
7
7
  const Base = FocusDelegated(InternalsAttached(LitElement));
8
8
  /**
9
9
  * TODO: Check if manually dispatching input/change events on input is necessary
10
- * TODO: handle slotchange
11
10
  */
12
11
  export class Autocomplete extends Base {
13
- constructor() {
14
- super(...arguments);
15
- this.open = false;
16
- // Passed to menu
17
- this.quick = false;
18
- this.offset = 0;
19
- this.align = 'bottom-start';
20
- this.alignStrategy = 'absolute';
21
- this.keepOpenSelect = false;
22
- this.mode = 'none';
23
- }
24
12
  get $input() {
25
13
  return this.inputSlotElements[0];
26
14
  }
@@ -28,32 +16,35 @@ export class Autocomplete extends Base {
28
16
  return html `<slot name="input" @slotchange="${this.handleInputSlotChange}"></slot>${this.renderMenu()}`;
29
17
  }
30
18
  /**
31
- * Example content:
32
- *
33
- * ```html
34
- * <your-menu
35
- * part="menu"
36
- * id="menu"
37
- * type="listbox"
38
- * data-tabindex="-1"
39
- * ?quick="${this.quick}"
40
- * .offset=${this.offset}
41
- * .align=${this.align}
42
- * .alignStrategy=${this.alignStrategy}
43
- * ?keep-open-select=${this.keepOpenSelect}
44
- * no-focus-control
45
- * ?open=${this.open}
46
- * @open="${() => (this.open = true)}"
47
- * @close="${() => (this.open = false)}"
48
- * @select=${this.handleMenuSelect}
49
- * >
50
- * <slot @slotchange=${this.handleItemsSlotChange}></slot>
51
- * </your-menu>
52
- * ```
19
+ * Check example content from the m3 implementation
53
20
  */
54
21
  renderMenu() {
55
22
  return html ``;
56
23
  }
24
+ constructor() {
25
+ super();
26
+ this.open = false;
27
+ this.mode = 'none';
28
+ if (!isServer) {
29
+ this.addEventListener('focusout', this.#handleFocusOut.bind(this));
30
+ }
31
+ }
32
+ #handleFocusOut(event) {
33
+ if (!this.open)
34
+ return;
35
+ const target = event.relatedTarget;
36
+ if (target && this.contains(target)) {
37
+ return;
38
+ }
39
+ if (target) {
40
+ this.$popup.hide();
41
+ return;
42
+ }
43
+ requestAnimationFrame(() => {
44
+ if (!document.hasFocus())
45
+ this.$popup.hide();
46
+ });
47
+ }
57
48
  // TODO: handle multiple calls on this function, currently double-call
58
49
  // disallowed
59
50
  async handleInputSlotChange() {
@@ -61,16 +52,15 @@ export class Autocomplete extends Base {
61
52
  const input = this.$input;
62
53
  const $realInput = input.$inputOrTextarea;
63
54
  $realInput.role = 'combobox';
64
- $realInput.ariaExpanded = String(this.open);
65
55
  $realInput.ariaHasPopup = 'listbox';
66
56
  $realInput.ariaAutoComplete = this.mode;
67
57
  $realInput.ariaControlsElements = [this.$menu];
68
58
  input.addEventListener('input', this.handleInput.bind(this));
69
59
  input.addEventListener('keydown', this.handleInputKeydown.bind(this));
70
- input.addEventListener('click', () => (this.open = !this.open));
71
- this.$menu.attach($realInput);
60
+ this.$popup.$ariaControl = $realInput;
61
+ this.$popup.attach(input);
72
62
  }
73
- handleItemsSlotChange() {
63
+ async handleItemsSlotChange() {
74
64
  // Initial filter based on current input value (if any)
75
65
  this.filterOptions(this.$input?.value || '');
76
66
  }
@@ -113,15 +103,17 @@ export class Autocomplete extends Base {
113
103
  if (this.$input?.disabled)
114
104
  return;
115
105
  if (['Enter', 'Escape', 'ArrowUp', 'ArrowDown'].includes(event.key)) {
116
- const eventClone = new KeyboardEvent(event.type, event);
117
- eventClone.preventDefault = () => event.preventDefault();
118
- eventClone.stopPropagation = () => event.stopPropagation();
119
- this.$menu.$menu.dispatchEvent(eventClone);
120
- if (event.key === 'Enter' && !this.keepOpenSelect)
121
- this.open = false;
106
+ if (!this.open && ['ArrowUp', 'ArrowDown'].includes(event.key)) {
107
+ event.preventDefault();
108
+ this.open = true;
109
+ return;
110
+ }
111
+ if (this.open) {
112
+ this.$menu.handleKeyDown(event);
113
+ }
122
114
  }
123
115
  }
124
- handleMenuSelect(event) {
116
+ handleMenuAction(event) {
125
117
  const selectedItem = event.detail.item;
126
118
  const newValue = selectedItem.getAttribute('value') ||
127
119
  selectedItem.textContent?.trim() ||
@@ -129,9 +121,6 @@ export class Autocomplete extends Base {
129
121
  if (this.$input) {
130
122
  this.$input.value = newValue;
131
123
  }
132
- if (!this.keepOpenSelect) {
133
- this.open = false;
134
- }
135
124
  }
136
125
  updated(changed) {
137
126
  if (changed.has('open') && this.$input) {
@@ -145,26 +134,14 @@ export class Autocomplete extends Base {
145
134
  __decorate([
146
135
  property({ type: Boolean })
147
136
  ], Autocomplete.prototype, "open", void 0);
148
- __decorate([
149
- property({ type: Boolean })
150
- ], Autocomplete.prototype, "quick", void 0);
151
- __decorate([
152
- property({ type: Number })
153
- ], Autocomplete.prototype, "offset", void 0);
154
- __decorate([
155
- property({ reflect: true })
156
- ], Autocomplete.prototype, "align", void 0);
157
- __decorate([
158
- property({ type: String, reflect: true, attribute: 'align-strategy' })
159
- ], Autocomplete.prototype, "alignStrategy", void 0);
160
- __decorate([
161
- property({ type: Boolean, attribute: 'keep-open-select' })
162
- ], Autocomplete.prototype, "keepOpenSelect", void 0);
163
137
  __decorate([
164
138
  property()
165
139
  ], Autocomplete.prototype, "mode", void 0);
166
140
  __decorate([
167
- query('[part="menu"]')
141
+ query('[part=popup]')
142
+ ], Autocomplete.prototype, "$popup", void 0);
143
+ __decorate([
144
+ query('[part=menu]')
168
145
  ], Autocomplete.prototype, "$menu", void 0);
169
146
  __decorate([
170
147
  queryAssignedElements({ slot: 'input', flatten: true })
@@ -7,7 +7,6 @@ export declare class Button extends Base {
7
7
  static styles: any[];
8
8
  constructor();
9
9
  connectedCallback(): void;
10
- disconnectedCallback(): void;
11
10
  updated(changed: Map<string, any>): void;
12
11
  [updateInternals](): void;
13
12
  _handleClick(e: Event): void;
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from "tslib";
2
- import { LitElement } from 'lit';
2
+ import { isServer, LitElement } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { InternalsAttached, internals, updateInternals, } from './mixins/internals-attached.js';
5
5
  import { FormAssociated } from './mixins/form-associated.js';
@@ -23,7 +23,7 @@ export class Button extends Base {
23
23
  // TODO: supporting `Enter` also requires listening on `focusout`
24
24
  };
25
25
  this.#handleKeyUp = (e) => {
26
- if (e.key === ' ') {
26
+ if (e.key === ' ' && this[internals].states.has('active')) {
27
27
  this[internals].states.delete('active');
28
28
  e.preventDefault();
29
29
  e.stopPropagation();
@@ -37,20 +37,16 @@ export class Button extends Base {
37
37
  // Double `requestAnimationFrame` is necessary since the callback inside is
38
38
  // called before the nth frame is printed.
39
39
  this.setAttribute('notransition', '');
40
+ if (!isServer) {
41
+ this.addEventListener('keydown', this.#handleKeyDown);
42
+ this.addEventListener('keyup', this.#handleKeyUp);
43
+ this.addEventListener('click', this._handleClick.bind(this));
44
+ }
40
45
  }
41
46
  connectedCallback() {
42
47
  super.connectedCallback();
43
- this.addEventListener('keydown', this.#handleKeyDown);
44
- this.addEventListener('keyup', this.#handleKeyUp);
45
- this.addEventListener('click', this._handleClick.bind(this));
46
48
  requestAnimationFrame(() => requestAnimationFrame(() => this.removeAttribute('notransition')));
47
49
  }
48
- disconnectedCallback() {
49
- super.disconnectedCallback();
50
- this.removeEventListener('keydown', this.#handleKeyDown);
51
- this.removeEventListener('keyup', this.#handleKeyUp);
52
- this.removeEventListener('click', this._handleClick.bind(this));
53
- }
54
50
  updated(changed) {
55
51
  if (changed.has('disabled'))
56
52
  this[updateInternals]();
@@ -7,8 +7,6 @@ export declare class Checkbox extends Base {
7
7
  required: boolean;
8
8
  static styles: any[];
9
9
  constructor();
10
- connectedCallback(): void;
11
- disconnectedCallback(): void;
12
10
  protected updated(changed: Map<string, any>): void;
13
11
  protected updateState(): void;
14
12
  protected toggleChecked(): void;
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from "tslib";
2
- import { LitElement } from 'lit';
2
+ import { isServer, LitElement } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { FormAssociated } from './mixins/form-associated.js';
5
5
  import { InternalsAttached, internals, replaceStates, } from './mixins/internals-attached.js';
@@ -39,18 +39,11 @@ export class Checkbox extends Base {
39
39
  this.checked = this.hasAttribute('checked');
40
40
  this.indeterminate = this.hasAttribute('indeterminate');
41
41
  this.updateState();
42
- }
43
- connectedCallback() {
44
- super.connectedCallback();
45
- this.addEventListener('click', this.#handleClick);
46
- this.addEventListener('keydown', this.#handleKeyDown);
47
- this.addEventListener('keyup', this.#handleKeyUp);
48
- }
49
- disconnectedCallback() {
50
- this.removeEventListener('click', this.#handleClick);
51
- this.removeEventListener('keydown', this.#handleKeyDown);
52
- this.removeEventListener('keyup', this.#handleKeyUp);
53
- super.disconnectedCallback();
42
+ if (!isServer) {
43
+ this.addEventListener('click', this.#handleClick);
44
+ this.addEventListener('keydown', this.#handleKeyDown);
45
+ this.addEventListener('keyup', this.#handleKeyUp);
46
+ }
54
47
  }
55
48
  updated(changed) {
56
49
  if (changed.has('checked') ||
@@ -34,4 +34,5 @@ export declare class ListController<Item extends ListItem> implements ReactiveCo
34
34
  focusPreviousItem(): void;
35
35
  handleSlotChange(): void;
36
36
  }
37
+ export declare function filterOptions(options: string[], filter: string, exclude?: string[]): string[];
37
38
  export declare function getIndexByLetter(options: string[], filter: string, startIndex?: number): number;
@@ -1,4 +1,3 @@
1
- import { filterOptions } from '../menu.js';
2
1
  export class ListController {
3
2
  constructor(host, config) {
4
3
  this._focusedItem = null;
@@ -99,6 +98,12 @@ export class ListController {
99
98
  this._focusedItem = index >= 0 ? items[index] : null;
100
99
  }
101
100
  }
101
+ export function filterOptions(options = [], filter, exclude = []) {
102
+ return options.filter((option) => {
103
+ const matches = option.toLowerCase().indexOf(filter.toLowerCase()) === 0;
104
+ return matches && exclude.indexOf(option) < 0;
105
+ });
106
+ }
102
107
  export function getIndexByLetter(options, filter, startIndex = 0) {
103
108
  const orderedOptions = [
104
109
  ...options.slice(startIndex),
@@ -15,6 +15,6 @@ import { LitElement } from 'lit';
15
15
  export declare class Dialog extends LitElement {
16
16
  $dialog: HTMLDialogElement;
17
17
  _handleCancel: (e: Event) => void;
18
- show(): void;
19
- close(): void;
18
+ show(): Promise<void>;
19
+ close(): Promise<void>;
20
20
  }
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { LitElement } from 'lit';
3
3
  import { query } from 'lit/decorators.js';
4
+ import { getFirstTabbable } from '../core/focus.js';
4
5
  /**
5
6
  * @csspart dialog
6
7
  *
@@ -22,10 +23,18 @@ export class Dialog extends LitElement {
22
23
  this.close();
23
24
  };
24
25
  }
25
- show() {
26
+ async show() {
26
27
  this.$dialog.showModal();
28
+ const autoFocus = this.querySelector('[autofocus]');
29
+ if (autoFocus) {
30
+ autoFocus.focus();
31
+ }
32
+ else {
33
+ const firstTabbable = getFirstTabbable(this);
34
+ firstTabbable?.focus();
35
+ }
27
36
  }
28
- close() {
37
+ async close() {
29
38
  this.$dialog.close();
30
39
  }
31
40
  }
@@ -7,7 +7,7 @@ export declare class ListItem extends ListItem_base {
7
7
  selected: boolean;
8
8
  focused: boolean;
9
9
  get displayText(): string;
10
- connectedCallback(): void;
10
+ constructor();
11
11
  protected updated(changed: Map<string, any>): void;
12
12
  focus(): void;
13
13
  blur(): void;
@@ -1,29 +1,28 @@
1
1
  import { __decorate } from "tslib";
2
- import { LitElement } from 'lit';
2
+ import { isServer, LitElement } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
- import { genUniqueId } from '../core/unique-id.js';
5
4
  import { InternalsAttached, internals } from './mixins/internals-attached.js';
6
5
  import { FormAssociated } from './mixins/form-associated.js';
7
6
  import { hiddenStyles } from './hidden-styles.css.js';
8
7
  export class ListItem extends FormAssociated(InternalsAttached(LitElement)) {
9
- constructor() {
10
- super(...arguments);
11
- this._role = 'option';
12
- this.selected = false;
13
- this.focused = false;
14
- }
15
8
  static { this.styles = [hiddenStyles]; }
16
9
  get displayText() {
17
10
  return this.innerText.trim();
18
11
  }
19
- connectedCallback() {
20
- super.connectedCallback();
12
+ // Accessibility tools, particularly Narrator, only fires `click` event on
13
+ // elements that have listeners for them.
14
+ #handleDummy() { }
15
+ constructor() {
16
+ super();
17
+ this._role = 'option';
18
+ this.selected = false;
19
+ this.focused = false;
21
20
  this.setAttribute('seele-base', 'option');
22
21
  this[internals].role = this._role;
23
22
  this.setAttribute('tabindex', '-1');
24
23
  this.#updateInternals();
25
- if (!this.id)
26
- this.id = genUniqueId('item');
24
+ if (!isServer)
25
+ this.addEventListener('click', this.#handleDummy);
27
26
  }
28
27
  updated(changed) {
29
28
  super.updated(changed);
@@ -1,54 +1,37 @@
1
+ /**
2
+ * TODO: currently list and menu has too much in common, should be split into
3
+ * menu, listbox and a LinearFocusController for tabs/toolbars
4
+ */
1
5
  import { LitElement } from 'lit';
2
6
  import type { ListItem } from './list-item.js';
3
- declare const Base: Constructor<import("./mixins/internals-attached.js").InternalsAttachedInterface> & typeof LitElement;
4
- interface ListSelectDetail {
7
+ export interface ListboxSelectDetail {
5
8
  item: ListItem;
6
9
  index: number;
7
10
  }
8
- export type ListSelectEvent = CustomEvent<ListSelectDetail>;
9
- interface ItemFocusDetail {
11
+ export type ListboxSelectEvent = CustomEvent<ListboxSelectDetail>;
12
+ export interface ItemFocusDetail {
10
13
  item: ListItem;
14
+ index: number;
11
15
  }
12
16
  export type ListItemFocusEvent = CustomEvent<ItemFocusDetail>;
17
+ declare const List_base: Constructor<import("./mixins/internals-attached.js").InternalsAttachedInterface> & typeof LitElement;
13
18
  /**
14
19
  * @csspart items
15
- *
16
- * @fires {Event} open - Fires when the menu is opened.
17
- * @fires {Event} close - Fires when the menu is closed.
18
- * @fires {ListSelectEvent} select - Fires when an item is selected.
20
+ * @fires {ListboxSelectEvent} select - Fires when an item is selected.
19
21
  * @fires {ListItemFocusEvent} item-focus - Fires when an item is focused
20
22
  */
21
- export declare class List extends Base {
23
+ export declare class List extends List_base {
22
24
  #private;
23
- readonly _scrollPadding: number;
24
25
  noFocusControl: boolean;
25
- slotItems: Array<ListItem | HTMLElement>;
26
+ slotItems: Array<ListItem>;
26
27
  get $items(): ListItem[];
27
- render(): import("lit-html").TemplateResult<1>;
28
- renderItemSlot(): import("lit-html").TemplateResult<1>;
29
- private readonly listController;
30
- constructor();
31
- protected updated(changed: Map<string, any>): void;
32
28
  get currentIndex(): number;
33
29
  focusFirstItem(): void;
34
30
  focusLastItem(): void;
35
31
  focusItem(item: ListItem): void;
32
+ render(): import("lit-html").TemplateResult<1>;
33
+ private readonly listController;
34
+ constructor();
35
+ handleKeyDown(event: KeyboardEvent): void;
36
36
  }
37
- export declare const MenuActions: {
38
- Close: number;
39
- CloseSelect: number;
40
- First: number;
41
- Last: number;
42
- Next: number;
43
- Open: number;
44
- PageDown: number;
45
- PageUp: number;
46
- Previous: number;
47
- Select: number;
48
- Type: number;
49
- };
50
- export declare function filterOptions(options: string[], filter: string, exclude?: string[]): string[];
51
- export declare function getActionFromKey(event: KeyboardEvent): number;
52
- export declare function getUpdatedIndex(currentIndex: number, maxIndex: number, action: number): number;
53
- export declare function scrollItemIntoView(list: HTMLElement, item: HTMLElement, paddingY?: number): void;
54
37
  export {};