@vollowx/seele 0.13.8 → 0.13.9

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/nagivation/navigation-rail-item-styles.css.js +2 -0
  38. package/src/m3/nagivation/navigation-rail-item.d.ts +21 -0
  39. package/src/m3/nagivation/navigation-rail-item.js +44 -0
  40. package/src/m3/nagivation/navigation-rail-styles.css.js +2 -0
  41. package/src/m3/nagivation/navigation-rail.d.ts +12 -0
  42. package/src/m3/nagivation/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
@@ -0,0 +1,44 @@
1
+ import { __decorate } from "tslib";
2
+ import { html } from 'lit';
3
+ import { customElement, property, query } from 'lit/decorators.js';
4
+ import { internals } from '../../base/mixins/internals-attached.js';
5
+ import { Button } from '../../base/button.js';
6
+ import '../focus-ring/focus-ring.js';
7
+ import '../ripple/ripple.js';
8
+ import { navigationRailItemStyles } from './navigation-rail-item-styles.css.js';
9
+ let M3NavigationRailItem = class M3NavigationRailItem extends Button {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.active = false;
13
+ }
14
+ static { this.styles = [navigationRailItemStyles]; }
15
+ render() {
16
+ return html `<div class="pill-root"><div class="pill"><md-focus-ring></md-focus-ring><md-ripple></md-ripple></div><slot></slot><slot name="active"></slot><span class="label-inside">${this.label}</span></div><span class="label-outside">${this.label}</span>`;
17
+ }
18
+ updated(changed) {
19
+ if (changed.has('label'))
20
+ this[internals].ariaLabel = this.label;
21
+ if (changed.has('active'))
22
+ this[internals].ariaCurrent = this.active ? 'true' : null;
23
+ }
24
+ firstUpdated() {
25
+ this.$focusRing.attach(this);
26
+ this.$ripple.attach(this);
27
+ }
28
+ };
29
+ __decorate([
30
+ property({ reflect: true })
31
+ ], M3NavigationRailItem.prototype, "label", void 0);
32
+ __decorate([
33
+ property({ type: Boolean, reflect: true })
34
+ ], M3NavigationRailItem.prototype, "active", void 0);
35
+ __decorate([
36
+ query('md-focus-ring')
37
+ ], M3NavigationRailItem.prototype, "$focusRing", void 0);
38
+ __decorate([
39
+ query('md-ripple')
40
+ ], M3NavigationRailItem.prototype, "$ripple", void 0);
41
+ M3NavigationRailItem = __decorate([
42
+ customElement('md-nav-rail-item')
43
+ ], M3NavigationRailItem);
44
+ export { M3NavigationRailItem };
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const navigationRailStyles = css`:host{background-color:var(--md-sys-color-surface-container);-webkit-user-select:none;user-select:none;z-index:10;flex-shrink:0;grid-template-rows:min-content auto;justify-content:space-between;gap:40px;width:96px;height:100%;padding-top:44px;padding-bottom:20px;display:grid;overflow:visible}.actions{z-index:10;place-self:center;display:grid;position:sticky;top:-44px}::slotted(md-fab){box-shadow:none}.items{grid-template-areas:"stack";display:grid}slot:not([name]){flex-direction:column;grid-area:stack;gap:8px;padding:0;list-style:none;display:flex;position:relative}`;
@@ -0,0 +1,12 @@
1
+ import { LitElement } from 'lit';
2
+ import { type M3NavigationRailItem } from './navigation-rail-item.js';
3
+ export declare class M3NavigationRail extends LitElement {
4
+ get $items(): Array<M3NavigationRailItem>;
5
+ static styles: any[];
6
+ render(): import("lit-html").TemplateResult<1>;
7
+ }
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'md-nav-rail': M3NavigationRail;
11
+ }
12
+ }
@@ -0,0 +1,17 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement, html } from 'lit';
3
+ import { customElement } from 'lit/decorators.js';
4
+ import { navigationRailStyles } from './navigation-rail-styles.css.js';
5
+ let M3NavigationRail = class M3NavigationRail extends LitElement {
6
+ get $items() {
7
+ return [...this.querySelectorAll('md-nav-rail-item')];
8
+ }
9
+ static { this.styles = [navigationRailStyles]; }
10
+ render() {
11
+ return html `<div class="actions"><slot name="menu"></slot><slot name="fab"></slot></div><div class="items"><slot></slot></div>`;
12
+ }
13
+ };
14
+ M3NavigationRail = __decorate([
15
+ customElement('md-nav-rail')
16
+ ], M3NavigationRail);
17
+ export { M3NavigationRail };
@@ -1,2 +1,2 @@
1
1
  import { css } from 'lit';
