@vollowx/seele 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -0
  3. package/package.json +62 -0
  4. package/src/all.js +19 -0
  5. package/src/base/button.js +61 -0
  6. package/src/base/checkbox.js +118 -0
  7. package/src/base/controllers/list-controller.js +96 -0
  8. package/src/base/controllers/popover-controller.js +163 -0
  9. package/src/base/field.js +3 -0
  10. package/src/base/hidden-styles.css.js +2 -0
  11. package/src/base/input.js +182 -0
  12. package/src/base/item.js +7 -0
  13. package/src/base/list-item.js +54 -0
  14. package/src/base/menu-item.js +12 -0
  15. package/src/base/menu-utils.js +111 -0
  16. package/src/base/menu.js +244 -0
  17. package/src/base/mixins/attachable.js +71 -0
  18. package/src/base/mixins/form-associated.js +69 -0
  19. package/src/base/mixins/internals-attached.js +13 -0
  20. package/src/base/option.js +17 -0
  21. package/src/base/select.js +285 -0
  22. package/src/base/switch.js +86 -0
  23. package/src/base/tooltip.js +139 -0
  24. package/src/core/focus-visible.js +13 -0
  25. package/src/core/shared.d.ts +1 -0
  26. package/src/core/unique-id.js +11 -0
  27. package/src/m3/button/common-button-styles.css.js +2 -0
  28. package/src/m3/button/common-button-toggle-styles.css.js +2 -0
  29. package/src/m3/button/common-button-toggle.js +69 -0
  30. package/src/m3/button/common-button.js +65 -0
  31. package/src/m3/button/icon-button-styles.css.js +2 -0
  32. package/src/m3/button/icon-button-toggle-styles.css.js +2 -0
  33. package/src/m3/button/icon-button-toggle.js +57 -0
  34. package/src/m3/button/icon-button.js +51 -0
  35. package/src/m3/button/shared-button-styles.css.js +2 -0
  36. package/src/m3/checkbox-styles.css.js +2 -0
  37. package/src/m3/checkbox.js +46 -0
  38. package/src/m3/fab-styles.css.js +2 -0
  39. package/src/m3/fab.js +48 -0
  40. package/src/m3/field/field-styles.css.js +2 -0
  41. package/src/m3/field/field.js +93 -0
  42. package/src/m3/field/filled-field-styles.css.js +2 -0
  43. package/src/m3/field/filled-field.js +30 -0
  44. package/src/m3/field/outlined-field-styles.css.js +2 -0
  45. package/src/m3/field/outlined-field.js +34 -0
  46. package/src/m3/focus-ring-styles.css.js +2 -0
  47. package/src/m3/focus-ring.js +72 -0
  48. package/src/m3/item-styles.css.js +2 -0
  49. package/src/m3/item.js +46 -0
  50. package/src/m3/list-item-styles.css.js +2 -0
  51. package/src/m3/list-item.js +52 -0
  52. package/src/m3/list-styles.css.js +2 -0
  53. package/src/m3/list.js +16 -0
  54. package/src/m3/menu-item.js +15 -0
  55. package/src/m3/menu-part-styles.css.js +2 -0
  56. package/src/m3/menu-styles.css.js +2 -0
  57. package/src/m3/menu.js +30 -0
  58. package/src/m3/option.js +15 -0
  59. package/src/m3/ripple-styles.css.js +2 -0
  60. package/src/m3/ripple.js +199 -0
  61. package/src/m3/select/filled-select.js +41 -0
  62. package/src/m3/select/outlined-select.js +41 -0
  63. package/src/m3/select/select-styles.css.js +2 -0
  64. package/src/m3/select/select.js +34 -0
  65. package/src/m3/switch-styles.css.js +2 -0
  66. package/src/m3/switch.js +129 -0
  67. package/src/m3/target-styles.css.js +2 -0
  68. package/src/m3/text-field/filled-text-field.js +38 -0
  69. package/src/m3/text-field/outlined-text-field.js +40 -0
  70. package/src/m3/text-field/text-field-styles.css.js +2 -0
  71. package/src/m3/toolbar-styles.css.js +2 -0
  72. package/src/m3/toolbar.js +53 -0
  73. package/src/m3/tooltip-styles.css.js +2 -0
  74. package/src/m3/tooltip.js +18 -0
