@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.
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/package.json +62 -0
- package/src/all.js +19 -0
- package/src/base/button.js +61 -0
- package/src/base/checkbox.js +118 -0
- package/src/base/controllers/list-controller.js +96 -0
- package/src/base/controllers/popover-controller.js +163 -0
- package/src/base/field.js +3 -0
- package/src/base/hidden-styles.css.js +2 -0
- package/src/base/input.js +182 -0
- package/src/base/item.js +7 -0
- package/src/base/list-item.js +54 -0
- package/src/base/menu-item.js +12 -0
- package/src/base/menu-utils.js +111 -0
- package/src/base/menu.js +244 -0
- package/src/base/mixins/attachable.js +71 -0
- package/src/base/mixins/form-associated.js +69 -0
- package/src/base/mixins/internals-attached.js +13 -0
- package/src/base/option.js +17 -0
- package/src/base/select.js +285 -0
- package/src/base/switch.js +86 -0
- package/src/base/tooltip.js +139 -0
- package/src/core/focus-visible.js +13 -0
- package/src/core/shared.d.ts +1 -0
- package/src/core/unique-id.js +11 -0
- package/src/m3/button/common-button-styles.css.js +2 -0
- package/src/m3/button/common-button-toggle-styles.css.js +2 -0
- package/src/m3/button/common-button-toggle.js +69 -0
- package/src/m3/button/common-button.js +65 -0
- package/src/m3/button/icon-button-styles.css.js +2 -0
- package/src/m3/button/icon-button-toggle-styles.css.js +2 -0
- package/src/m3/button/icon-button-toggle.js +57 -0
- package/src/m3/button/icon-button.js +51 -0
- package/src/m3/button/shared-button-styles.css.js +2 -0
- package/src/m3/checkbox-styles.css.js +2 -0
- package/src/m3/checkbox.js +46 -0
- package/src/m3/fab-styles.css.js +2 -0
- package/src/m3/fab.js +48 -0
- package/src/m3/field/field-styles.css.js +2 -0
- package/src/m3/field/field.js +93 -0
- package/src/m3/field/filled-field-styles.css.js +2 -0
- package/src/m3/field/filled-field.js +30 -0
- package/src/m3/field/outlined-field-styles.css.js +2 -0
- package/src/m3/field/outlined-field.js +34 -0
- package/src/m3/focus-ring-styles.css.js +2 -0
- package/src/m3/focus-ring.js +72 -0
- package/src/m3/item-styles.css.js +2 -0
- package/src/m3/item.js +46 -0
- package/src/m3/list-item-styles.css.js +2 -0
- package/src/m3/list-item.js +52 -0
- package/src/m3/list-styles.css.js +2 -0
- package/src/m3/list.js +16 -0
- package/src/m3/menu-item.js +15 -0
- package/src/m3/menu-part-styles.css.js +2 -0
- package/src/m3/menu-styles.css.js +2 -0
- package/src/m3/menu.js +30 -0
- package/src/m3/option.js +15 -0
- package/src/m3/ripple-styles.css.js +2 -0
- package/src/m3/ripple.js +199 -0
- package/src/m3/select/filled-select.js +41 -0
- package/src/m3/select/outlined-select.js +41 -0
- package/src/m3/select/select-styles.css.js +2 -0
- package/src/m3/select/select.js +34 -0
- package/src/m3/switch-styles.css.js +2 -0
- package/src/m3/switch.js +129 -0
- package/src/m3/target-styles.css.js +2 -0
- package/src/m3/text-field/filled-text-field.js +38 -0
- package/src/m3/text-field/outlined-text-field.js +40 -0
- package/src/m3/text-field/text-field-styles.css.js +2 -0
- package/src/m3/toolbar-styles.css.js +2 -0
- package/src/m3/toolbar.js +53 -0
- package/src/m3/tooltip-styles.css.js +2 -0
- 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 };
|
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}`;
|
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 };
|
package/src/m3/option.js
ADDED
|
@@ -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}`;
|
package/src/m3/ripple.js
ADDED
|
@@ -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}`;
|
package/src/m3/switch.js
ADDED
|
@@ -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 };
|