2
- export const radioStyles = css`:host{--_d:var(--md-sys-motion-effects-default-duration);--_default:var(--_d) var(--md-sys-motion-effects-default);--_slow:var(--md-sys-motion-effects-slow-duration) var(--md-sys-motion-effects-slow);cursor:pointer;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none;border-radius:20px;outline:0;justify-content:center;align-items:center;width:40px;height:40px;display:inline-flex;position:relative}:host:before,.middle,:host:after{content:"";box-sizing:border-box;border-radius:50%;position:absolute;animation-fill-mode:forwards!important}:host:before{z-index:1;background-color:var(--md-sys-color-on-surface-variant);width:20px;height:20px;transition:background var(--_default)}.middle{z-index:2;background-color:var(--md-sys-color-surface);width:16px;height:16px}:host:after{z-index:3;background-color:var(--md-sys-color-primary);width:10px;height:10px;transform:scale(0)}:host(:state(unchecking)) .middle{animation:uncheck-mid-2 var(--_slow) var(--_d)}:host(:state(unchecking)):after{animation:uncheck-inner-1 var(--_default), uncheck-inner-2 var(--_slow) var(--_d)}:host([checked]):before{background-color:var(--md-sys-color-primary)}:host([checked]):after{transform:scale(1)}:host(:state(checking)) .middle{animation:check-mid-1 var(--_default), check-mid-2 var(--_slow) var(--_d)}:host(:state(checking)):after{animation:check-inner-1 var(--_default), check-inner-2 var(--_slow) var(--_d)}@keyframes uncheck-mid-2{0%,to{z-index:4}0%{transform:scale(0)}to{transform:scale(1)}}@keyframes uncheck-inner-1{0%{background-color:var(--md-sys-color-primary);transform:scale(1)}to{background-color:var(--md-sys-color-on-surface-variant);transform:scale(1.6)}}@keyframes uncheck-inner-2{0%{transform:scale(1.6)}to{transform:scale(1.6)}}@keyframes check-mid-1{0%{transform:scale(1)}to{transform:scale(0)}}@keyframes check-mid-2{0%{transform:scale(.625)}to{transform:scale(1)}}@keyframes check-inner-1{0%,to{transform:scale(0)}}@keyframes check-inner-2{0%,to{transform:scale(1)}}:host([disabled]){pointer-events:none}:host([disabled]):before,:host([disabled]):after{background:color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent)}@media (forced-colors:active){:host{--md-sys-color-primary:SelectedItem;--md-sys-color-on-surface-variant:CanvasText}:host(:disabled):before,:host(:disabled):after{background:graytext}}`;
2
+ export const radioStyles = css`:host{--_d:var(--md-sys-motion-effects-default-duration);--_default:var(--_d) var(--md-sys-motion-effects-default);--_slow:var(--md-sys-motion-effects-slow-duration) var(--md-sys-motion-effects-slow);cursor:pointer;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none;border-radius:20px;outline:0;justify-content:center;align-items:center;width:40px;height:40px;display:inline-flex;position:relative}.icon{z-index:1;width:20px;height:20px}.ring{fill:none;r:9px;stroke:var(--md-sys-color-on-surface-variant);stroke-width:2px;transition:stroke var(--_default);will-change:r, stroke-width}:host(:state(checked)) .ring{stroke:var(--md-sys-color-primary)}.dot{fill:var(--md-sys-color-primary);r:0px;will-change:r}:host(:state(checked)) .dot{r:5px}:host(:state(checking)) .ring{animation:check-ring-1 var(--_default), check-ring-2 var(--_slow) var(--_d)}:host(:state(checking)) .dot{animation:check-dot-1 var(--_default), check-dot-2 var(--_slow) var(--_d)}@keyframes check-ring-1{0%{r:9px;stroke-width:2px}to{r:4.5px;stroke-width:9px}}@keyframes check-ring-2{0%{r:8px;stroke-width:2px}to{r:9px;stroke-width:2px}}@keyframes check-dot-1{0%,to{r:0px}}@keyframes check-dot-2{0%{r:7px}to{r:5px}}:host(:state(unchecking)) .ring{animation:uncheck-ring-1 var(--_default), uncheck-ring-2 var(--_slow) var(--_d)}:host(:state(unchecking)) .dot{animation:uncheck-dot-1 var(--_default)}@keyframes uncheck-ring-1{0%{r:9px;stroke:var(--md-sys-color-primary);stroke-width:2px}to{r:8px;stroke:var(--md-sys-color-on-surface-variant);stroke-width:2px}}@keyframes uncheck-ring-2{0%{r:4.5px;stroke-width:9px}to{r:9px;stroke-width:2px}}@keyframes uncheck-dot-1{0%{fill:var(--md-sys-color-primary);r:5px}to{fill:var(--md-sys-color-on-surface-variant);r:7.5px}}:host([disabled]){pointer-events:none}:host([disabled]) .ring{stroke:color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent)}:host([disabled]) .dot{fill:color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent)}@media (forced-colors:active){:host{--md-sys-color-primary:SelectedItem;--md-sys-color-on-surface-variant:CanvasText}:host(:disabled) .ring{stroke:graytext}:host(:disabled) .dot{fill:graytext}}`;
@@ -2,12 +2,15 @@ import { PropertyValues } from 'lit';
2
2
  import { Radio } from '../../base/radio.js';
