@vollowx/seele 0.12.0 → 0.12.3

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.
package/README.md CHANGED
@@ -1,38 +1,29 @@
1
1
  # Standard Extensible Elements
2
2
 
3
- **SEELE** is a modern, lightweight [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) library. It provides a set of highly customizable UI components that follow the [Material Design 3](https://m3.material.io/) guidelines out of the box, while being designed for easy extension and restyling.
3
+ **SEELE** is a modern, lightweight and accessible
4
+ [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components)
5
+ library. It provides a set of highly customizable UI components that follow the
6
+ [Material Design 3](https://m3.material.io/) guidelines out of the box, while
7
+ being designed for easy extension and restyling.
4
8
 
5
9
  Visit the [website of SEELE](https://seele.v9.nz/) for documentation and demos.
6
10
 
7
- ## Features
8
-
9
- - **Material Design 3**: Ready-to-use components following the latest Material guidelines.
10
- - **Web Components**: Framework-agnostic. Works with vanilla HTML or any framework.
11
- - **Extensible**: Built to be extended. Create your own design system on top of SEELE's logic.
12
- - **Lightweight**: Built on [Lit](https://lit.dev/) and [floating-ui](https://floating-ui.com/) only, ensuring fast performance and small bundle sizes.
13
- - **Accessible**: Designed with accessibility in mind (using `ElementInternals` and standard ARIA patterns).
14
-
15
11
  ## Installation
16
12
 
17
- Install SEELE using your preferred package manager:
13
+ SEELE is published on [npm](https://www.npmjs.com/package/@vollowx/seele),
14
+ install with your preferred package manager:
18
15
 
19
16
  ```bash
20
- # npm
21
17
  npm install @vollowx/seele
22
18
 
23
- # pnpm
24
- pnpm add @vollowx/seele
25
-
26
- # yarn
27
19
  yarn add @vollowx/seele
28
20
 
29
- # bun
30
21
  bun add @vollowx/seele
31
22
  ```
32
23
 
33
24
  ## Usage
34
25
 
35
- ### Importing Components
26
+ ### Importing
36
27
 
37
28
  You can import the entire library or individual components to keep your bundle size small.
38
29
 
@@ -40,14 +31,15 @@ You can import the entire library or individual components to keep your bundle s
40
31
  // Import all components
41
32
  import '@vollowx/seele';
42
33
 
43
- // OR Import specific components (Recommended)
34
+ // Or import specific components (recommended)
35
+ // They all follow such path :@/catagory/group/component.js
44
36
  import '@vollowx/seele/m3/button/common-button.js';
45
37
  import '@vollowx/seele/m3/checkbox/checkbox.js';
46
38
  ```
47
39
 
48
- ### Using Components
40
+ ### Using
49
41
 
50
- Once imported, use the components just like standard HTML tags.
42
+ Once imported, the components can be used just like standard HTML elements.
51
43
 
52
44
  ```html
53
45
  <md-button variant="filled">Filled Button</md-button>
@@ -61,9 +53,15 @@ Once imported, use the components just like standard HTML tags.
61
53
 
62
54
  ### Theming
63
55
 
64
- SEELE components use CSS variables for styling. Currently, the global Material Design 3 token variables are not included in the JavaScript bundle.
56
+ SEELE components use CSS variables for styling.
57
+
58
+ Currently, Material Design 3 token variables are not yet included in the source
59
+ code.
65
60
 
66
- To style the components correctly, you need to define the necessary CSS variables in your project. You can find reference implementations in [vollowx/seele-docs](https://github.com/vollowx/seele-docs/) or the `dev` folder of this repository.
61
+ To style the components correctly, you need to define the necessary CSS
62
+ variables in your project. You can find reference implementations in
63
+ [vollowx/seele-docs](https://github.com/vollowx/seele-docs/) or the `dev` folder
64
+ of this repository.
67
65
 
68
66
  ## Browser Supporty
69
67
 
@@ -75,5 +73,5 @@ SEELE relies on modern web standards like `ElementInternals`.
75
73
  ## Resources
76
74
 
77
75
  - [Roadmap](./ROADMAP.md)
78
- - [Contributing Guide](./CONTRIBUTING.md)
76
+ - [Contributing](./CONTRIBUTING.md)
79
77
  - [License](./LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vollowx/seele",
3
- "version": "0.12.0",
3
+ "version": "0.12.3",
4
4
  "description": "Standard Extensible Elements. A web components library that can be styled and extended freely, pre-providing components in Material Design 3.",
5
5
  "author": "vollowx",
6
6
  "license": "Apache-2.0",
@@ -9,8 +9,8 @@
9
9
  "module": "./src/all.js",
10
10
  "exports": {
11
11
  ".": "./src/all.js",
12
- "./m3/*": "./src/m3/*.js",
13
- "./base/*": "./src/base/*.js"
12
+ "./base/*": "./src/base/*",
13
+ "./m3/*": "./src/m3/*"
14
14
  },
15
15
  "files": [
16
16
  "src/**/*.js",
@@ -49,20 +49,20 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@custom-elements-manifest/analyzer": "^0.11.0",
52
- "@swc/core": "^1.15.11",
53
- "@types/bun": "^1.3.8",
52
+ "@swc/core": "^1.15.18",
53
+ "@types/bun": "^1.3.11",
54
54
  "@web/dev-server": "^0.4.6",
55
- "@web/dev-server-esbuild": "^1.0.4",
55
+ "@web/dev-server-esbuild": "^1.0.5",
56
56
  "chokidar": "^5.0.0",
57
- "lightningcss": "^1.31.1",
58
- "postcss": "^8.5.6",
57
+ "lightningcss": "^1.32.0",
58
+ "postcss": "^8.5.8",
59
59
  "postcss-cli": "^11.0.1",
60
60
  "postcss-sorting": "^9.1.0",
61
61
  "prettier": "^3.8.1"
62
62
  },
63
63
  "dependencies": {
64
- "@floating-ui/dom": "^1.7.5",
65
- "@swc/helpers": "^0.5.18",
64
+ "@floating-ui/dom": "^1.7.6",
65
+ "@swc/helpers": "^0.5.19",
66
66
  "lit": "^3.3.2"
67
67
  }
68
68
  }
@@ -25,9 +25,11 @@ const Base = FocusDelegated(InternalsAttached(LitElement));
25
25
  * id="menu"
26
26
  * type="listbox"
27
27
  * data-tabindex="-1"
28
+ * ?quick="${this.quick}"
28
29
  * .offset=${this.offset}
29
30
  * .align=${this.align}
30
31
  * .alignStrategy=${this.alignStrategy}
32
+ * ?keep-open-select=${this.keepOpenSelect}
31
33
  * no-focus-control
32
34
  * ?open=${this.open}
33
35
  * @open="${() => (this.open = true)}"
@@ -108,7 +110,7 @@ const Base = FocusDelegated(InternalsAttached(LitElement));
108
110
  eventClone.preventDefault = ()=>event.preventDefault();
109
111
  eventClone.stopPropagation = ()=>event.stopPropagation();
110
112
  this.$menu.$menu.dispatchEvent(eventClone);
111
- if (event.key === 'Enter') this.open = false;
113
+ if (event.key === 'Enter' && !this.keepOpenSelect) this.open = false;
112
114
  }
113
115
  }
114
116
  handleMenuSelect(event) {
@@ -117,7 +119,9 @@ const Base = FocusDelegated(InternalsAttached(LitElement));
117
119
  if (this.$input) {
118
120
  this.$input.value = newValue;
119
121
  }
120
- this.open = false;
122
+ if (!this.keepOpenSelect) {
123
+ this.open = false;
124
+ }
121
125
  }
122
126
  updated(changed) {
123
127
  if (changed.has('open') && this.$input) {
@@ -128,7 +132,8 @@ const Base = FocusDelegated(InternalsAttached(LitElement));
128
132
  }
129
133
  }
130
134
  constructor(...args){
131
- super(...args), this.open = false, this.offset = 0, this.align = 'bottom-start', this.alignStrategy = 'absolute', this.mode = 'none';
135
+ super(...args), this.open = false, // Passed to menu
136
+ this.quick = false, this.offset = 0, this.align = 'bottom-start', this.alignStrategy = 'absolute', this.keepOpenSelect = false, this.mode = 'none';
132
137
  }
133
138
  }
134
139
  _ts_decorate([
@@ -136,6 +141,11 @@ _ts_decorate([
136
141
  type: Boolean
137
142
  })
138
143
  ], Autocomplete.prototype, "open", void 0);
144
+ _ts_decorate([
145
+ property({
146
+ type: Boolean
147
+ })
148
+ ], Autocomplete.prototype, "quick", void 0);
139
149
  _ts_decorate([
140
150
  property({
141
151
  type: Number
@@ -153,6 +163,12 @@ _ts_decorate([
153
163
  attribute: 'align-strategy'
154
164
  })
155
165
  ], Autocomplete.prototype, "alignStrategy", void 0);
166
+ _ts_decorate([
167
+ property({
168
+ type: Boolean,
169
+ attribute: 'keep-open-select'
170
+ })
171
+ ], Autocomplete.prototype, "keepOpenSelect", void 0);
156
172
  _ts_decorate([
157
173
  property()
158
174
  ], Autocomplete.prototype, "mode", void 0);
@@ -0,0 +1,245 @@
1
+ import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
2
+ import { LitElement, html } from 'lit';
3
+ import { property, query, queryAssignedElements } from 'lit/decorators.js';
4
+ import { setFocusVisible } from '../core/focus-visible.js';
5
+ import { InternalsAttached } from './mixins/internals-attached.js';
6
+ import { FocusDelegated } from './mixins/focus-delegated.js';
7
+ import { ListController } from './controllers/list-controller.js';
8
+ const Base = FocusDelegated(InternalsAttached(LitElement));
9
+ /**
10
+ * @csspart list
11
+ * @csspart items
12
+ *
13
+ * @fires {Event} open - Fires when the menu is opened.
14
+ * @fires {Event} close - Fires when the menu is closed.
15
+ * @fires {ListSelectEvent} select - Fires when an item is selected.
16
+ * @fires {ListItemFocusEvent} item-focus - Fires when an item is focused
17
+ */ export class List extends Base {
18
+ get $items() {
19
+ return this.listController.items || [];
20
+ }
21
+ render() {
22
+ return html`<div
23
+ part="list"
24
+ role="listbox"
25
+ tabindex="0"
26
+ @keydown=${this.#handleKeyDown}
27
+ @focusin=${this.#handleFocusIn}
28
+ @focusout=${this.#handleFocusOut}
29
+ @pointerdown=${this.#handlePointerDown}
30
+ @click=${this.#handleClick}
31
+ @mouseover=${this.#handleMouseOver}
32
+ >
33
+ ${this.renderItemSlot()}
34
+ </div>`;
35
+ }
36
+ renderItemSlot() {
37
+ return html`<slot part="items"></slot>`;
38
+ }
39
+ updated(changed) {
40
+ // TODO: Find somewhere to put this
41
+ // this.listController.clearSearch();
42
+ }
43
+ #handleKeyDown(event) {
44
+ if (event.defaultPrevented) return;
45
+ const action = getActionFromKey(event);
46
+ const items = this.$items;
47
+ const currentIndex = this.listController.currentIndex;
48
+ const maxIndex = items.length - 1;
49
+ switch(action){
50
+ case MenuActions.Last:
51
+ case MenuActions.First:
52
+ case MenuActions.Next:
53
+ case MenuActions.Previous:
54
+ case MenuActions.PageUp:
55
+ case MenuActions.PageDown:
56
+ event.preventDefault();
57
+ const nextIndex = getUpdatedIndex(currentIndex, maxIndex, action);
58
+ this.listController._focusItem(items[nextIndex]);
59
+ return;
60
+ case MenuActions.CloseSelect:
61
+ event.preventDefault();
62
+ if (currentIndex >= 0) {
63
+ items[currentIndex].focused = false;
64
+ this.dispatchEvent(new CustomEvent('select', {
65
+ detail: {
66
+ item: items[currentIndex],
67
+ index: currentIndex
68
+ },
69
+ bubbles: true,
70
+ composed: true
71
+ }));
72
+ }
73
+ return;
74
+ case MenuActions.Type:
75
+ this.listController.handleType(event.key);
76
+ return;
77
+ }
78
+ }
79
+ #handleFocusIn() {
80
+ if (this.currentIndex == -1) this.listController.focusFirstItem();
81
+ else this.$items[this.currentIndex].focused = true;
82
+ }
83
+ #handleFocusOut() {
84
+ this.$items[this.currentIndex].focused = false;
85
+ }
86
+ #handleMouseOver(event) {
87
+ setFocusVisible(false);
88
+ const item = event.target.closest(this._possibleItemTags.join(','));
89
+ if (item && this.listController.items.includes(item)) {
90
+ this.listController._focusItem(item);
91
+ }
92
+ }
93
+ #handlePointerDown(event) {
94
+ event.preventDefault(); // This makes sure that the container is focused
95
+ this.$list.focus();
96
+ const item = this.#getEventItem(event);
97
+ if (!item || !this.listController.items.includes(item)) return;
98
+ this.listController._focusItem(item);
99
+ }
100
+ #handleClick(event) {
101
+ this.$list.focus();
102
+ const item = this.#getEventItem(event);
103
+ if (!item || !this.listController.items.includes(item)) return;
104
+ this.dispatchEvent(new CustomEvent('select', {
105
+ detail: {
106
+ item: item,
107
+ index: this.listController.items.indexOf(item)
108
+ },
109
+ bubbles: true,
110
+ composed: true
111
+ }));
112
+ }
113
+ #getEventItem(event) {
114
+ const selector = this._possibleItemTags.join(',');
115
+ return event.target.closest(selector);
116
+ }
117
+ get currentIndex() {
118
+ return this.listController?.currentIndex;
119
+ }
120
+ focusFirstItem() {
121
+ this.listController.focusFirstItem();
122
+ }
123
+ focusLastItem() {
124
+ this.listController.focusLastItem();
125
+ }
126
+ focusItem(item) {
127
+ this.listController._focusItem(item);
128
+ }
129
+ constructor(...args){
130
+ super(...args), this._possibleItemTags = [], this._scrollPadding = 0, this.noFocusControl = false, this.listController = new ListController(this, {
131
+ isItem: (item)=>this._possibleItemTags.includes(item.tagName.toLowerCase()) && !item.hasAttribute('disabled') && !item.hidden,
132
+ getPossibleItems: ()=>this.slotItems,
133
+ blurItem: (item)=>{
134
+ item.focused = false;
135
+ },
136
+ focusItem: (item)=>{
137
+ item.focused = true;
138
+ if (!this.noFocusControl) {
139
+ this.$list.ariaActiveDescendantElement = item;
140
+ }
141
+ scrollItemIntoView(this.$list, item, this._scrollPadding);
142
+ this.dispatchEvent(new CustomEvent('item-focus', {
143
+ detail: {
144
+ item: item
145
+ },
146
+ bubbles: true,
147
+ composed: true
148
+ }));
149
+ },
150
+ wrapNavigation: ()=>false
151
+ });
152
+ }
153
+ }
154
+ _ts_decorate([
155
+ property({
156
+ type: Boolean,
157
+ attribute: 'no-focus-control'
158
+ })
159
+ ], List.prototype, "noFocusControl", void 0);
160
+ _ts_decorate([
161
+ query('[part="list"]')
162
+ ], List.prototype, "$list", void 0);
163
+ _ts_decorate([
164
+ queryAssignedElements({
165
+ flatten: true
166
+ })
167
+ ], List.prototype, "slotItems", void 0);
168
+ // Reference: https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/
169
+ export const MenuActions = {
170
+ Close: 0,
171
+ CloseSelect: 1,
172
+ First: 2,
173
+ Last: 3,
174
+ Next: 4,
175
+ Open: 5,
176
+ PageDown: 6,
177
+ PageUp: 7,
178
+ Previous: 8,
179
+ Select: 9,
180
+ Type: 10
181
+ };
182
+ export function filterOptions(options = [], filter, exclude = []) {
183
+ return options.filter((option)=>{
184
+ const matches = option.toLowerCase().indexOf(filter.toLowerCase()) === 0;
185
+ return matches && exclude.indexOf(option) < 0;
186
+ });
187
+ }
188
+ export function getActionFromKey(event) {
189
+ const { key, altKey, ctrlKey, metaKey } = event;
190
+ if (key === 'Home') {
191
+ return MenuActions.First;
192
+ }
193
+ if (key === 'End') {
194
+ return MenuActions.Last;
195
+ }
196
+ if (key === 'Backspace' || key === 'Clear' || key.length === 1 && key !== ' ' && !altKey && !ctrlKey && !metaKey) {
197
+ return MenuActions.Type;
198
+ }
199
+ if (key === 'ArrowUp' && altKey) {
200
+ return MenuActions.CloseSelect;
201
+ } else if (key === 'ArrowDown' && !altKey) {
202
+ return MenuActions.Next;
203
+ } else if (key === 'ArrowUp') {
204
+ return MenuActions.Previous;
205
+ } else if (key === 'PageUp') {
206
+ return MenuActions.PageUp;
207
+ } else if (key === 'PageDown') {
208
+ return MenuActions.PageDown;
209
+ } else if (key === 'Escape') {
210
+ return MenuActions.Close;
211
+ } else if (key === 'Enter' || key === ' ') {
212
+ return MenuActions.CloseSelect;
213
+ }
214
+ return undefined;
215
+ }
216
+ export function getUpdatedIndex(currentIndex, maxIndex, action) {
217
+ const pageSize = 10;
218
+ switch(action){
219
+ case MenuActions.First:
220
+ return 0;
221
+ case MenuActions.Last:
222
+ return maxIndex;
223
+ case MenuActions.Previous:
224
+ return Math.max(0, currentIndex - 1);
225
+ case MenuActions.Next:
226
+ return Math.min(maxIndex, currentIndex + 1);
227
+ case MenuActions.PageUp:
228
+ return Math.max(0, currentIndex - pageSize);
229
+ case MenuActions.PageDown:
230
+ return Math.min(maxIndex, currentIndex + pageSize);
231
+ default:
232
+ return currentIndex;
233
+ }
234
+ }
235
+ export function scrollItemIntoView(list, item, paddingY = 0) {
236
+ if (!list) return;
237
+ // Basic scroll into view logic
238
+ const menuRect = list.getBoundingClientRect();
239
+ const itemRect = item.getBoundingClientRect();
240
+ if (itemRect.bottom + paddingY > menuRect.bottom) {
241
+ list.scrollTop += itemRect.bottom - menuRect.bottom + paddingY;
242
+ } else if (itemRect.top - paddingY < menuRect.top) {
243
+ list.scrollTop -= menuRect.top - itemRect.top + paddingY;
244
+ }
245
+ }
package/src/base/menu.js CHANGED
@@ -123,7 +123,7 @@ const Base = FocusDelegated(InternalsAttached(Attachable(LitElement)));
123
123
  bubbles: true,