package/src/m3/item.js ADDED
@@ -0,0 +1,46 @@
1
+ import { __decorate } from "tslib";
2
+ import { html } from 'lit';
3
+ import { customElement } from 'lit/decorators.js';
4
+ import { Item } from '../base/item.js';
5
+ import { itemStyles } from './item-styles.css.js';
6
+ /**
7
+ * @tag md-item
8
+ *
9
+ * @csspart container
10
+ * @csspart start
11
+ * @csspart text
12
+ * @csspart overline
13
+ * @csspart headline
14
+ * @csspart supporting-text
15
+ * @csspart trailing-supporting-text
16
+ * @csspart end
17
+ *
18
+ * @slot container - container element
19
+ * @slot start - start content
20
+ * @slot overline - overline text
21
+ * @slot headline - headline text
22
+ * @slot supporting-text - supporting text
23
+ * @slot trailing-supporting-text - trailing supporting text
24
+ * @slot end - end content
25
+ */
26
+ let M3Item = class M3Item extends Item {
27
+ static { this.styles = [itemStyles]; }
28
+ render() {
29
+ return html `
30
+ <slot name="container"></slot>
31
+ <slot name="start"></slot>
32
+ <div class="text">
33
+ <slot name="overline"></slot>
34
+ <slot></slot>
35
+ <slot name="headline"></slot>
36
+ <slot name="supporting-text"></slot>
37
+ </div>
38
+ <slot name="trailing-supporting-text"></slot>
39
+ <slot name="end"></slot>
40
+ `;
41
+ }
42
+ };
43
+ M3Item = __decorate([
44
+ customElement('md-item')
45
+ ], M3Item);
46
+ export { M3Item };
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const listItemStyles = css `:host{--md-focus-ring-shape:12px;--md-focus-ring-inward-offset:-4px;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none;border-radius:12px;outline:0;display:flex}:host(:state(selected)){background-color:var(--md-sys-color-tertiary-container);color:var(--md-sys-color-on-tertiary-container)}:host(:disabled){cursor:default;opacity:.3;pointer-events:none}md-item,md-item div[slot=container]{border-radius:inherit}`;
@@ -0,0 +1,52 @@
1
+ import { __decorate } from "tslib";
2
+ import { html } from 'lit';
3
+ import { customElement, query } from 'lit/decorators.js';
4
+ import { ListItem } from '../base/list-item.js';
5
+ import { listItemStyles } from './list-item-styles.css.js';
6
+ /**
7
+ * @tag md-list-item
8
+ *
9
+ * @slot - contents in md-item
10
+ */
11
+ let M3ListItem = class M3ListItem extends ListItem {
12
+ constructor() {
13
+ super();
14
+ this.updateComplete.then(() => {
15
+ this.ripple.$control = this;
16
+ this.focusRing.$control = this;
17
+ });
18
+ }
19
+ static { this.styles = [...super.styles, listItemStyles]; }
20
+ updated(changed) {
21
+ super.updated(changed);
22
+ if (changed.has('focused')) {
23
+ if (this.focused) {
24
+ this.focusRing.visualFocus();
25
+ }
26
+ else {
27
+ this.focusRing.visualBlur();
28
+ }
29
+ }
30
+ }
31
+ render() {
32
+ return html `
33
+ <md-item>
34
+ <div slot="container">
35
+ <md-focus-ring inward></md-focus-ring>
36
+ <md-ripple></md-ripple>
37
+ </div>
38
+ <slot></slot>
39
+ </md-item>
40
+ `;
41
+ }
42
+ };
43
+ __decorate([
44
+ query('md-ripple')
45
+ ], M3ListItem.prototype, "ripple", void 0);
46
+ __decorate([
47
+ query('md-focus-ring')
48
+ ], M3ListItem.prototype, "focusRing", void 0);
49
+ M3ListItem = __decorate([
50
+ customElement('md-list-item')
51
+ ], M3ListItem);
52
+ export { M3ListItem };
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const listStyles = css `:host{box-sizing:border-box;flex-direction:column;display:flex}`;
package/src/m3/list.js ADDED
@@ -0,0 +1,16 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement } from 'lit';
3
+ import { customElement } from 'lit/decorators.js';
4
+ import { listStyles } from './list-styles.css.js';
5
+ /**
6
+ * @tag md-list
7
+ *
8
+ * TODO: Use listController
9
+ */
10
+ let M3List = class M3List extends LitElement {
11
+ static { this.styles = [listStyles]; }
12
+ };
13
+ M3List = __decorate([
14
+ customElement('md-list')
15
+ ], M3List);
16
+ export { M3List };
@@ -0,0 +1,15 @@
1
+ import { __decorate } from "tslib";
2
+ import { customElement } from 'lit/decorators.js';
3
+ import { M3ListItem } from './list-item.js';
4
+ import { MenuItemMixin } from '../base/menu-item.js';
5
+ /**
6
+ * @tag md-menu-item
7
+ *
8
+ * @slot - contents in md-item
9
+ */
10
+ let M3MenuItem = class M3MenuItem extends MenuItemMixin(M3ListItem) {
11
+ };
12
+ M3MenuItem = __decorate([
13
+ customElement('md-menu-item')
14
+ ], M3MenuItem);
15
+ export { M3MenuItem };
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const menuPartStyles = css `[part=menu]{background:var(--md-sys-color-surface-container);box-shadow:var(--md-sys-elevation-shadow-2);box-sizing:border-box;color:var(--md-sys-color-on-surface);height:inherit;max-height:inherit;max-width:inherit;min-width:inherit;opacity:0;z-index:1000;border-radius:16px;padding:4px;inset:auto;overflow-y:auto;transform:scaleY(.4)}:host(:state(closed)) [part=menu]{display:none}:host(:state(opening)) [part=menu]{opacity:1;transition:opacity 67ms,transform var(--md-sys-motion-exp-effects-slow-duration)var(--md-sys-motion-exp-effects-slow);display:block;transform:scaleY(1)}:host(:state(opened)) [part=menu]{opacity:1;display:block;transform:scaleY(1)}:host(:state(closing)) [part=menu]{opacity:0;transition:opacity var(--md-sys-motion-exp-effects-default-duration),transform var(--md-sys-motion-exp-effects-default-duration)var(--md-sys-motion-exp-effects-default);transform:scaleY(.4)}[part=items]{opacity:0;flex-direction:column;gap:2px;display:flex}:host(:state(opening)) [part=items]{opacity:1;transition:opacity 67ms linear 67ms}:host(:state(opened)) [part=items]{opacity:1}:host(:state(closing)) [part=items]{opacity:0;transition:opacity 67ms}`;
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const menuStyles = css `:host{outline:0;min-width:112px;display:block}`;
package/src/m3/menu.js ADDED
@@ -0,0 +1,30 @@
1
+ import { __decorate } from "tslib";
2
+ import { customElement } from 'lit/decorators.js';
3
+ import { Menu } from '../base/menu.js';
4
+ import { menuPartStyles } from './menu-part-styles.css.js';
5
+ import { menuStyles } from './menu-styles.css.js';
6
+ /**
7
+ * @tag md-menu
8
+ *
9
+ * @csspart menu-surface
10
+ * @csspart list
11
+ *
12
+ * @slot - menu items
13
+ */
14
+ let M3Menu = class M3Menu extends Menu {
15
+ constructor() {
16
+ super(...arguments);
17
+ this._possibleItemTags = [
18
+ 'md-menu-item',
19
+ 'md-menu-item-checkbox',
20
+ 'md-menu-item-radio',
21
+ ];
22
+ this._durations = { show: 300, hide: 200 };
23
+ this._scrollPadding = 4;
24
+ }
25
+ static { this.styles = [menuPartStyles, menuStyles]; }
26
+ };
27
+ M3Menu = __decorate([
28
+ customElement('md-menu')
29
+ ], M3Menu);
30
+ export { M3Menu };
@@ -0,0 +1,15 @@
1
+ import { __decorate } from "tslib";
2
+ import { customElement } from 'lit/decorators.js';
3
+ import { OptionMixin } from '../base/option.js';
4
+ import { M3ListItem } from './list-item.js';
5
+ /**
6
+ * @tag md-option
7
+ *
8
+ * @slot - contents in md-menu-item
9
+ */
10
+ let M3Option = class M3Option extends OptionMixin(M3ListItem) {
11
+ };
12
+ M3Option = __decorate([
13
+ customElement('md-option')
14
+ ], M3Option);
15
+ export { M3Option };
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const rippleStyles = css `:host{border-radius:inherit;pointer-events:none;display:block;position:absolute;inset:0;overflow:hidden}[part~=ripple]{background-image:radial-gradient(closest-side,var(--md-ripple-color,currentColor)max(calc(100% - 70px),65%),transparent 100%);position:absolute;top:0;left:0}:host:before{background-color:var(--md-ripple-color,currentColor);border-radius:inherit;content:"";opacity:0;transition:opacity 67ms linear;display:block;position:absolute;inset:0}:host(:state(hover)):before{opacity:.08}`;
@@ -0,0 +1,199 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement } from 'lit';
3
+ import { customElement, property } from 'lit/decorators.js';
4
+ import { Attachable } from '../base/mixins/attachable.js';
5
+ import { InternalsAttached, internals, } from '../base/mixins/internals-attached.js';
6
+ import { rippleStyles } from './ripple-styles.css.js';
7
+ const PRESS_GROW_MS = 450;
8
+ const MINIMUM_PRESS_MS = 225;
9
+ const OPACITY_IN_MS = 105;
10
+ const OPACITY_OUT_MS = 375;
11
+ function distance({ x: ax, y: ay }, { x: bx, y: by }) {
12
+ return Math.sqrt((ax - bx) ** 2 + (ay - by) ** 2);
13
+ }
14
+ /**
15
+ * @tag md-ripple
16
+ *
17
+ * @cssprop --md-ripple-color
18
+ */
19
+ let M3Ripple = class M3Ripple extends Attachable(InternalsAttached(LitElement)) {
20
+ static { this.styles = [rippleStyles]; }
21
+ constructor() {
22
+ super();
23
+ this.clickBehavior = 'always';
24
+ this.enterBehavior = 'always';
25
+ this.spaceBehavior = 'once';
26
+ this.$ripples = [];
27
+ this.#spaceKeyDown = false;
28
+ this.#pointerDown = false;
29
+ this.#lastTime = 0;
30
+ this.#handleKeyDown = (e) => {
31
+ if ((e.key === 'Enter' && this.enterBehavior === 'always') ||
32
+ (e.key === ' ' && this.spaceBehavior === 'always')) {
33
+ this.addRipple();
34
+ this.removeRippleAll();
35
+ }
36
+ else if (e.key === ' ' && this.spaceBehavior === 'once') {
37
+ if (!this.#spaceKeyDown)
38
+ this.addRipple();
39
+ this.#spaceKeyDown = true;
40
+ }
41
+ };
42
+ this.#handleKeyUp = (e) => {
43
+ if (e.key === ' ' && this.spaceBehavior === 'once') {
44
+ this.#spaceKeyDown = false;
45
+ this.removeRippleAll();
46
+ }
47
+ };
48
+ this.#handlePointerEnter = (e) => {
49
+ if (e.pointerType === 'touch')
50
+ return;
51
+ this[internals].states.add('hover');
52
+ if (this.#pointerDown && this.clickBehavior === 'always')
53
+ this.addRipple(e);
54
+ };
55
+ this.#handlePointerLeave = () => {
56
+ this[internals].states.delete('hover');
57
+ if (this.#pointerDown && this.clickBehavior === 'always')
58
+ this.removeRippleAll();
59
+ };
60
+ this.#handlePointerDown = (e) => {
61
+ if (e.pointerType === 'mouse')
62
+ this.#pointerDown = true;
63
+ document.addEventListener('pointerup', this.#handlePointerUp);
64
+ document.addEventListener('touchcancel', this.#handlePointerUp);
65
+ document.addEventListener('touchend', this.#handlePointerUp);
66
+ document.addEventListener('touchmove', this.#handlePointerUp);
67
+ if (e.button === 2)
68
+ return;
69
+ if (this.clickBehavior === 'always')
70
+ this.addRipple(e);
71
+ };
72
+ this.#handlePointerUp = () => {
73
+ this.#pointerDown = false;
74
+ document.removeEventListener('pointerup', this.#handlePointerUp);
75
+ document.removeEventListener('touchcancel', this.#handlePointerUp);
76
+ document.removeEventListener('touchend', this.#handlePointerUp);
77
+ document.removeEventListener('touchmove', this.#handlePointerUp);
78
+ this.removeRippleAll();
79
+ };
80
+ this[internals].ariaHidden = 'true';
81
+ }
82
+ #spaceKeyDown;
83
+ #pointerDown;
84
+ #lastTime;
85
+ #handleKeyDown;
86
+ #handleKeyUp;
87
+ #handlePointerEnter;
88
+ #handlePointerLeave;
89
+ #handlePointerDown;
90
+ #handlePointerUp;
91
+ handleControlChange(prev = null, next = null) {
92
+ const eventHandlers = {
93
+ keydown: this.#handleKeyDown,
94
+ keyup: this.#handleKeyUp,
95
+ pointerenter: this.#handlePointerEnter,
96
+ pointerleave: this.#handlePointerLeave,
97
+ pointerdown: this.#handlePointerDown,
98
+ };
99
+ Object.keys(eventHandlers).forEach((eventName) => {
100
+ // @ts-ignore
101
+ prev?.labels?.forEach((label) => label.removeEventListener(eventName, eventHandlers[eventName]));
102
+ prev?.removeEventListener(eventName, eventHandlers[eventName]);
103
+ // Check if control is nested in label, if so, only bind to label
104
+ let isNestedInLabel = false;
105
+ // @ts-ignore
106
+ next?.labels?.forEach((label) => {
107
+ if (label.contains(next))
108
+ isNestedInLabel = true;
109
+ });
110
+ if (isNestedInLabel) {
111
+ // @ts-ignore
112
+ next.labels?.forEach((label) => label.addEventListener(eventName, eventHandlers[eventName]));
113
+ }
114
+ else {
115
+ next?.addEventListener(eventName, eventHandlers[eventName]);
116
+ }
117
+ });
118
+ }
119
+ #calculateRipple(e = null) {
120
+ const containerRect = this.getBoundingClientRect();
121
+ const containerMiddle = {
122
+ x: containerRect.width / 2,
123
+ y: containerRect.height / 2,
124
+ };
125
+ const centered = !e;
126
+ const endCenter = containerMiddle;
127
+ let startCenter = endCenter;
128
+ if (!centered) {
129
+ startCenter.x = e.clientX - containerRect.left;
130
+ startCenter.y = e.clientY - containerRect.top;
131
+ }
132
+ const corners = [
133
+ { x: 0, y: 0 },
134
+ { x: containerRect.width, y: 0 },
135
+ { x: 0, y: containerRect.height },
136
+ { x: containerRect.width, y: containerRect.height },
137
+ ];
138
+ const radius = Math.max(...corners.map((corner) => distance(endCenter, corner)));
139
+ return { startCenter, endCenter, radius };
140
+ }
141
+ addRipple(e = null) {
142
+ const { startCenter, endCenter, radius } = this.#calculateRipple(e);
143
+ const diameter = radius * 2 + 'px';
144
+ const translateStart = `${startCenter.x - radius}px ${startCenter.y - radius}px`;
145
+ const translateEnd = `${endCenter.x - radius}px ${endCenter.y - radius}px`;
146
+ const ripple = document.createElement('div');
147
+ ripple.setAttribute('part', 'ripple');
148
+ this.renderRoot.append(ripple);
149
+ this.$ripples.push(ripple);
150
+ ripple.animate({
151
+ opacity: [0, 0.1],
152
+ }, {
153
+ duration: OPACITY_IN_MS,
154
+ easing: 'linear',
155
+ fill: 'forwards',
156
+ });
157
+ ripple.animate({
158
+ height: [diameter, diameter],
159
+ width: [diameter, diameter],
160
+ translate: [translateStart, translateEnd],
161
+ scale: [0.2, 1.35],
162
+ }, {
163
+ duration: PRESS_GROW_MS,
164
+ // TODO: Control by global variables
165
+ easing: 'cubic-bezier(0.2, 0, 0, 1)',
166
+ fill: 'forwards',
167
+ });
168
+ this.#lastTime = Date.now();
169
+ }
170
+ removeRipple(ripple) {
171
+ setTimeout(() => {
172
+ const animation = ripple.animate({
173
+ opacity: [getComputedStyle(ripple).opacity, '0'],
174
+ }, {
175
+ duration: OPACITY_OUT_MS,
176
+ fill: 'forwards',
177
+ easing: 'linear',
178
+ });
179
+ animation.onfinish = animation.oncancel = () => ripple.remove();
180
+ }, Math.max(MINIMUM_PRESS_MS - (Date.now() - this.#lastTime), 0));
181
+ }
182
+ removeRippleAll() {
183
+ for (const ripple of this.$ripples.splice(0))
184
+ this.removeRipple(ripple);
185
+ }
186
+ };
187
+ __decorate([
188
+ property()
189
+ ], M3Ripple.prototype, "clickBehavior", void 0);
190
+ __decorate([
191
+ property()
192
+ ], M3Ripple.prototype, "enterBehavior", void 0);
193
+ __decorate([
194
+ property()
195
+ ], M3Ripple.prototype, "spaceBehavior", void 0);
196
+ M3Ripple = __decorate([
197
+ customElement('md-ripple')
198
+ ], M3Ripple);
199
+ export { M3Ripple };
@@ -0,0 +1,41 @@
1
+ import { __decorate } from "tslib";
2
+ import { html } from 'lit';
3
+ import { customElement } from 'lit/decorators.js';
4
+ import { M3Select } from './select.js';
5
+ import '../field/filled-field.js';
6
+ import { selectStyles } from './select-styles.css.js';
7
+ import { menuPartStyles } from '../menu-part-styles.css.js';
8
+ let MdFilledSelect = class MdFilledSelect extends M3Select {
9
+ static { this.styles = [menuPartStyles, selectStyles]; }
10
+ renderField() {
11
+ return html `
12
+ <md-filled-field
13
+ part="field"
14
+ .label=${this.label}
15
+ .populated=${!!this.value}
16
+ .disabled=${this.disabled}
17
+ .required=${this.required}
18
+ .error=${this.error}
19
+ .focused=${this.open || this.fieldFocused}
20
+ supportingtext=${this.supportingText}
21
+ @click=${this.toggle}
22
+ @keydown=${this.handleFieldKeydown}
23
+ @focus=${() => (this.fieldFocused = true)}
24
+ @blur=${() => (this.fieldFocused = false)}
25
+ tabindex=${this.disabled ? '-1' : '0'}
26
+ role="combobox"
27
+ aria-haspopup="listbox"
28
+ aria-expanded=${this.open}
29
+ aria-controls="menu"
30
+ aria-disabled=${this.disabled}
31
+ aria-required=${this.required}
32
+ >
33
+ ${this.renderFieldContent()}
34
+ </md-filled-field>
35
+ `;
36
+ }
37
+ };
38
+ MdFilledSelect = __decorate([
39
+ customElement('md-filled-select')
40
+ ], MdFilledSelect);
41
+ export { MdFilledSelect };
@@ -0,0 +1,41 @@
1
+ import { __decorate } from "tslib";
2
+ import { html } from 'lit';
3
+ import { customElement } from 'lit/decorators.js';
4
+ import { M3Select } from './select.js';
5
+ import '../field/outlined-field.js';
6
+ import { selectStyles } from './select-styles.css.js';
7
+ import { menuPartStyles } from '../menu-part-styles.css.js';
8
+ let MdOutlinedSelect = class MdOutlinedSelect extends M3Select {
9
+ static { this.styles = [menuPartStyles, selectStyles]; }
10
+ renderField() {
11
+ return html `
12
+ <md-outlined-field
13
+ part="field"
14
+ .label=${this.label}
15
+ .populated=${!!this.value}
16
+ .disabled=${this.disabled}
17
+ .required=${this.required}
18
+ .error=${this.error}
19
+ .focused=${this.open || this.fieldFocused}
20
+ supportingtext=${this.supportingText}
21
+ @click=${this.toggle}
22
+ @keydown=${this.handleFieldKeydown}
23
+ @focus=${() => (this.fieldFocused = true)}
24
+ @blur=${() => (this.fieldFocused = false)}
25
+ tabindex=${this.disabled ? '-1' : '0'}
26
+ role="combobox"
27
+ aria-haspopup="listbox"
28
+ aria-expanded=${this.open}
29
+ aria-controls="menu"
30
+ aria-disabled=${this.disabled}
31
+ aria-required=${this.required}
32
+ >
33
+ ${this.renderFieldContent()}
34
+ </md-outlined-field>
35
+ `;
36
+ }
37
+ };
38
+ MdOutlinedSelect = __decorate([
39
+ customElement('md-outlined-select')
40
+ ], MdOutlinedSelect);
41
+ export { MdOutlinedSelect };
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const selectStyles = css `:host{min-width:210px;display:inline-block;position:relative}[part=field]{cursor:pointer;outline:none;width:100%}[part=value]{font:var(--md-sys-typography-body-large);height:1.5em}[part=menu]{max-height:var(--md-select-menu-max-height,300px);min-width:100%}`;
@@ -0,0 +1,34 @@
1
+ import { __decorate } from "tslib";
2
+ import { property, query, state } from 'lit/decorators.js';
3
+ import { Select } from '../../base/select.js';
4
+ /**
5
+ * @fires {Event} change - Fired when the selected value has changed.
6
+ * @fires {Event} input - Fired when the selected value has changed.
7
+ */
8
+ export class M3Select extends Select {
9
+ constructor() {
10
+ super(...arguments);
11
+ this._possibleItemTags = ['md-option'];
12
+ this._durations = { show: 300, hide: 200 };
13
+ this._scrollPadding = 4;
14
+ this.label = '';
15
+ this.supportingText = '';
16
+ this.error = false;
17
+ this.fieldFocused = false;
18
+ }
19
+ }
20
+ __decorate([
21
+ property({ type: String })
22
+ ], M3Select.prototype, "label", void 0);
23
+ __decorate([
24
+ property({ type: String })
25
+ ], M3Select.prototype, "supportingText", void 0);
26
+ __decorate([
27
+ property({ type: Boolean, reflect: true })
28
+ ], M3Select.prototype, "error", void 0);
29
+ __decorate([
30
+ state()
31
+ ], M3Select.prototype, "fieldFocused", void 0);
32
+ __decorate([
33
+ query('md-filled-field, md-outlined-field')
34
+ ], M3Select.prototype, "field", void 0);
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const switchStyles = css `:host{--_outline-color:var(--md-sys-color-outline);--_track-color:var(--md-sys-color-surface-container-highest);--_thumb-color:var(--md-sys-color-outline);--_icon-color:var(--md-sys-color-surface-container-highest);--_ripple-color:var(--md-sys-color-on-surface);background-color:color-mix(in srgb,var(--_track-color)var(--_track-opacity,100%),transparent);border-color:color-mix(in srgb,var(--_outline-color)var(--_outline-opacity,100%),transparent);box-sizing:border-box;cursor:pointer;-webkit-tap-highlight-color:transparent;touch-action:none;height:32px;transition:background-color var(--md-sys-motion-exp-effects-fast-duration)var(--md-sys-motion-exp-effects-fast),border-color var(--md-sys-motion-exp-effects-fast-duration)var(--md-sys-motion-exp-effects-fast);-webkit-user-select:none;user-select:none;vertical-align:top;border-style:solid;border-width:2px;border-radius:9999px;outline:0;place-content:center;place-items:center;width:52px;display:inline-grid;position:relative}:host(:state(checked)){--_outline-color:var(--md-sys-color-primary);--_track-color:var(--md-sys-color-primary);--_thumb-color:var(--md-sys-color-on-primary);--_icon-color:var(--md-sys-color-on-primary-container);--_ripple-color:var(--md-sys-color-primary)}:host(:disabled){--_outline-color:var(--md-sys-color-on-surface);--_outline-opacity:12%;--_track-color:var(--md-sys-color-surface-variant);--_track-opacity:12%;--_thumb-color:var(--md-sys-color-on-surface);--_thumb-opacity:38%;--_icon-color:var(--md-sys-color-surface-container-highest);cursor:default;pointer-events:none}:host(:disabled:state(checked)){--_outline-color:var(--md-sys-color-surface);--_track-color:var(--md-sys-color-on-surface);--_thumb-color:var(--md-sys-color-surface);--_thumb-opacity:100%;--_icon-color:var(--md-sys-color-on-surface)}:host([icons]:not(:state(checked)):not([checkedicononly])) [part~=icon-off],:host([icons]:state(checked)) [part~=icon-on]{--_icon-opacity:100%}:host([icons]:state(checked):disabled) [part~=icon-on]{--_icon-opacity:38%}@media (hover:hover) and (pointer:fine){:host(:hover){--_thumb-color:var(--md-sys-color-on-surface-variant)}:host(:state(checked):hover){--_thumb-color:var(--md-sys-color-primary-container)}}@media (forced-colors:active){:host{forced-color-adjust:none}}[part~=thumb]{--_thumb-diameter:16px;--_thumb-diff-default:20px;background-color:color-mix(in srgb,var(--_thumb-color)var(--_thumb-opacity,100%),transparent);height:var(--_thumb-diameter);transition:background-color var(--md-sys-motion-exp-effects-fast-duration)var(--md-sys-motion-exp-effects-fast),width var(--md-sys-motion-exp-spatial-fast-duration)var(--md-sys-motion-exp-spatial-fast),height var(--md-sys-motion-exp-spatial-fast-duration)var(--md-sys-motion-exp-spatial-fast),margin var(--md-sys-motion-exp-spatial-fast-duration)var(--md-sys-motion-exp-spatial-fast);width:var(--_thumb-diameter);z-index:1;border-radius:50%;place-content:center;place-items:center;margin-inline-start:calc(var(--_thumb-diff-pointer,0px) - var(--_thumb-diff-default));display:grid;position:absolute}:host(:state(checked)) [part~=thumb]{--_thumb-diameter:24px;--_thumb-diff-default:-20px;background-color:var(--_thumb-color)}:host([icons]:not([checkedicononly])) [part~=thumb]{--_thumb-diameter:24px}:host(:active) [part~=thumb]{--_thumb-color:var(--md-sys-color-on-surface-variant);--_thumb-diameter:28px!important}:host(:state(checked):active) [part~=thumb]{--_thumb-color:var(--md-sys-color-primary-container)}[part~=icons]{fill:color-mix(in srgb,var(--_icon-color)var(--_icon-opacity,0%),transparent);width:16px;height:16px;transition:fill 67ms linear;position:absolute}md-focus-ring{inset:-4px}md-ripple{color:var(--_ripple-color);height:40px;inset:unset;width:40px}`;
@@ -0,0 +1,129 @@
1
+ import { __decorate } from "tslib";
2
+ import { html } from 'lit';
3
+ import { customElement, property } from 'lit/decorators.js';
4
+ import { Switch } from '../base/switch.js';
5
+ import './focus-ring.js';
6
+ import './ripple.js';
7
+ import { switchStyles } from './switch-styles.css.js';
8
+ import { targetStyles } from './target-styles.css.js';
9
+ // FIXME: Drag-and-drop breaks the support for working with `<label>`. Temporarily disabled.
10
+ // function isRTL() {
11
+ // return document.documentElement.dir === 'rtl';
12
+ // }
13
+ /**
14
+ * @tag md-switch
15
+ *
16
+ * @csspart thumb
17
+ * @csspart label
18
+ */
19
+ let M3Switch = class M3Switch extends Switch {
20
+ constructor() {
21
+ super(...arguments);
22
+ // /** @type {M3Ripple} */
23
+ // @query('md-ripple') $ripple;
24
+ // /** @type {HTMLSpanElement} */
25
+ // @query('[part~="thumb"]') $thumb;
26
+ // connectedCallback() {
27
+ // super.connectedCallback();
28
+ // this.$ripple.attach(this);
29
+ // this.addEventListener('pointerdown', this.#boundPointerDown);
30
+ // this.addEventListener('pointerup', this.#boundPointerUp);
31
+ // }
32
+ // disconnectedCallback() {
33
+ // super.disconnectedCallback();
34
+ // this.removeEventListener('pointerdown', this.#boundPointerDown);
35
+ // this.removeEventListener('pointerup', this.#boundPointerUp);
36
+ // }
37
+ this.icons = false;
38
+ this.checkedIconOnly = false;
39
+ // #pointerDownX = 0;
40
+ //
41
+ // #boundPointerDown = this.#handlePointerDown.bind(this);
42
+ // #boundPointerMove = this.#handlePointerMove.bind(this);
43
+ // #boundPointerUp = this.#handlePointerUp.bind(this);
44
+ // /** @param {PointerEvent} e */
45
+ // #handlePointerDown(e) {
46
+ // this._ignoreClick = false;
47
+ //
48
+ // if (e.button !== 0) return;
49
+ // this.#pointerDownX = e.clientX;
50
+ // this.setPointerCapture(e.pointerId);
51
+ // this.addEventListener('pointermove', this.#boundPointerMove);
52
+ // }
53
+ // /** @param {PointerEvent} e */
54
+ // #handlePointerMove(e) {
55
+ // this._ignoreClick = true;
56
+ //
57
+ // const diff = (isRTL() ? -1 : 1) * (e.clientX - this.#pointerDownX);
58
+ // const limitedDiff = this.checked
59
+ // ? Math.min(0, Math.max(-20, diff))
60
+ // : Math.min(20, Math.max(0, diff));
61
+ // this.$thumb.style.setProperty(
62
+ // '--_thumb-diff-pointer',
63
+ // `${2 * limitedDiff}px`
64
+ // );
65
+ // // Thumb loses its `:active` status before pointer up event
66
+ // this.$thumb.style.setProperty('--_thumb-diameter', '28px');
67
+ // this.$thumb.style.transitionDuration = '0s';
68
+ // }
69
+ // /** @param {PointerEvent} e */
70
+ // #handlePointerUp(e) {
71
+ // this.removeEventListener('pointermove', this.#boundPointerMove);
72
+ // this.releasePointerCapture(e.pointerId);
73
+ //
74
+ // const trackRect = this.getBoundingClientRect();
75
+ // const thumbRect = this.$thumb.getBoundingClientRect();
76
+ // const diff =
77
+ // thumbRect.left +
78
+ // thumbRect.width / 2 -
79
+ // trackRect.left -
80
+ // trackRect.width / 2;
81
+ // const shouldBeChecked = (diff >= 0 && !isRTL()) || (diff < 0 && isRTL());
82
+ //
83
+ // this.$thumb.style.setProperty('--_thumb-diff-pointer', '');
84
+ // this.$thumb.style.setProperty('--_thumb-diameter', '');
85
+ // this.$thumb.style.transitionDuration = '';
86
+ //
87
+ // if (this.checked != shouldBeChecked) this.__toggleStatus();
88
+ // }
89
+ }
90
+ static { this.styles = [targetStyles, switchStyles]; }
91
+ render() {
92
+ return html `
93
+ <md-focus-ring></md-focus-ring>
94
+ <div part="thumb">
95
+ <md-ripple spacebehavior="always"></md-ripple>
96
+ <span part="target"></span>
97
+ ${this.renderOffIcon()}${this.renderOnIcon()}
98
+ </div>
99
+ `;
100
+ }
101
+ renderOnIcon() {
102
+ return html `
103
+ <svg part="icons icon-on" viewBox="0 0 24 24" aria-hidden="true">
104
+ <path
105
+ d="M9.55 18.2 3.65 12.3 5.275 10.675 9.55 14.95 18.725 5.775 20.35 7.4Z"
106
+ />
107
+ </svg>
108
+ `;
109
+ }
110
+ renderOffIcon() {
111
+ return html `
112
+ <svg part="icons icon-off" viewBox="0 0 24 24" aria-hidden="true">
113
+ <path
114
+ d="M6.4 19.2 4.8 17.6 10.4 12 4.8 6.4 6.4 4.8 12 10.4 17.6 4.8 19.2 6.4 13.6 12 19.2 17.6 17.6 19.2 12 13.6Z"
115
+ />
116
+ </svg>
117
+ `;
118
+ }
119
+ };
120
+ __decorate([
121
+ property({ type: Boolean, reflect: true })
122
+ ], M3Switch.prototype, "icons", void 0);
123
+ __decorate([
124
+ property({ type: Boolean, reflect: true })
125
+ ], M3Switch.prototype, "checkedIconOnly", void 0);
126
+ M3Switch = __decorate([
127
+ customElement('md-switch')
128
+ ], M3Switch);
129
+ export { M3Switch };
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const targetStyles = css `[part~=target]{box-sizing:border-box;content:"";width:100%;min-width:48px;height:100%;min-height:48px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}`;