3
3
  import '../focus-ring/focus-ring.js';
4
4
  import '../ripple/ripple.js';
5
+ import type { M3Ripple } from '../ripple/ripple.js';
5
6
  /**
6
7
  * @tag md-radio
7
8
  */
8
9
  export declare class M3Radio extends Radio {
10
+ $ripple: M3Ripple;
9
11
  static styles: any[];
10
12
  render(): import("lit-html").TemplateResult<1>;
13
+ firstUpdated(): void;
11
14
  updated(changedProperties: PropertyValues<this>): void;
12
15
  }
13
16
  declare global {
@@ -1,19 +1,24 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { html } from 'lit';
3
- import { Radio } from '../../base/radio.js';
3
+ import { query } from 'lit/decorators.js';
4
4
  import { customElement } from '../../core/decorators.js';
5
5
  import { internals } from '../../base/mixins/internals-attached.js';
6
- import { radioStyles } from './radio-styles.css.js';
7
- import { targetStyles } from '../target-styles.css.js';
6
+ import { Radio } from '../../base/radio.js';
8
7
  import '../focus-ring/focus-ring.js';
9
8
  import '../ripple/ripple.js';
9
+ import { targetStyles } from '../target-styles.css.js';
10
+ import { radioStyles } from './radio-styles.css.js';
10
11
  /**
11
12
  * @tag md-radio
12
13
  */
13
14
  let M3Radio = class M3Radio extends Radio {
14
15
  static { this.styles = [targetStyles, radioStyles]; }
15
16
  render() {
16
- return html `<md-focus-ring></md-focus-ring><md-ripple></md-ripple><span part="target"></span> <span class="middle"></span>`;
17
+ return html `<md-focus-ring></md-focus-ring><md-ripple enterbehavior="none"></md-ripple><span part="target"></span> <svg class="icon" viewBox="0 0 20 20" aria-hidden="true"><circle class="ring" cx="10" cy="10" r="9"/><circle class="dot" cx="10" cy="10" r="0"/></svg>`;
18
+ }
19
+ firstUpdated() {
20
+ // SSR'd <md-radio> components don't have their labels set up on time
21
+ this.$ripple.attach(this, true);
17
22
  }
18
23
  updated(changedProperties) {
19
24
  super.updated(changedProperties);
@@ -27,6 +32,9 @@ let M3Radio = class M3Radio extends Radio {
27
32
  }
28
33
  }
29
34
  };
35
+ __decorate([
36
+ query('md-ripple')
37
+ ], M3Radio.prototype, "$ripple", void 0);
30
38
  M3Radio = __decorate([
31
39
  customElement('md-radio')
32
40
  ], M3Radio);
@@ -1,4 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
+ import { handleControlChange } from '../../base/mixins/attachable.js';
2
3
  declare const M3Ripple_base: Constructor<import("../../base/mixins/attachable.js").AttachableInterface> & Constructor<import("../../base/mixins/internals-attached.js").InternalsAttachedInterface> & typeof LitElement;
3
4
  /**
4
5
  * @tag md-ripple
@@ -19,7 +20,7 @@ export declare class M3Ripple extends M3Ripple_base {
19
20
  handlePointerLeave: () => void;
20
21
  handlePointerDown: (e: PointerEvent) => void;
21
22
  handlePointerUp: () => void;
22
- handleControlChange(prev?: HTMLElement | null, next?: HTMLElement | HTMLInputElement | null): void;
23
+ [handleControlChange](prev?: HTMLElement | null, next?: HTMLElement | null): void;
23
24
  addRipple(e?: MouseEvent | null): void;
24
25
  removeRipple(ripple: HTMLSpanElement): void;
25
26
  keepLastRipple(): void;
@@ -2,16 +2,16 @@ import { __decorate } from "tslib";
2
2
  import { LitElement } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { customElement } from '../../core/decorators.js';
5
- import { Attachable } from '../../base/mixins/attachable.js';
5
+ import { Attachable, handleControlChange, } from '../../base/mixins/attachable.js';
6
6
  import { InternalsAttached, internals, } from '../../base/mixins/internals-attached.js';
7
7
  import { rippleStyles } from './ripple-styles.css.js';
8
8
  const PRESS_GROW_MS = 450;
9
9
  const MINIMUM_PRESS_MS = 225;
10
10
  const OPACITY_IN_MS = 105;
11
11
  const OPACITY_OUT_MS = 375;
12
- function distance({ x: ax, y: ay }, { x: bx, y: by }) {
12
+ const distance = ({ x: ax, y: ay }, { x: bx, y: by }) => {
13
13
  return Math.sqrt((ax - bx) ** 2 + (ay - by) ** 2);
14
- }
14
+ };
15
15
  /**
16
16
  * @tag md-ripple
17
17
  *
@@ -83,31 +83,29 @@ let M3Ripple = class M3Ripple extends Attachable(InternalsAttached(LitElement))
83
83
  #spaceKeyDown;
84
84
  #pointerDown;
85
85
  #lastTime;
86
- handleControlChange(prev = null, next = null) {
86
+ [handleControlChange](prev = null, next = null) {
87
87
  const eventHandlers = {
88
- keydown: this.handleKeyDown,
89
- keyup: this.handleKeyUp,
90
- pointerenter: this.handlePointerEnter,
91
- pointerleave: this.handlePointerLeave,
92
- pointerdown: this.handlePointerDown,
88
+ keydown: { fn: this.handleKeyDown, kbd: true },
89
+ keyup: { fn: this.handleKeyUp, kbd: true },
90
+ pointerenter: { fn: this.handlePointerEnter, kbd: false },
91
+ pointerleave: { fn: this.handlePointerLeave, kbd: false },
92
+ pointerdown: { fn: this.handlePointerDown, kbd: false },
93
93
  };
94
- Object.keys(eventHandlers).forEach((eventName) => {
95
- // @ts-ignore
96
- prev?.labels?.forEach((label) => label.removeEventListener(eventName, eventHandlers[eventName]));
97
- prev?.removeEventListener(eventName, eventHandlers[eventName]);
94
+ Object.entries(eventHandlers).forEach(([eventName, { fn, kbd }]) => {
95
+ prev?.labels?.forEach((label) => label.removeEventListener(eventName, fn));
96
+ prev?.removeEventListener(eventName, fn);
98
97
  // Check if control is nested in label, if so, only bind to label
99
98
  let isNestedInLabel = false;
100
- // @ts-ignore
101
99
  next?.labels?.forEach((label) => {
102
- if (label.contains(next))
100
+ if (label.contains(next)) {
103
101
  isNestedInLabel = true;
102
+ }
103
+ if (!kbd) {
104
+ label.addEventListener(eventName, fn);
105
+ }
104
106
  });
105
- if (isNestedInLabel) {
106
- // @ts-ignore
107
- next.labels?.forEach((label) => label.addEventListener(eventName, eventHandlers[eventName]));
108
- }
109
- else {
110
- next?.addEventListener(eventName, eventHandlers[eventName]);
107
+ if (!isNestedInLabel || kbd) {
108
+ next?.addEventListener(eventName, fn);
111
109
  }
112
110
  });
113
111
  }
@@ -119,7 +117,7 @@ let M3Ripple = class M3Ripple extends Attachable(InternalsAttached(LitElement))
119
117
  };
120
118
  const centered = !e;
121
119
  const endCenter = containerMiddle;
122
- let startCenter = endCenter;
120
+ let startCenter = { ...endCenter };
123
121
  if (!centered) {
124
122
  startCenter.x = e.clientX - containerRect.left;
125
123
  startCenter.y = e.clientY - containerRect.top;
@@ -2,7 +2,7 @@ body {
2
2
  accent-color: var(--md-sys-color-primary);
3
3
  background-color: var(--md-sys-color-background);
4
4
  color: var(--md-sys-color-on-background);
5
- font-family: var(--md-sys-typography-family);
5
+ font: var(--md-sys-typography-body-large);
6
6
  }
7
7
 
8
8
  ::selection {
@@ -0,0 +1,15 @@
1
+ :root {
2
+ --md-sys-motion-spatial-fast: cubic-bezier(0.42, 1.67, 0.21, 0.9);
3
+ --md-sys-motion-spatial-fast-duration: 350ms;
4
+ --md-sys-motion-spatial-default: cubic-bezier(0.38, 1.21, 0.22, 1);
5
+ --md-sys-motion-spatial-default-duration: 500ms;
6
+ --md-sys-motion-spatial-slow: cubic-bezier(0.39, 1.29, 0.35, 0.98);
7
+ --md-sys-motion-spatial-slow-duration: 650ms;
8
+
9
+ --md-sys-motion-effects-fast: cubic-bezier(0.31, 0.94, 0.34, 1);
10
+ --md-sys-motion-effects-fast-duration: 150ms;
11
+ --md-sys-motion-effects-default: cubic-bezier(0.34, 0.8, 0.34, 1);
12
+ --md-sys-motion-effects-default-duration: 200ms;
13
+ --md-sys-motion-effects-slow: cubic-bezier(0.34, 0.88, 0.34, 1);
14
+ --md-sys-motion-effects-slow-duration: 300ms;
15
+ }
@@ -0,0 +1,15 @@
1
+ :root {
2
+ --md-sys-motion-spatial-fast: cubic-bezier(0.27, 1.06, 0.18, 1);
3
+ --md-sys-motion-spatial-fast-duration: 350ms;
4
+ --md-sys-motion-spatial-default: cubic-bezier(0.27, 1.06, 0.18, 1);
5
+ --md-sys-motion-spatial-default-duration: 500ms;
6
+ --md-sys-motion-spatial-slow: cubic-bezier(0.27, 1.06, 0.18, 1);
7
+ --md-sys-motion-spatial-slow-duration: 750ms;
8
+
9
+ --md-sys-motion-effects-fast: cubic-bezier(0.31, 0.94, 0.34, 1);
10
+ --md-sys-motion-effects-fast-duration: 150ms;
11
+ --md-sys-motion-effects-default: cubic-bezier(0.34, 0.8, 0.34, 1);
12
+ --md-sys-motion-effects-default-duration: 200ms;
13
+ --md-sys-motion-effects-slow: cubic-bezier(0.34, 0.88, 0.34, 1);
14
+ --md-sys-motion-effects-slow-duration: 300ms;
15
+ }
@@ -0,0 +1,24 @@
1
+ :root {
2
+ --_brand: var(--md-ref-typeface-brand, sans-serif);
3
+ --_plain: var(--md-ref-typeface-plain, sans-serif);
4
+
5
+ --md-sys-typography-display-large: 400 3.5625rem / 4rem var(--_brand);
6
+ --md-sys-typography-display-medium: 400 2.8125rem / 3.25rem var(--_brand);
7
+ --md-sys-typography-display-small: 400 2.25rem / 2.75rem var(--_brand);
8
+
9
+ --md-sys-typography-headline-large: 400 2rem / 2.5rem var(--_brand);
10
+ --md-sys-typography-headline-medium: 400 1.75rem / 2.25rem var(--_brand);
11
+ --md-sys-typography-headline-small: 400 1.5rem / 2rem var(--_brand);
12
+
13
+ --md-sys-typography-title-large: 400 1.375rem / 1.75rem var(--_brand);
14
+ --md-sys-typography-title-medium: 500 1rem / 1.25rem var(--_plain);
15
+ --md-sys-typography-title-small: 500 0.875rem / 1.125rem var(--_plain);
16
+
17
+ --md-sys-typography-label-large: 500 0.875rem / 1.25rem var(--_plain);
18
+ --md-sys-typography-label-medium: 500 0.75rem / 1rem var(--_plain);
19
+ --md-sys-typography-label-small: 500 0.6875rem / 0.875rem var(--_plain);
20
+
21
+ --md-sys-typography-body-large: 400 1rem / 1.5rem var(--_plain);
22
+ --md-sys-typography-body-medium: 400 0.875rem / 1.25rem var(--_plain);
23
+ --md-sys-typography-body-small: 400 0.75rem / 1rem var(--_plain);
24
+ }
@@ -20,6 +20,7 @@ export declare class M3Switch extends ToggleButton {
20
20
  renderOffIcon(): import("lit-html").TemplateResult<1>;
21
21
  connectedCallback(): void;
22
22
  disconnectedCallback(): void;
23
+ firstUpdated(): void;
23
24
  }
24
25
  declare global {
25
26
  interface HTMLElementTagNameMap {
@@ -69,9 +69,6 @@ let M3Switch = class M3Switch extends ToggleButton {
69
69
  }
70
70
  connectedCallback() {
71
71
  super.connectedCallback();
72
- this.updateComplete.then(() => {
73
- this.$ripple.attach(this, true);
74
- });
75
72
  this.addEventListener('pointerdown', this.#handlePointerDown);
76
73
  this.addEventListener('pointerup', this.#handlePointerUp);
77
74
  }
@@ -80,6 +77,10 @@ let M3Switch = class M3Switch extends ToggleButton {
80
77
  this.removeEventListener('pointerup', this.#handlePointerUp);
81
78
  super.disconnectedCallback();
82
79
  }
80
+ firstUpdated() {
81
+ // SSR'd <md-switch> components don't have their labels set up on time
82
+ this.$ripple.attach(this, true);
83
+ }
83
84
  #pointerDownX;
84
85
  #handlePointerDown;
85
86
  #handlePointerMove;
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export const secondaryTabStyles = css`:host{--_tab-selected-color:var(--md-sys-color-on-surface);--_indicator-height:2px}[part=indicator]{border-radius:0;left:0;right:0}`;
@@ -0,0 +1,5 @@
1
+ import { M3Tab } from './tab.js';
2
+ export declare class M3SecondaryTab extends M3Tab {
3
+ protected _isSecondary: boolean;
4
+ static styles: any[];
5
+ }
@@ -0,0 +1,15 @@
1
+ import { __decorate } from "tslib";
2
+ import { customElement } from '../../core/decorators.js';
3
+ import { M3Tab } from './tab.js';
4
+ import { secondaryTabStyles } from './secondary-tab-styles.css.js';
5
+ let M3SecondaryTab = class M3SecondaryTab extends M3Tab {
6
+ constructor() {
7
+ super(...arguments);
8
+ this._isSecondary = true;
9
+ }
10
+ static { this.styles = [...super.styles, secondaryTabStyles]; }
11
+ };
12
+ M3SecondaryTab = __decorate([
13
+ customElement('md-secondary-tab')
14
+ ], M3SecondaryTab);
15
+ export { M3SecondaryTab };
@@ -1,2 +1,2 @@
1
1
  import { css } from 'lit';
2
- export const tabPanelStyles = css`:host{display:block}:host([hidden]){display:none}`;
2
+ export const tabPanelStyles = css`:host{display:block}:host(:not([selected])){display:none!important}`;
@@ -1,2 +1,2 @@
1
1
  import { css } from 'lit';
2
- export const tabStyles = css`:host{--md-focus-ring-shape:12px;box-sizing:border-box;color:var(--md-sys-color-on-surface-variant);cursor:pointer;font:var(--md-sys-typography-title-small);-webkit-tap-highlight-color:transparent;text-wrap-mode:nowrap;user-select:none;-webkit-user-select-:none;outline:none;flex-shrink:0;justify-content:center;padding:0 16px;display:inline-flex;position:relative}:host([selected]){color:var(--_tab-selected-color)}:host([selected]) md-focus-ring{margin-bottom:calc(var(--_tab-indicator-height) + 2px)}[part=content]{flex-direction:var(--_tab-flex-dir,row);align-items:center;gap:var(--_tab-gap,8px);height:var(--_tab-height,48px);justify-content:center;display:inline-flex}[part~=icon]{fill:currentColor;block-size:1em;inline-size:1em;font-size:24px}`;
2
+ export const tabStyles = css`:host{--md-focus-ring-shape:12px;box-sizing:border-box;color:var(--md-sys-color-on-surface-variant);cursor:pointer;font:var(--md-sys-typography-title-small);-webkit-tap-highlight-color:transparent;text-wrap-mode:nowrap;user-select:none;-webkit-user-select-:none;outline:none;flex-shrink:0;justify-content:center;padding:0 16px;display:inline-flex;position:relative}:host([selected]){color:var(--_tab-selected-color);& md-focus-ring{margin-bottom:calc(var(--_indicator-height) + 2px)}& [part=indicator]{opacity:1}}:host([disabled]){pointer-events:none;color:color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent)}[part=content]{flex-direction:var(--_tab-flex-dir,row);align-items:center;gap:var(--_tab-gap,8px);height:var(--_tab-height,48px);justify-content:center;display:inline-flex;position:relative}[part=indicator]{height:var(--_indicator-height);background-color:var(--md-sys-color-primary);opacity:0;transform-origin:0;pointer-events:none;will-change:transform, opacity;border-radius:3px 3px 0 0;min-width:24px;position:absolute;bottom:0;left:2px;right:2px}::slotted([slot=icon]){fill:currentColor;block-size:1em;inline-size:1em;font-size:24px}`;
@@ -9,8 +9,11 @@ import '../ripple/ripple.js';
9
9
  */
10
10
  export declare class M3Tab extends Tab {
11
11
  $content: HTMLDivElement;
12
+ $indicator: HTMLElement;
13
+ protected _isSecondary: boolean;
12
14
  static styles: any[];
13
15
  render(): import("lit-html").TemplateResult<1>;
16
+ animateIndicator(previousTab: M3Tab): void;
14
17
  }
15
18
  declare global {
16
19
  interface HTMLElementTagNameMap {
package/src/m3/tab/tab.js CHANGED
@@ -1,11 +1,13 @@
1
1
  import { __decorate } from "tslib";
2
- import { html } from 'lit';
3
- import { customElement, query } from 'lit/decorators.js';
2
+ import { html, nothing } from 'lit';
3
+ import { customElement, query, state } from 'lit/decorators.js';
4
4
  import { Tab } from '../../base/tab.js';
5
+ import { getSpring } from '../styles/motion.js';
5
6
  import '../focus-ring/focus-ring.js';
6
7
  import '../ripple/ripple.js';
7
8
  import { targetStyles } from '../target-styles.css.js';
8
9
  import { tabStyles } from './tab-styles.css.js';
10
+ const KEYFRAMES = 20;
9
11
  /**
10
12
  * @tag md-tab
11
13
  *
@@ -13,14 +15,77 @@ import { tabStyles } from './tab-styles.css.js';
13
15
  * @slot - label
14
16
  */
15
17
  let M3Tab = class M3Tab extends Tab {
18
+ constructor() {
19
+ super(...arguments);
20
+ this._isSecondary = false;
21
+ }
16
22
  static { this.styles = [targetStyles, tabStyles]; }
17
23
  render() {
18
- return html `<md-focus-ring inward></md-focus-ring><md-ripple inward></md-ripple><span part="target"></span><div part="content"><slot part="icon" name="icon" aria-hidden="true"></slot><slot part="label"></slot></div>`;
24
+ return html `<md-focus-ring inward></md-focus-ring><md-ripple></md-ripple><span part="target"></span><div part="content"><slot part="icon" name="icon" aria-hidden="true"></slot><slot part="label"></slot>${!this._isSecondary ? html `<div part="indicator" role="presentation"></div>` : nothing}</div>${this._isSecondary ? html `<div part="indicator" role="presentation"></div>` : nothing}`;
25
+ }
26
+ animateIndicator(previousTab) {
27
+ const indicator = this.$indicator;
28
+ indicator.getAnimations().forEach((a) => a.cancel());
29
+ const prevIndicator = previousTab.$indicator;
30
+ if (prevIndicator &&
31
+ !window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
32
+ const from = prevIndicator.getBoundingClientRect();
33
+ const to = indicator.getBoundingClientRect();
34
+ let keyframes = [];
35
+ if (!this._isSecondary) {
36
+ const startLeft = from.left - to.left;
37
+ const startRight = from.right - to.left;
38
+ const endLeft = 0;
39
+ const endRight = to.width;
40
+ const movingRight = startLeft < 0;
41
+ for (let i = 0; i <= KEYFRAMES; i++) {
42
+ const t = i / KEYFRAMES;
43
+ const dec = Math.sin((t * Math.PI) / 2);
44
+ const acc = 1 - Math.cos((t * Math.PI) / 2);
45
+ const leftProgress = movingRight ? acc : dec;
46
+ const rightProgress = movingRight ? dec : acc;
47
+ const left = startLeft + (endLeft - startLeft) * leftProgress;
48
+ const right = startRight + (endRight - startRight) * rightProgress;
49
+ const width = right - left;
50
+ const translateX = left.toFixed(4);
51
+ const scaleX = (width / to.width).toFixed(4);
52
+ keyframes.push({
53
+ transform: `translateX(${translateX}px) scaleX(${scaleX})`,
54
+ });
55
+ }
56
+ }
57
+ else {
58
+ const translateX = (from.left - to.left).toFixed(4);
59
+ const scaleX = (from.width / to.width).toFixed(4);
60
+ keyframes = [
61
+ {
62
+ transform: `translateX(${translateX}px) scaleX(${scaleX})`,
63
+ },
64
+ { transform: 'none' },
65
+ ];
66
+ }
67
+ indicator.animate(keyframes, {
68
+ ...getSpring(this, 'spatial', 'default'),
69
+ fill: 'none',
70
+ });
71
+ }
72
+ else {
73
+ indicator.animate([{ opacity: '0' }, { opacity: '1' }], {
74
+ ...getSpring(this, 'effects', 'default'),
75
+ fill: 'none',
76
+ });
77
+ }
19
78
  }
20
79
  };
21
80
  __decorate([
22
81
  query('[part="content"]')
23
82
  ], M3Tab.prototype, "$content", void 0);
83
+ __decorate([
84
+ query('[part="indicator"]')
85
+ ], M3Tab.prototype, "$indicator", void 0);
86
+ __decorate([
87
+ state()
88
+ ], M3Tab.prototype, "_isSecondary", void 0);
24
89
  M3Tab = __decorate([
25
90
  customElement('md-tab')
26
91
  ], M3Tab);
@@ -1,2 +1,2 @@
1
1
  import { css } from 'lit';
2
- export const tabsStyles = css`:host{--_tab-selected-color:var(--md-sys-color-primary);--_tab-indicator-height:3px;border-bottom:1px solid var(--md-sys-color-outline-variant);box-sizing:border-box;scroll-behavior:smooth;scrollbar-width:none;display:block;position:relative;overflow:auto hidden}[part=tablist]{display:flex}[part=indicator]{height:var(--_tab-indicator-height);background-color:var(--md-sys-color-primary);transition:left var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-spatial-default), width var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-spatial-default);will-change:left, width;border-radius:3px 3px 0 0;position:absolute;bottom:0}::slotted(*){flex:1}:host([secondary]){--_tab-selected-color:var(--md-sys-color-on-surface);--_tab-indicator-height:2px}:host([secondary]) [part=indicator]{border-radius:0}:host([iconsabove]){--_tab-flex-dir:column;--_tab-height:64px;--_tab-gap:2px}@media (forced-colors:active){[part=indicator]{background-color:highlight}}`;
2
+ export const tabsStyles = css`:host{--_tab-selected-color:var(--md-sys-color-primary);--_indicator-height:3px;box-sizing:border-box;flex-direction:column;display:flex;position:relative}[part=tablist]{border-bottom:1px solid var(--md-sys-color-outline-variant);box-sizing:border-box;scroll-behavior:smooth;scrollbar-width:none;display:flex;overflow:auto hidden}::slotted(md-tab),::slotted(md-secondary-tab){flex:1}:host([iconsabove]){--_tab-flex-dir:column;--_tab-height:64px;--_tab-gap:2px}@media (forced-colors:active){[part=indicator]{background-color:highlight}}`;
@@ -5,18 +5,12 @@ import type { M3Tab } from './tab.js';
5
5
  *
6
6
  * @tag md-tabs
7
7
  *
8
- * @csspart indicator
9
- *
10
8
  * @slot - tabs
11
9
  */
12
10
  export declare class M3Tabs extends Tabs {
13
- #private;
14
- $indicator: HTMLElement;
15
- secondary: boolean;
16
11
  iconsAbove: boolean;
17
12
  static styles: any[];
18
- render(): import("lit-html").TemplateResult<1>;
19
- selectTab(selectedTab: M3Tab): void;
13
+ _selectTab(selectedTab: M3Tab): void;
20
14
  }
21
15
  declare global {
22
16
  interface HTMLElementTagNameMap {
@@ -1,7 +1,5 @@
1
1
  import { __decorate } from "tslib";
2
- import { html } from 'lit';
3
- import { customElement, property, query } from 'lit/decorators.js';
4
- import { computePosition, autoUpdate } from '@floating-ui/dom';
2
+ import { customElement, property } from 'lit/decorators.js';
5
3
  import { Tabs } from '../../base/tabs.js';
6
4
  import { tabsStyles } from './tabs-styles.css.js';
7
5
  /**
@@ -9,52 +7,21 @@ import { tabsStyles } from './tabs-styles.css.js';
9
7
  *
10
8
  * @tag md-tabs
11
9
  *
12
- * @csspart indicator
13
- *
14
10
  * @slot - tabs
15
11
  */
16
12
  let M3Tabs = class M3Tabs extends Tabs {
17
13
  constructor() {
18
14
  super(...arguments);
19
- this.secondary = false;
20
15
  this.iconsAbove = false;
21
16
  }
22
- #cleanup;
23
17
  static { this.styles = [tabsStyles]; }
24
- render() {
25
- return html `${super.render()}<div part="indicator" role="presentation"></div>`;
26
- }
27
- selectTab(selectedTab) {
28
- super.selectTab(selectedTab);
29
- // It's kinda ridiculous to use floating-ui on such simple element, but I
30
- // do not want to have indicators in each tab either.
31
- // Another solution is using CSS anchor, which does not work across Shadow
32
- // DOM for now.
33
- this.#cleanup?.();
34
- const updatePosition = () => {
35
- computePosition(selectedTab, this.$indicator, {
36
- placement: 'bottom',
37
- strategy: 'absolute',
38
- }).then(({ x }) => {
39
- const left = (this.secondary ? x : (x + 2));
40
- const width = this.secondary
41
- ? selectedTab.offsetWidth
42
- : (selectedTab.$content.offsetWidth - 4);
43
- Object.assign(this.$indicator.style, {
44
- left: `${left}px`,
45
- width: `${width}px`,
46
- });
47
- });
48
- };
49
- this.#cleanup = autoUpdate(selectedTab, this.$indicator, updatePosition);
18
+ _selectTab(selectedTab) {
19
+ const previousTab = this.$tabs.find((t) => t.selected);
20
+ super._selectTab(selectedTab);
21
+ if (previousTab && previousTab !== selectedTab)
22
+ selectedTab.animateIndicator(previousTab);
50
23
  }
51
24
  };
52
- __decorate([
53
- query('[part="indicator"]')
54
- ], M3Tabs.prototype, "$indicator", void 0);
55
- __decorate([
56
- property({ type: Boolean, reflect: true })
57
- ], M3Tabs.prototype, "secondary", void 0);
58
25
  __decorate([
59
26
  property({ type: Boolean, reflect: true })
60
27
  ], M3Tabs.prototype, "iconsAbove", void 0);
@@ -1,34 +0,0 @@
1
- :root {
2
- --md-sys-typography-family: sans-serif;
3
-
4
- --md-sys-typography-display-large: 400 3.5625rem / 4rem
5
- var(--md-sys-typography-family);
6
- --md-sys-typography-display-medium: 400 2.8125rem / 3.25rem
7
- var(--md-sys-typography-family);
8
- --md-sys-typography-display-small: 400 2.25rem / 2.75rem
9
- var(--md-sys-typography-family);
10
- --md-sys-typography-headline-large: 400 2rem / 2.5rem
11
- var(--md-sys-typography-family);
12
- --md-sys-typography-headline-medium: 400 1.75rem / 2.25rem
13
- var(--md-sys-typography-family);
14
- --md-sys-typography-headline-small: 400 1.5rem / 2rem
15
- var(--md-sys-typography-family);
16
- --md-sys-typography-title-large: 400 1.375rem / 1.75rem
17
- var(--md-sys-typography-family);
18
- --md-sys-typography-title-medium: 500 1rem / 1.25rem
19
- var(--md-sys-typography-family);
20
- --md-sys-typography-title-small: 500 0.875rem / 1.125rem
21
- var(--md-sys-typography-family);
22
- --md-sys-typography-label-large: 500 0.875rem / 1.25rem
23
- var(--md-sys-typography-family);
24
- --md-sys-typography-label-medium: 500 0.75rem / 1rem
25
- var(--md-sys-typography-family);
26
- --md-sys-typography-label-small: 500 0.6875rem / 0.875rem
27
- var(--md-sys-typography-family);
28
- --md-sys-typography-body-large: 400 1rem / 1.5rem
29
- var(--md-sys-typography-family);
30
- --md-sys-typography-body-medium: 400 0.875rem / 1.25rem
31
- var(--md-sys-typography-family);
32
- --md-sys-typography-body-small: 400 0.75rem / 1rem
33
- var(--md-sys-typography-family);
34
- }
File without changes
File without changes
File without changes
File without changes