124
124
  composed: true
125
125
  }));
126
- if (this.keepOpenClickItem) return;
126
+ if (this.keepOpenSelect) return;
127
127
  this.open = false;
128
128
  }
129
129
  return;
@@ -166,7 +166,7 @@ const Base = FocusDelegated(InternalsAttached(Attachable(LitElement)));
166
166
  bubbles: true,
167
167
  composed: true
168
168
  }));
169
- if (!this.keepOpenClickItem) this.open = false;
169
+ if (!this.keepOpenSelect) this.open = false;
170
170
  }
171
171
  get currentIndex() {
172
172
  return this.listController?.currentIndex;
@@ -190,7 +190,7 @@ const Base = FocusDelegated(InternalsAttached(Attachable(LitElement)));
190
190
  super(...args), this._possibleItemTags = [], this._durations = {
191
191
  show: 0,
192
192
  hide: 0
193
- }, this._scrollPadding = 0, this.type = 'menu', this.open = false, this.quick = false, this.offset = 0, this.align = 'bottom-start', this.alignStrategy = 'absolute', this.keepOpenBlur = false, this.keepOpenClickItem = false, this.keepOpenClickAway = false, this.noFocusControl = false, this.tabIndex = 0, this.$lastFocused = null, this.popoverController = new PopoverController(this, {
193
+ }, this._scrollPadding = 0, this.type = 'menu', this.open = false, this.quick = false, this.offset = 0, this.align = 'bottom-start', this.alignStrategy = 'absolute', this.keepOpenBlur = false, this.keepOpenSelect = false, this.keepOpenClickAway = false, this.noFocusControl = false, this.tabIndex = 0, this.$lastFocused = null, this.popoverController = new PopoverController(this, {
194
194
  popover: ()=>this.$menu,
195
195
  trigger: ()=>this.$control,
196
196
  positioning: {
@@ -271,9 +271,9 @@ _ts_decorate([
271
271
  _ts_decorate([
272
272
  property({
273
273
  type: Boolean,
274
- attribute: 'keep-open-click-item'
274
+ attribute: 'keep-open-select'
275
275
  })
276
- ], Menu.prototype, "keepOpenClickItem", void 0);
276
+ ], Menu.prototype, "keepOpenSelect", void 0);
277
277
  _ts_decorate([
278
278
  property({
279
279
  type: Boolean,
@@ -16,9 +16,11 @@ export class M3Autocomplete extends Autocomplete {
16
16
  id="menu"
17
17
  type="listbox"
18
18
  data-tabindex="-1"
19
+ ?quick="${this.quick}"
19
20
  .offset=${this.offset}
20
21
  .align=${this.align}
21
22
  .alignStrategy=${this.alignStrategy}
23
+ ?keep-open-select=${this.keepOpenSelect}
22
24
  no-focus-control
23
25
  ?open=${this.open}
24
26
  @open="${()=>this.open = true}"
@@ -1,2 +1,2 @@
1
1
  import { css } from 'lit';
2
- export const focusRingStyles = css`:host{animation-delay:0s, calc(var(--md-focus-ring-duration,.6s) * .25);animation-duration:calc(var(--md-focus-ring-duration,.6s) * .25), calc(var(--md-focus-ring-duration,.6s) * .75);animation-timing-function:var(--md-sys-motion-exp-spatial-slow);box-sizing:border-box;color:var(--md-focus-ring-color,var(--md-sys-color-secondary));pointer-events:none;display:none;position:absolute}:host(:state(visible)){display:flex}:host(:not([inward])){inset:calc(-1 * var(--md-focus-ring-outward-offset,2px));outline:var(--md-focus-ring-width,3px) solid currentColor;border-start-start-radius:calc(var(--md-focus-ring-shape-start-start,var(--md-focus-ring-shape,9999px)) + var(--md-focus-ring-outward-offset,2px));border-start-end-radius:calc(var(--md-focus-ring-shape-start-end,var(--md-focus-ring-shape,9999px)) + var(--md-focus-ring-outward-offset,2px));border-end-end-radius:calc(var(--md-focus-ring-shape-end-end,var(--md-focus-ring-shape,9999px)) + var(--md-focus-ring-outward-offset,2px));border-end-start-radius:calc(var(--md-focus-ring-shape-end-start,var(--md-focus-ring-shape,9999px)) + var(--md-focus-ring-outward-offset,2px));animation-name:outward-grow,outward-shrink}:host([inward]){border:var(--md-focus-ring-width,3px) solid currentColor;inset:var(--md-focus-ring-inward-offset,0px);border-start-start-radius:calc(var(--md-focus-ring-shape-start-start,var(--md-focus-ring-shape,9999px)) - var(--md-focus-ring-inward-offset,0px));border-start-end-radius:calc(var(--md-focus-ring-shape-start-end,var(--md-focus-ring-shape,9999px)) - var(--md-focus-ring-inward-offset,0px));border-end-end-radius:calc(var(--md-focus-ring-shape-end-end,var(--md-focus-ring-shape,9999px)) - var(--md-focus-ring-inward-offset,0px));border-end-start-radius:calc(var(--md-focus-ring-shape-end-start,var(--md-focus-ring-shape,9999px)) - var(--md-focus-ring-inward-offset,0px));animation-name:inward-grow,inward-shrink}@keyframes outward-grow{0%{outline-width:0}to{outline-width:var(--md-focus-ring-active-width,8px)}}@keyframes outward-shrink{0%{outline-width:var(--md-focus-ring-active-width,8px)}}@keyframes inward-grow{0%{border-width:0}to{border-width:var(--md-focus-ring-active-width,8px)}}@keyframes inward-shrink{0%{border-width:var(--md-focus-ring-active-width,8px)}}@media (prefers-reduced-motion){:host{animation:none}}`;
2
+ export const focusRingStyles = css`:host{animation-delay:0s, calc(var(--md-focus-ring-duration,.6s) * .25);animation-duration:calc(var(--md-focus-ring-duration,.6s) * .25), calc(var(--md-focus-ring-duration,.6s) * .75);box-sizing:border-box;color:var(--md-focus-ring-color,var(--md-sys-color-secondary));pointer-events:none;animation-timing-function:cubic-bezier(.2,0,0,1),cubic-bezier(.2,0,0,1);display:none;position:absolute}:host(:state(visible)){display:flex}:host(:not([inward])){box-shadow:0 0 0 var(--md-focus-ring-width,3px) currentColor;inset:calc(-1 * var(--md-focus-ring-outward-offset,2px));border-start-start-radius:calc(var(--md-focus-ring-shape-start-start,var(--md-focus-ring-shape,9999px)) + var(--md-focus-ring-outward-offset,2px));border-start-end-radius:calc(var(--md-focus-ring-shape-start-end,var(--md-focus-ring-shape,9999px)) + var(--md-focus-ring-outward-offset,2px));border-end-end-radius:calc(var(--md-focus-ring-shape-end-end,var(--md-focus-ring-shape,9999px)) + var(--md-focus-ring-outward-offset,2px));border-end-start-radius:calc(var(--md-focus-ring-shape-end-start,var(--md-focus-ring-shape,9999px)) + var(--md-focus-ring-outward-offset,2px));animation-name:outward-grow,outward-shrink}:host([inward]){box-shadow:inset 0 0 0 var(--md-focus-ring-width,3px) currentColor;inset:var(--md-focus-ring-inward-offset,0px);border-start-start-radius:calc(var(--md-focus-ring-shape-start-start,var(--md-focus-ring-shape,9999px)) - var(--md-focus-ring-inward-offset,0px));border-start-end-radius:calc(var(--md-focus-ring-shape-start-end,var(--md-focus-ring-shape,9999px)) - var(--md-focus-ring-inward-offset,0px));border-end-end-radius:calc(var(--md-focus-ring-shape-end-end,var(--md-focus-ring-shape,9999px)) - var(--md-focus-ring-inward-offset,0px));border-end-start-radius:calc(var(--md-focus-ring-shape-end-start,var(--md-focus-ring-shape,9999px)) - var(--md-focus-ring-inward-offset,0px));animation-name:inward-grow,inward-shrink}@keyframes outward-grow{0%{box-shadow:0 0}to{box-shadow:0 0 0 var(--md-focus-ring-active-width,8px) currentColor}}@keyframes outward-shrink{0%{box-shadow:0 0 0 var(--md-focus-ring-active-width,8px) currentColor}}@keyframes inward-grow{0%{box-shadow:inset 0 0}to{box-shadow:inset 0 0 0 var(--md-focus-ring-active-width,8px) currentColor}}@keyframes inward-shrink{0%{box-shadow:inset 0 0 0 var(--md-focus-ring-active-width,8px) currentColor}}@media (prefers-reduced-motion){:host{animation:none}}`;
@@ -1,2 +1,2 @@
1
1
  import { css } from 'lit';
2
- export const listStyles = css`:host{box-sizing:border-box;flex-direction:column;display:flex}`;
2
+ export const listStyles = css`:host{min-width:112px;display:contents}[part=list]{box-sizing:border-box;height:inherit;max-height:inherit;max-width:inherit;min-width:inherit;-webkit-user-select:none;user-select:none;width:inherit;outline:0;flex-direction:column;gap:2px;padding:4px;display:flex;position:absolute;inset:auto;overflow-y:auto}`;
@@ -1,13 +1,22 @@
1
1
  import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
2
- import { LitElement } from 'lit';
3
2
  import { customElement } from 'lit/decorators.js';
3
+ import { List } from '../../base/list.js';
4
4
  import { listStyles } from './list-styles.css.js';
5
- export class M3List extends LitElement {
5
+ export class M3List extends List {
6
6
  static{
7
+ // FIXME: Might cause a long list to scroll more than expected
8
+ // override readonly _scrollPadding = 4;
7
9
  this.styles = [
8
10
  listStyles
9
11
  ];
10
12
  }
13
+ constructor(...args){
14
+ super(...args), this._possibleItemTags = [
15
+ 'md-list-item',
16
+ 'md-list-item-checkbox',
17
+ 'md-list-item-radio'
18
+ ];
19
+ }
11
20
  }
12
21
  M3List = _ts_decorate([
13
22
  customElement('md-list')