@vollowx/seele 0.13.8 → 0.13.10

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 (68) hide show
  1. package/README.md +3 -4
  2. package/package.json +2 -2
  3. package/src/all.d.ts +3 -0
  4. package/src/all.js +3 -0
  5. package/src/base/autocomplete.js +13 -13
  6. package/src/base/button.d.ts +1 -1
  7. package/src/base/button.js +1 -2
  8. package/src/base/experimental/popup.d.ts +3 -1
  9. package/src/base/experimental/popup.js +4 -2
  10. package/src/base/mixins/attachable.d.ts +5 -2
  11. package/src/base/mixins/attachable.js +63 -23
  12. package/src/base/mixins/button-toggle-mixin.js +1 -2
  13. package/src/base/mixins/internals-attached.d.ts +2 -0
  14. package/src/base/mixins/internals-attached.js +1 -0
  15. package/src/base/radio.d.ts +3 -0
  16. package/src/base/radio.js +28 -16
  17. package/src/base/tab-panel.d.ts +3 -3
  18. package/src/base/tab-panel.js +9 -11
  19. package/src/base/tab.d.ts +2 -8
  20. package/src/base/tab.js +16 -35
  21. package/src/base/tabs.d.ts +6 -6
  22. package/src/base/tabs.js +101 -99
  23. package/src/base/tooltip.d.ts +2 -1
  24. package/src/base/tooltip.js +2 -2
  25. package/src/core/ensure-ready.d.ts +2 -1
  26. package/src/core/ensure-ready.js +12 -7
  27. package/src/m3/button/shared-button-styles.css.js +1 -1
  28. package/src/m3/button-group/standard-button-group-styles.css.js +1 -1
  29. package/src/m3/button-group/standard-button-group.d.ts +2 -0
  30. package/src/m3/button-group/standard-button-group.js +44 -38
  31. package/src/m3/checkbox/checkbox.d.ts +1 -1
  32. package/src/m3/checkbox/checkbox.js +2 -5
  33. package/src/m3/dialog/dialog.d.ts +3 -1
  34. package/src/m3/dialog/dialog.js +6 -4
  35. package/src/m3/focus-ring/focus-ring.d.ts +2 -1
  36. package/src/m3/focus-ring/focus-ring.js +4 -7
  37. package/src/m3/navigation/navigation-rail-item-styles.css.js +2 -0
  38. package/src/m3/navigation/navigation-rail-item.d.ts +21 -0
  39. package/src/m3/navigation/navigation-rail-item.js +44 -0
  40. package/src/m3/navigation/navigation-rail-styles.css.js +2 -0
  41. package/src/m3/navigation/navigation-rail.d.ts +12 -0
  42. package/src/m3/navigation/navigation-rail.js +17 -0
  43. package/src/m3/radio/radio-styles.css.js +1 -1
  44. package/src/m3/radio/radio.d.ts +3 -0
  45. package/src/m3/radio/radio.js +12 -4
  46. package/src/m3/ripple/ripple.d.ts +2 -1
  47. package/src/m3/ripple/ripple.js +20 -22
  48. package/src/m3/{system → styles}/defaults.css +1 -1
  49. package/src/m3/styles/motion-expressive.css +15 -0
  50. package/src/m3/styles/motion-standard.css +15 -0
  51. package/src/m3/styles/typography.css +24 -0
  52. package/src/m3/switch/switch.d.ts +1 -0
  53. package/src/m3/switch/switch.js +4 -3
  54. package/src/m3/tab/secondary-tab-styles.css.js +2 -0
  55. package/src/m3/tab/secondary-tab.d.ts +5 -0
  56. package/src/m3/tab/secondary-tab.js +15 -0
  57. package/src/m3/tab/tab-panel-styles.css.js +1 -1
  58. package/src/m3/tab/tab-styles.css.js +1 -1
  59. package/src/m3/tab/tab.d.ts +3 -0
  60. package/src/m3/tab/tab.js +68 -3
  61. package/src/m3/tab/tabs-styles.css.js +1 -1
  62. package/src/m3/tab/tabs.d.ts +1 -7
  63. package/src/m3/tab/tabs.js +6 -39
  64. package/src/m3/system/typography.css +0 -34
  65. /package/src/m3/{system → styles}/base.css +0 -0
  66. /package/src/m3/{system → styles}/elevation.css +0 -0
  67. /package/src/m3/{system → styles}/motion.d.ts +0 -0
  68. /package/src/m3/{system → styles}/motion.js +0 -0
package/README.md CHANGED
@@ -33,13 +33,12 @@ What's the differences comparing to other projects?
33
33
 
34
34
  ## Getting started
35
35
 
36
- Check out [Overview](./docs/00-Overview.md).
36
+ Check out [Installation](https://tideover.cc/seele/docs/#installation).
37
37
 
38
38
  ## Documentations
39
39
 
40
- - [Documentations](./docs/00-Overview.md) (Markdown)
41
- - [lucaz.srht.site](https://lucaz.srht.site/) (components rendered)
42
- - Previous [documentations and demos](https://tideover.cc/seele/docs/), being replaced
40
+ - [Documentations](https://tideover.cc/seele/docs/), ([source](./docs/00-Overview.md))
41
+ - [Backup site](https://lucaz.srht.site/)
43
42
 
44
43
  ## Download
45
44
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vollowx/seele",
3
- "version": "0.13.8",
3
+ "version": "0.13.10",
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",
@@ -20,7 +20,7 @@
20
20
  "files": [
21
21
  "src/**/*.js",
22
22
  "src/**/*.d.ts",
23
- "src/m3/system/*.css",
23
+ "src/m3/styles/*.css",
24
24
  "custom-elements.json",
25
25
  "LICENSE",
26
26
  "README.md"
package/src/all.d.ts CHANGED
@@ -17,6 +17,8 @@ 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/navigation/navigation-rail.js';
21
+ import './m3/navigation/navigation-rail-item.js';
20
22
  import './m3/radio/radio.js';
21
23
  import './m3/ripple/ripple.js';
22
24
  import './m3/select/filled-select.js';
@@ -26,6 +28,7 @@ import './m3/slider/slider.js';
26
28
  import './m3/switch/switch.js';
27
29
  import './m3/tab/tabs.js';
28
30
  import './m3/tab/tab.js';
31
+ import './m3/tab/secondary-tab.js';
29
32
  import './m3/tab/tab-panel.js';
30
33
  import './m3/text-field/filled-text-field.js';
31
34
  import './m3/text-field/outlined-text-field.js';
package/src/all.js CHANGED
@@ -17,6 +17,8 @@ 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/navigation/navigation-rail.js';
21
+ import './m3/navigation/navigation-rail-item.js';
20
22
  import './m3/radio/radio.js';
21
23
  import './m3/ripple/ripple.js';
22
24
  import './m3/select/filled-select.js';
@@ -26,6 +28,7 @@ import './m3/slider/slider.js';
26
28
  import './m3/switch/switch.js';
27
29
  import './m3/tab/tabs.js';
28
30
  import './m3/tab/tab.js';
31
+ import './m3/tab/secondary-tab.js';
29
32
  import './m3/tab/tab-panel.js';
30
33
  import './m3/text-field/filled-text-field.js';
31
34
  import './m3/text-field/outlined-text-field.js';
@@ -56,19 +56,19 @@ export class Autocomplete extends Base {
56
56
  }
57
57
  // TODO: handle multiple calls on this function, currently double-call
58
58
  // disallowed
59
- handleInputSlotChange() {
60
- ensureReady(this.$input).then((input) => {
61
- const $realInput = input.$inputOrTextarea;
62
- $realInput.role = 'combobox';
63
- $realInput.ariaExpanded = String(this.open);
64
- $realInput.ariaHasPopup = 'listbox';
65
- $realInput.ariaAutoComplete = this.mode;
66
- $realInput.ariaControlsElements = [this.$menu];
67
- input.addEventListener('input', this.handleInput.bind(this));
68
- input.addEventListener('keydown', this.handleInputKeydown.bind(this));
69
- input.addEventListener('click', () => (this.open = !this.open));
70
- this.$menu.attach($realInput);
71
- });
59
+ async handleInputSlotChange() {
60
+ await ensureReady(this.$input);
61
+ const input = this.$input;
62
+ const $realInput = input.$inputOrTextarea;
63
+ $realInput.role = 'combobox';
64
+ $realInput.ariaExpanded = String(this.open);
65
+ $realInput.ariaHasPopup = 'listbox';
66
+ $realInput.ariaAutoComplete = this.mode;
67
+ $realInput.ariaControlsElements = [this.$menu];
68
+ input.addEventListener('input', this.handleInput.bind(this));
69
+ input.addEventListener('keydown', this.handleInputKeydown.bind(this));
70
+ input.addEventListener('click', () => (this.open = !this.open));
71
+ this.$menu.attach($realInput);
72
72
  }
73
73
  handleItemsSlotChange() {
74
74
  // Initial filter based on current input value (if any)
@@ -1,5 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
- export declare const updateInternals: unique symbol;
2
+ import { updateInternals } from './mixins/internals-attached.js';
3
3
  declare const Base: Constructor<import("./mixins/form-associated.js").FormAssociatedInterface> & Constructor<import("./mixins/internals-attached.js").InternalsAttachedInterface> & typeof LitElement;
4
4
  export declare class Button extends Base {
5
5
  #private;
@@ -1,10 +1,9 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { LitElement } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
- import { InternalsAttached, internals } from './mixins/internals-attached.js';
4
+ import { InternalsAttached, internals, updateInternals, } from './mixins/internals-attached.js';
5
5
  import { FormAssociated } from './mixins/form-associated.js';
6
6
  import { hiddenStyles } from './hidden-styles.css.js';
7
- export const updateInternals = Symbol('updateInternals');
8
7
  const Base = FormAssociated(InternalsAttached(LitElement));
9
8
  export class Button extends Base {
10
9
  static { this.styles = [hiddenStyles]; }
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import { LitElement, PropertyValues } from 'lit';
13
13
  import { Placement, Strategy } from '@floating-ui/dom';
14
+ import { autoAttachToParent, handleControlChange } from '../mixins/attachable.js';
14
15
  export declare function lookForTabbable(root: Node): HTMLElement | null;
15
16
  declare const Popup_base: Constructor<import("../mixins/attachable.js").AttachableInterface> & Constructor<import("../mixins/internals-attached.js").InternalsAttachedInterface> & typeof LitElement;
16
17
  export declare class Popup extends Popup_base {
@@ -27,7 +28,8 @@ export declare class Popup extends Popup_base {
27
28
  connectedCallback(): void;
28
29
  disconnectedCallback(): void;
29
30
  protected updated(changedProperties: PropertyValues<this>): void;
30
- handleControlChange(prev: HTMLElement | null, next: HTMLElement | null): void;
31
+ [autoAttachToParent]: boolean;
32
+ [handleControlChange](prev: HTMLElement | null, next: HTMLElement | null): void;
31
33
  toggle(): Promise<void>;
32
34
  show(): Promise<void>;
33
35
  hide(): Promise<void>;
@@ -9,12 +9,13 @@
9
9
  *
10
10
  * Design: TO BE ADDED
11
11
  */
12
+ var _a;
12
13
  import { __decorate } from "tslib";
13
14
  import { LitElement, html, isServer } from 'lit';
14
15
  import { customElement, property } from 'lit/decorators.js';
15
16
  import { autoUpdate, computePosition, arrow, flip, offset, shift, } from '@floating-ui/dom';
16
17
  import { InternalsAttached } from '../mixins/internals-attached.js';
17
- import { Attachable } from '../mixins/attachable.js';
18
+ import { Attachable, autoAttachToParent, handleControlChange, } from '../mixins/attachable.js';
18
19
  import { transformOriginFromArrow } from '../controllers/popover-controller.js';
19
20
  import { popupStyles } from './popup-styles.css.js';
20
21
  // Returns the first tabbable element within an eleent
@@ -75,6 +76,7 @@ let Popup = class Popup extends Attachable(InternalsAttached(LitElement)) {
75
76
  this.strategy = 'absolute';
76
77
  this.offset = 0;
77
78
  this.windowPadding = 8;
79
+ this[_a] = false;
78
80
  this.#onRequestHide = () => {
79
81
  this.hide();
80
82
  };
@@ -142,7 +144,7 @@ let Popup = class Popup extends Attachable(InternalsAttached(LitElement)) {
142
144
  this.#syncTriggerAria();
143
145
  }
144
146
  }
145
- handleControlChange(prev, next) {
147
+ [(_a = autoAttachToParent, handleControlChange)](prev, next) {
146
148
  if (prev) {
147
149
  prev.removeEventListener('click', this.#onTriggerClick);
148
150
  prev.removeEventListener('focusout', this.#onFocusOut);
@@ -1,9 +1,12 @@
1
1
  import { LitElement } from 'lit';
2
+ export declare const autoAttachToParent: unique symbol;
3
+ export declare const handleControlChange: unique symbol;
2
4
  export declare class AttachableInterface {
3
- $control: HTMLElement;
5
+ $control: HTMLElement | null;
4
6
  htmlFor: string | null;
5
7
  attach(control: HTMLElement, force?: boolean): void;
6
8
  detach(): void;
7
- handleControlChange(prev: HTMLElement | null, next: HTMLElement | null): void;
9
+ [autoAttachToParent]: boolean;
10
+ [handleControlChange](prev: HTMLElement | null, next: HTMLElement | null): void;
8
11
  }
9
12
  export declare const Attachable: <T extends Constructor<LitElement>>(superClass: T) => Constructor<AttachableInterface> & T;
@@ -1,18 +1,23 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { property } from 'lit/decorators.js';
3
+ export const autoAttachToParent = Symbol('autoAttachToParent');
4
+ export const handleControlChange = Symbol('handleControlChange');
3
5
  export const Attachable = (superClass) => {
6
+ var _a;
4
7
  class AttachableElement extends superClass {
5
8
  constructor() {
6
9
  super(...arguments);
7
- this.currentControl = null;
8
- }
9
- connectedCallback() {
10
- super.connectedCallback();
11
- this.setCurrentControl(this.$control);
12
- }
13
- disconnectedCallback() {
14
- this.setCurrentControl(null);
15
- super.disconnectedCallback();
10
+ /**
11
+ * The control element currently attached to
12
+ */
13
+ this.#$control = null;
14
+ /**
15
+ * Whether `parentNode` is a candidate of `$control`.
16
+ *
17
+ * When false, only `id` is considered without manually setting `$control`
18
+ * or `attach()`
19
+ */
20
+ this[_a] = true;
16
21
  }
17
22
  /**
18
23
  * If has `for` attribute, use it to find the control element.
@@ -23,9 +28,19 @@ export const Attachable = (superClass) => {
23
28
  if (!this.htmlFor || !this.isConnected) {
24
29
  return null;
25
30
  }
26
- return this.getRootNode().querySelector(`#${this.htmlFor}`);
31
+ const root = this.getRootNode();
32
+ if (!root || !('querySelector' in root)) {
33
+ return null;
34
+ }
35
+ return root.querySelector(`#${CSS.escape(this.htmlFor)}`);
36
+ }
37
+ if (this.#$control) {
38
+ return this.#$control;
39
+ }
40
+ if (!this[autoAttachToParent]) {
41
+ return null;
27
42
  }
28
- return this.currentControl || this.parentNode instanceof ShadowRoot
43
+ return this.parentNode instanceof ShadowRoot
29
44
  ? this.parentNode.host
30
45
  : this.parentElement;
31
46
  }
@@ -37,32 +52,57 @@ export const Attachable = (superClass) => {
37
52
  this.detach();
38
53
  }
39
54
  }
55
+ connectedCallback() {
56
+ super.connectedCallback();
57
+ this.#setControl(this.$control);
58
+ }
59
+ disconnectedCallback() {
60
+ this.#setControl(null);
61
+ super.disconnectedCallback();
62
+ }
63
+ firstUpdated(changed) {
64
+ super.firstUpdated(changed);
65
+ // When the control element is placed after `this` and wasn't parsed yet
66
+ // at `connectedCallback`.
67
+ if (!this.#$control && this.htmlFor) {
68
+ this.#setControl(this.$control);
69
+ }
70
+ }
40
71
  updated(changed) {
41
72
  super.updated(changed);
42
73
  if (changed.has('htmlFor')) {
43
74
  // Will be triggered when first render using `for` attribute, will be
44
- // prevented in setCurrentControl since it's unnecessary.
45
- this.setCurrentControl(this.$control);
75
+ // prevented in #setControl since it's unnecessary.
76
+ this.#setControl(this.$control);
46
77
  }
47
78
  }
48
- setCurrentControl(control, force = false) {
49
- if (control === this.currentControl && !force)
50
- return;
51
- this.handleControlChange(this.currentControl, control);
52
- this.currentControl = control;
53
- }
54
79
  attach(control, force = false) {
55
- this.setCurrentControl(control, force);
80
+ this.#setControl(control, force);
56
81
  this.removeAttribute('for');
57
82
  }
58
83
  detach() {
59
- this.setCurrentControl(null);
60
- this.setAttribute('for', '');
84
+ this.#setControl(null);
85
+ this.removeAttribute('for');
86
+ this[autoAttachToParent] = false;
87
+ // That is to prevent attaching automatically on a `$control` access.
88
+ // (yet, I don't even know who would call `detach()`) :/
89
+ }
90
+ /**
91
+ * The control element currently attached to
92
+ */
93
+ #$control;
94
+ #setControl(control, force = false) {
95
+ if (control === this.#$control && !force)
96
+ return;
97
+ this[handleControlChange](this.#$control, control);
98
+ this.#$control = control;
61
99
  }
62
100
  /**
63
101
  * Handles the first attaching and actual control element changing
64
102
  */
65
- handleControlChange(prev = null, next = null) { }
103
+ [(_a = autoAttachToParent, handleControlChange)](_prev = null, _next = null) {
104
+ console.warn('[seele] You should implement [onControlChange] on any class that mixes Attachable');
105
+ }
66
106
  }
67
107
  __decorate([
68
108
  property({ attribute: 'for', type: String })
@@ -1,7 +1,6 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { property } from 'lit/decorators.js';
3
- import { internals, replaceStates } from './internals-attached.js';
4
- import { updateInternals } from '../button.js';
3
+ import { internals, updateInternals, replaceStates, } from './internals-attached.js';
5
4
  const PROPERTY_FROM_ARIA_PRESSED = {
6
5
  true: 'checked',
7
6
  false: 'unchecked',
@@ -1,8 +1,10 @@
1
1
  import { LitElement } from 'lit';
2
2
  export declare const internals: unique symbol;
3
+ export declare const updateInternals: unique symbol;
3
4
  export declare const replaceStates: unique symbol;
4
5
  export declare class InternalsAttachedInterface {
5
6
  [internals]: ElementInternals;
7
+ [updateInternals]?(): void;
6
8
  [replaceStates](del: Array<string>, add: Array<string>): void;
7
9
  }
8
10
  export declare const InternalsAttached: <T extends Constructor<LitElement>>(superClass: T) => Constructor<InternalsAttachedInterface> & T;
@@ -1,5 +1,6 @@
1
1
  export const internals = Symbol('internals');
2
2
  const privateInternals = Symbol('privateInternals');
3
+ export const updateInternals = Symbol('updateInternals');
3
4
  export const replaceStates = Symbol('replaceStates');
4
5
  export const InternalsAttached = (superClass) => {
5
6
  class InternalsAttachedElement extends superClass {
@@ -1,4 +1,5 @@
1
1
  import { LitElement, PropertyValues } from 'lit';
2
+ import { updateInternals } from './mixins/internals-attached.js';
2
3
  declare const Radio_base: Constructor<import("./mixins/form-associated.js").FormAssociatedInterface> & Constructor<import("./mixins/internals-attached.js").InternalsAttachedInterface> & typeof LitElement;
3
4
  export declare class Radio extends Radio_base {
4
5
  #private;
@@ -8,6 +9,8 @@ export declare class Radio extends Radio_base {
8
9
  connectedCallback(): void;
9
10
  disconnectedCallback(): void;
10
11
  protected updated(changedProperties: PropertyValues<this>): void;
12
+ [updateInternals](): void;
11
13
  formResetCallback(): void;
14
+ formStateRestoreCallback(state: string | null): void;
12
15
  }
13
16
  export {};
package/src/base/radio.js CHANGED
@@ -3,7 +3,7 @@ import { __decorate } from "tslib";
3
3
  import { LitElement } from 'lit';
4
4
  import { property } from 'lit/decorators.js';
5
5
  import { FormAssociated } from './mixins/form-associated.js';
6
- import { InternalsAttached, internals } from './mixins/internals-attached.js';
6
+ import { InternalsAttached, internals, replaceStates, updateInternals, } from './mixins/internals-attached.js';
7
7
  export class Radio extends FormAssociated(InternalsAttached(LitElement)) {
8
8
  // Static hidden registry: Scope (Form or RootNode) -> Name -> Set<Radio>
9
9
  static #registry = new Map();
@@ -19,7 +19,7 @@ export class Radio extends FormAssociated(InternalsAttached(LitElement)) {
19
19
  connectedCallback() {
20
20
  super.connectedCallback();
21
21
  this.#registerToGroup();
22
- this.#updateAriaState();
22
+ this[updateInternals]();
23
23
  this.addEventListener('click', this.#handleClick);
24
24
  this.addEventListener('keydown', this.#handleKeyDown);
25
25
  }
@@ -41,16 +41,16 @@ export class Radio extends FormAssociated(InternalsAttached(LitElement)) {
41
41
  }
42
42
  this[internals].setFormValue(this.checked ? this.value : null);
43
43
  this.#updateGroupTabIndices();
44
- this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
45
44
  }
46
45
  if (changedProperties.has('disabled') || changedProperties.has('checked'))
47
- this.#updateAriaState();
46
+ this[updateInternals]();
48
47
  }
49
48
  #handleClick() {
50
49
  if (this.disabled || this.checked)
51
50
  return;
52
51
  this.checked = true;
53
52
  this.focus();
53
+ this.#dispatchEvents();
54
54
  }
55
55
  #handleKeyDown(event) {
56
56
  if (this.disabled)
@@ -58,8 +58,10 @@ export class Radio extends FormAssociated(InternalsAttached(LitElement)) {
58
58
  switch (event.key) {
59
59
  case ' ':
60
60
  event.preventDefault();
61
- if (!this.checked)
61
+ if (!this.checked) {
62
62
  this.checked = true;
63
+ this.#dispatchEvents();
64
+ }
63
65
  break;
64
66
  case 'ArrowDown':
65
67
  case 'ArrowRight':
@@ -117,11 +119,9 @@ export class Radio extends FormAssociated(InternalsAttached(LitElement)) {
117
119
  this.#currentName = '';
118
120
  }
119
121
  #getGroupRadios() {
120
- if (!this.name)
122
+ if (!this.#currentName || !this.#currentScope)
121
123
  return [this];
122
- const scope = this.#getScope();
123
- const group = _a.#registry.get(scope)?.get(this.name);
124
- return group ? Array.from(group) : [this];
124
+ return (_a.#registry.get(this.#currentScope)?.get(this.#currentName) ?? [this]);
125
125
  }
126
126
  #uncheckSiblings() {
127
127
  const radios = this.#getGroupRadios();
@@ -130,10 +130,14 @@ export class Radio extends FormAssociated(InternalsAttached(LitElement)) {
130
130
  radio.checked = false;
131
131
  }
132
132
  #updateGroupTabIndices(groupSet) {
133
- const radios = groupSet ? Array.from(groupSet) : this.#getGroupRadios();
134
- if (radios.length === 0)
135
- return;
136
- const hasChecked = radios.some((r) => r.checked && !r.disabled);
133
+ const radios = groupSet ?? this.#getGroupRadios();
134
+ let hasChecked = false;
135
+ for (const r of radios) {
136
+ if (r.checked && !r.disabled) {
137
+ hasChecked = true;
138
+ break;
139
+ }
140
+ }
137
141
  let enabledFound = false;
138
142
  for (const radio of radios) {
139
143
  const active = !radio.disabled && (hasChecked ? radio.checked : !enabledFound);
@@ -143,7 +147,7 @@ export class Radio extends FormAssociated(InternalsAttached(LitElement)) {
143
147
  }
144
148
  }
145
149
  #navigateGroup(direction) {
146
- const radios = this.#getGroupRadios().filter((r) => !r.disabled);
150
+ const radios = Array.from(this.#getGroupRadios()).filter((r) => !r.disabled);
147
151
  if (radios.length <= 1)
148
152
  return;
149
153
  const currentIndex = radios.indexOf(this);
@@ -152,18 +156,26 @@ export class Radio extends FormAssociated(InternalsAttached(LitElement)) {
152
156
  targetRadio.checked = true;
153
157
  targetRadio.focus();
154
158
  }
155
- #updateAriaState() {
159
+ [updateInternals]() {
156
160
  this[internals].ariaChecked = String(this.checked);
157
161
  this[internals].ariaDisabled = String(this.disabled);
162
+ this[replaceStates](['checked'], [this.checked ? 'checked' : null]);
163
+ }
164
+ #dispatchEvents() {
165
+ this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
166
+ this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
158
167
  }
159
168
  formResetCallback() {
160
169
  this.checked = this.hasAttribute('checked');
161
170
  }
171
+ formStateRestoreCallback(state) {
172
+ this.checked = state === this.value;
173
+ }
162
174
  }
163
175
  _a = Radio;
164
176
  __decorate([
165
177
  property({ type: String })
166
178
  ], Radio.prototype, "value", void 0);
167
179
  __decorate([
168
- property({ type: Boolean, reflect: true })
180
+ property({ type: Boolean })
169
181
  ], Radio.prototype, "checked", void 0);
@@ -1,9 +1,9 @@
1
1
  import { LitElement } from 'lit';
2
2
  declare const TabPanel_base: Constructor<import("./mixins/internals-attached.js").InternalsAttachedInterface> & typeof LitElement;
3
3
  export declare class TabPanel extends TabPanel_base {
4
- protected _role: string;
5
- render(): import("lit-html").TemplateResult<1>;
6
4
  value: string;
7
- connectedCallback(): void;
5
+ selected: boolean;
6
+ render(): import("lit-html").TemplateResult<1>;
7
+ constructor();
8
8
  }
9
9
  export {};
@@ -2,24 +2,22 @@ import { __decorate } from "tslib";
2
2
  import { LitElement, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { InternalsAttached, internals } from './mixins/internals-attached.js';
5
- import { genUniqueId } from '../core/unique-id.js';
6
5
  export class TabPanel extends InternalsAttached(LitElement) {
7
- constructor() {
8
- super(...arguments);
9
- this._role = 'tabpanel';
10
- this.value = '';
11
- }
12
6
  render() {
13
7
  return html `<slot></slot>`;
14
8
  }
15
- connectedCallback() {
16
- super.connectedCallback();
9
+ constructor() {
10
+ super();
11
+ this.value = '';
12
+ this.selected = false;
13
+ this[internals].role = 'tabpanel';
17
14
  this.setAttribute('seele-base', 'tabpanel');
18
- this[internals].role = this._role;
19
- if (!this.id)
20
- this.id = genUniqueId('tabpanel');
15
+ this.setAttribute('slot', 'panels');
21
16
  }
22
17
  }
23
18
  __decorate([
24
19
  property({ type: String, reflect: true })
25
20
  ], TabPanel.prototype, "value", void 0);
21
+ __decorate([
22
+ property({ type: Boolean, reflect: true })
23
+ ], TabPanel.prototype, "selected", void 0);
package/src/base/tab.d.ts CHANGED
@@ -1,18 +1,12 @@
1
1
  import { LitElement } from 'lit';
2
2
  declare const Tab_base: Constructor<import("./mixins/internals-attached.js").InternalsAttachedInterface> & typeof LitElement;
3
- /**
4
- * TODO: disabled
5
- */
6
3
  export declare class Tab extends Tab_base {
7
4
  #private;
8
- protected _role: string;
5
+ disabled: boolean;
9
6
  selected: boolean;
10
- focused: boolean;
11
7
  value: string;
12
8
  render(): import("lit-html").TemplateResult<1>;
13
- connectedCallback(): void;
9
+ constructor();
14
10
  protected updated(changed: Map<string, any>): void;
15
- focus(): void;
16
- blur(): void;
17
11
  }
18
12
  export {};
package/src/base/tab.js CHANGED
@@ -1,60 +1,41 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { LitElement, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
- import { InternalsAttached, internals } from './mixins/internals-attached.js';
5
- import { genUniqueId } from '../core/unique-id.js';
6
- /**
7
- * TODO: disabled
8
- */
4
+ import { InternalsAttached, internals, replaceStates, } from './mixins/internals-attached.js';
9
5
  export class Tab extends InternalsAttached(LitElement) {
10
- constructor() {
11
- super(...arguments);
12
- this._role = 'tab';
13
- this.selected = false;
14
- this.focused = false;
15
- this.value = '';
16
- }
17
6
  render() {
18
7
  return html `<slot></slot>`;
19
8
  }
20
- connectedCallback() {
21
- super.connectedCallback();
9
+ constructor() {
10
+ super();
11
+ this.disabled = false;
12
+ this.selected = false;
13
+ this.value = '';
22
14
  this.setAttribute('seele-base', 'tab');
23
- this[internals].role = this._role;
24
- if (!this.id)
25
- this.id = genUniqueId('tab');
15
+ this[internals].role = 'tab';
26
16
  this.#updateInternals();
27
17
  }
28
18
  updated(changed) {
29
19
  super.updated(changed);
30
- if (changed.has('selected') || changed.has('focused')) {
20
+ if (changed.has('selected') ||
21
+ changed.has('focused') ||
22
+ changed.has('disabled')) {
31
23
  this.#updateInternals();
32
24
  }
33
25
  }
34
26
  #updateInternals() {
35
- this[internals].ariaSelected = this.selected ? 'true' : 'false';
36
- this.focused
37
- ? this[internals].states.add('focused')
38
- : this[internals].states.delete('focused');
39
- this.selected
40
- ? this[internals].states.add('selected')
41
- : this[internals].states.delete('selected');
42
- }
43
- focus() {
44
- this.focused = true;
45
- super.focus();
46
- }
47
- blur() {
48
- this.focused = false;
49
- super.blur();
27
+ this.tabIndex = this.disabled ? -1 : this.selected ? 0 : -1;
28
+ this[internals].ariaSelected = String(this.selected);
29
+ this[internals].ariaDisabled = String(this.disabled);
30
+ this[replaceStates](['selected', 'disabled'], [this.selected ? 'selected' : null, this.disabled ? 'disabled' : null]);
50
31
  }
51
32
  }
52
33
  __decorate([
53
34
  property({ type: Boolean, reflect: true })
54
- ], Tab.prototype, "selected", void 0);
35
+ ], Tab.prototype, "disabled", void 0);
55
36
  __decorate([
56
37
  property({ type: Boolean, reflect: true })
57
- ], Tab.prototype, "focused", void 0);
38
+ ], Tab.prototype, "selected", void 0);
58
39
  __decorate([
59
40
  property({ type: String, reflect: true })
60
41
  ], Tab.prototype, "value", void 0);
@@ -1,19 +1,19 @@
1
1
  import { LitElement } from 'lit';
2
2
  import type { Tab } from './tab.js';
3
+ import type { TabPanel } from './tab-panel.js';
3
4
  /**
4
- * @fires {CustomEvent} tab-select
5
+ * @fires {CustomEvent} select
5
6
  */
6
7
  export declare class Tabs extends LitElement {
7
8
  #private;
8
- protected _role: string;
9
9
  switch: 'auto' | 'manual';
10
10
  selected: string;
11
- $slotItems: Array<HTMLElement>;
12
- get $tabs(): Tab[];
13
- get $parent(): HTMLElement;
11
+ get $tabs(): Array<Tab>;
12
+ get $panels(): Array<TabPanel>;
14
13
  render(): import("lit-html").TemplateResult<1>;
14
+ constructor();
15
15
  connectedCallback(): void;
16
16
  protected updated(changed: Map<string, any>): void;
17
17
  focusTab(tab: Tab): void;
18
- selectTab(selectedTab: Tab): void;
18
+ protected _selectTab(selectedTab: Tab, dispatchEvent?: boolean): void;
19
19
  }