@swiftwc/ui 0.0.0-dev.98 → 0.0.0-dev.99
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/generated/components/toggle-view.js +156 -35
- package/generated/css/index.css +44 -16
- package/package.json +1 -1
- package/scss/components/_index.scss +1 -0
- package/scss/components/_toggle-view.scss +66 -28
- package/scss/final/_touch-glass.scss +7 -0
- package/web-components.html-data/en.json +1 -4
|
@@ -2,7 +2,7 @@ var _a;
|
|
|
2
2
|
import { CleanupRegistry } from '../internal/class/cleanup-registry';
|
|
3
3
|
import { FormAssociatedBase, getInternals } from '../internal/class/form-associated-base';
|
|
4
4
|
import { MutationObserverSet } from '../internal/class/mutation-observer-set';
|
|
5
|
-
import { $, devFlags, kebabCase, onoff } from '../internal/utils';
|
|
5
|
+
import { $, devFlags, kebabCase, onoff, touchGlass } from '../internal/utils';
|
|
6
6
|
import { queryMorph } from '../morphdom';
|
|
7
7
|
import { html } from '../tpl';
|
|
8
8
|
const toggleStyles = ['switch', 'button'];
|
|
@@ -24,7 +24,6 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
24
24
|
* @type {boolean}
|
|
25
25
|
*/
|
|
26
26
|
'is-on',
|
|
27
|
-
'keyboard-type',
|
|
28
27
|
/**
|
|
29
28
|
* @type {boolean}
|
|
30
29
|
*/
|
|
@@ -42,8 +41,7 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
42
41
|
<slot name="label"></slot>
|
|
43
42
|
</div>
|
|
44
43
|
<div part="root toggle-input-stack">
|
|
45
|
-
|
|
46
|
-
<div part="root toggle-form-input" tabindex="0"></div>
|
|
44
|
+
<div part="root toggle-track" tabindex="0"></div>
|
|
47
45
|
</div>
|
|
48
46
|
<slot name="validity-options" hidden></slot>
|
|
49
47
|
</label>`));
|
|
@@ -57,10 +55,30 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
57
55
|
#customValidity = '';
|
|
58
56
|
#slots = new Map();
|
|
59
57
|
#validityObservers = new MutationObserverSet(this.#renderValidityMsgs);
|
|
60
|
-
#
|
|
58
|
+
#track;
|
|
61
59
|
#value = 'on';
|
|
62
60
|
#isOn = false;
|
|
63
|
-
#
|
|
61
|
+
#didDrag = false;
|
|
62
|
+
#trackWidth = 0;
|
|
63
|
+
#dotSize = 0;
|
|
64
|
+
get #trackMinX() {
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
get #trackMaxX() {
|
|
68
|
+
return this.#trackWidth - this.#dotSize;
|
|
69
|
+
}
|
|
70
|
+
#handleMeasure = ([{ target, borderBoxSize }]) => {
|
|
71
|
+
if (devFlags.debug)
|
|
72
|
+
console.debug(`${_a.name} ⚡️ measure`);
|
|
73
|
+
if (!(target instanceof HTMLElement))
|
|
74
|
+
return;
|
|
75
|
+
this.#trackWidth = borderBoxSize.at(0)?.inlineSize ?? 0;
|
|
76
|
+
this.#dotSize = borderBoxSize.at(0)?.blockSize ?? 0;
|
|
77
|
+
};
|
|
78
|
+
#resizeObserver = new ResizeObserver(this.#handleMeasure);
|
|
79
|
+
get #isDragging() {
|
|
80
|
+
return '0ms' === this.#track?.style.getPropertyValue('--toggle--dot-transition-duration');
|
|
81
|
+
}
|
|
64
82
|
get #internals() {
|
|
65
83
|
return getInternals(this);
|
|
66
84
|
}
|
|
@@ -75,14 +93,18 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
75
93
|
});
|
|
76
94
|
CleanupRegistry.unregister(this, 'validities');
|
|
77
95
|
CleanupRegistry.register(this, onoff('slotchange', this.#handleValiditiesSlotchange, this.#slots?.get('validity-options')).on(), 'validities');
|
|
78
|
-
this.#
|
|
79
|
-
this.#input?.addEventListener('click', () => {
|
|
80
|
-
this.isOn = !this.isOn;
|
|
81
|
-
this.#sendValueToForm(this.#connected);
|
|
82
|
-
});
|
|
96
|
+
this.#track = this.#shadowRoot.querySelector('[part*=toggle-track]') ?? undefined;
|
|
83
97
|
CleanupRegistry.register(this, onoff([{ types: 'focusin', listener: this.#handleFocusin }], this).on());
|
|
84
|
-
CleanupRegistry.register(this, onoff([
|
|
85
|
-
|
|
98
|
+
CleanupRegistry.register(this, onoff([
|
|
99
|
+
{ types: 'keydown', listener: this.#handleTrackKeydown },
|
|
100
|
+
{ types: 'click', listener: this.#handleTrackClick },
|
|
101
|
+
{ types: 'pointerdown', listener: this.#handleTrackPointerdown },
|
|
102
|
+
{ types: 'pointerup', listener: this.#handleTrackPointerup },
|
|
103
|
+
{ types: 'pointercancel', listener: this.#handleTrackPointercancel },
|
|
104
|
+
{ types: 'pointermove', listener: this.#handleTrackPointermove },
|
|
105
|
+
{ types: 'lostpointercapture', listener: this.#handleTrackPointercancel },
|
|
106
|
+
], this.#track).on());
|
|
107
|
+
CleanupRegistry.register(this, onoff([{ types: 'blur', listener: this.#handleWindowBlur }], self).on());
|
|
86
108
|
}
|
|
87
109
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
88
110
|
if (devFlags.debug)
|
|
@@ -90,18 +112,18 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
90
112
|
switch (name) {
|
|
91
113
|
case 'value':
|
|
92
114
|
this.value = String(newValue); // this.#input?.setAttribute('checked', newValue ?? '')
|
|
93
|
-
this.#sendValueToForm(
|
|
115
|
+
this.#sendValueToForm(false);
|
|
94
116
|
break;
|
|
95
117
|
case 'is-on':
|
|
96
118
|
this.isOn = newValue !== null; // this.#input?.setAttribute('checked', newValue ?? '')
|
|
97
|
-
this.#sendValueToForm(
|
|
119
|
+
this.#sendValueToForm(false);
|
|
98
120
|
break;
|
|
99
121
|
case 'required':
|
|
100
122
|
// this.#input?.setAttribute(name, newValue ?? '')
|
|
101
|
-
this.#sendValueToForm(
|
|
123
|
+
this.#sendValueToForm(false);
|
|
102
124
|
break;
|
|
103
125
|
case 'name':
|
|
104
|
-
this.#sendValueToForm(
|
|
126
|
+
this.#sendValueToForm(false);
|
|
105
127
|
break;
|
|
106
128
|
case 'label':
|
|
107
129
|
queryMorph('[slot=label]', html `<label-view slot="label">${newValue ? html `<span>${newValue}</span>` : null}</label-view>`, this);
|
|
@@ -114,16 +136,18 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
114
136
|
}
|
|
115
137
|
disconnectedCallback() {
|
|
116
138
|
super.disconnectedCallback();
|
|
139
|
+
if (this.#track)
|
|
140
|
+
this.#resizeObserver.unobserve(this.#track);
|
|
117
141
|
this.#validityObservers.unobserveAll();
|
|
118
142
|
}
|
|
119
143
|
connectedCallback() {
|
|
120
144
|
super.connectedCallback();
|
|
121
|
-
// finally
|
|
122
|
-
// if (this.hasAttribute('value')) this.value = this.getAttribute('value') ?? ''
|
|
123
145
|
if (this.hasAttribute('is-on'))
|
|
124
146
|
this.isOn = this.hasAttribute('is-on');
|
|
125
147
|
this.#sendValueToForm(false);
|
|
126
|
-
this.#
|
|
148
|
+
if (this.#track)
|
|
149
|
+
this.#resizeObserver.observe(this.#track);
|
|
150
|
+
CleanupRegistry.register(this, onoff(touchGlass(this, (t) => t, ({ clientX, clientY }) => this.#measurePointerIsOverDot(clientX, clientY) ?? false), this).on());
|
|
127
151
|
}
|
|
128
152
|
get toggleStyle() {
|
|
129
153
|
return toggleStyles.includes(this.getAttribute('toggle-style') ?? '') ? this.getAttribute('toggle-style') : 'switch';
|
|
@@ -149,7 +173,116 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
149
173
|
if (devFlags.debug)
|
|
150
174
|
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
151
175
|
if (target === this)
|
|
152
|
-
this.#
|
|
176
|
+
this.#track?.focus();
|
|
177
|
+
};
|
|
178
|
+
#handleTrackClick = ({ type }) => {
|
|
179
|
+
if (devFlags.debug)
|
|
180
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
181
|
+
if (this.#didDrag)
|
|
182
|
+
return (this.#didDrag = false);
|
|
183
|
+
this.#applyIsOnWithFlip(!this.isOn);
|
|
184
|
+
this.#sendValueToForm(true);
|
|
185
|
+
};
|
|
186
|
+
#measurePointerIsOverDot = (clientX, clientY) => {
|
|
187
|
+
if (!this.#track)
|
|
188
|
+
return;
|
|
189
|
+
const { left, top, height } = this.#track.getBoundingClientRect();
|
|
190
|
+
const dotLeft = left + parseFloat(self.getComputedStyle(this.#track, '::before').left);
|
|
191
|
+
const dotCenterX = dotLeft + this.#dotSize / 2;
|
|
192
|
+
const dotCenterY = top + height / 2;
|
|
193
|
+
return Math.hypot(clientX - dotCenterX, clientY - dotCenterY) <= this.#dotSize / 2;
|
|
194
|
+
};
|
|
195
|
+
#dragOffsetX = 0;
|
|
196
|
+
get #baseX() {
|
|
197
|
+
return this.isOn ? this.#trackMaxX : this.#trackMinX;
|
|
198
|
+
}
|
|
199
|
+
#handleTrackPointerdown = ({ type, pointerId, clientX, clientY }) => {
|
|
200
|
+
if (devFlags.debug)
|
|
201
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
202
|
+
if (!this.#track)
|
|
203
|
+
return;
|
|
204
|
+
if (!this.#measurePointerIsOverDot(clientX, clientY))
|
|
205
|
+
return; // ignore taps elsewhere on the track
|
|
206
|
+
this.#didDrag = true; // dot was engaged — settle() will own the outcome, click must be swallowed
|
|
207
|
+
const currentDelta = parseFloat(self.getComputedStyle(this.#track).getPropertyValue('--toggle--dot-x')) || 0;
|
|
208
|
+
const currentAbsoluteX = this.#baseX + currentDelta;
|
|
209
|
+
this.#dragOffsetX = clientX - this.#track.getBoundingClientRect().left - currentAbsoluteX;
|
|
210
|
+
this.#track.style.setProperty('--toggle--dot-transition-duration', '0ms');
|
|
211
|
+
this.#track.setPointerCapture(pointerId);
|
|
212
|
+
// this.#updateFromEvent(clientX)
|
|
213
|
+
};
|
|
214
|
+
#handleTrackPointermove = ({ type, clientX }) => {
|
|
215
|
+
if (devFlags.debug)
|
|
216
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
217
|
+
if (!this.#isDragging)
|
|
218
|
+
return;
|
|
219
|
+
this.#updateFromEvent(clientX);
|
|
220
|
+
};
|
|
221
|
+
#handleTrackPointerup = ({ type, pointerId }) => {
|
|
222
|
+
if (devFlags.debug)
|
|
223
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
224
|
+
if (!this.#isDragging)
|
|
225
|
+
return; // pointerdown never engaged (missed the dot) — plain click, nothing to settle
|
|
226
|
+
this.#track?.style.removeProperty('--toggle--dot-transition-duration');
|
|
227
|
+
this.#track?.releasePointerCapture(pointerId);
|
|
228
|
+
this.#settle();
|
|
229
|
+
};
|
|
230
|
+
#handleTrackPointercancel = ({ type }) => {
|
|
231
|
+
if (devFlags.debug)
|
|
232
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
233
|
+
if (!this.#isDragging)
|
|
234
|
+
return; // already settled via pointerup, or nothing to settle
|
|
235
|
+
this.#track?.style.removeProperty('--toggle--dot-transition-duration');
|
|
236
|
+
this.#settle();
|
|
237
|
+
};
|
|
238
|
+
#handleWindowBlur = () => {
|
|
239
|
+
if (!this.#isDragging)
|
|
240
|
+
return;
|
|
241
|
+
this.#track?.style.removeProperty('--toggle--dot-transition-duration');
|
|
242
|
+
this.#settle();
|
|
243
|
+
};
|
|
244
|
+
#updateFromEvent = (clientX) => {
|
|
245
|
+
if (!this.#track)
|
|
246
|
+
return;
|
|
247
|
+
const { left } = this.#track.getBoundingClientRect();
|
|
248
|
+
const absoluteX = Math.min(Math.max(clientX - left - this.#dragOffsetX, this.#trackMinX), this.#trackMaxX);
|
|
249
|
+
this.#track.style.setProperty('--toggle--dot-x', `${Math.round(absoluteX - this.#baseX)}px`);
|
|
250
|
+
};
|
|
251
|
+
#settle = () => {
|
|
252
|
+
if (!this.#track)
|
|
253
|
+
return;
|
|
254
|
+
const deltaX = parseFloat(self.getComputedStyle(this.#track).getPropertyValue('--toggle--dot-x')) || 0;
|
|
255
|
+
const absoluteX = this.#baseX + deltaX;
|
|
256
|
+
const nextIsOn = absoluteX > this.#trackMaxX / 2;
|
|
257
|
+
if (nextIsOn === this.isOn)
|
|
258
|
+
return this.#track.style.removeProperty('--toggle--dot-x'); // pure transform animation back to rest, inset untouched
|
|
259
|
+
this.#applyIsOnWithFlip(nextIsOn);
|
|
260
|
+
this.#sendValueToForm(true);
|
|
261
|
+
};
|
|
262
|
+
#handleTrackKeydown = (evt) => {
|
|
263
|
+
if (devFlags.debug)
|
|
264
|
+
console.debug(`${_a.name} ⚡️ ${evt?.type}`);
|
|
265
|
+
if (' ' !== evt.key)
|
|
266
|
+
return;
|
|
267
|
+
evt.preventDefault();
|
|
268
|
+
this.#applyIsOnWithFlip(!this.isOn);
|
|
269
|
+
this.#sendValueToForm(true);
|
|
270
|
+
};
|
|
271
|
+
#applyIsOnWithFlip = (nextIsOn) => {
|
|
272
|
+
if (!this.#track || nextIsOn === this.isOn)
|
|
273
|
+
return;
|
|
274
|
+
// capture current visual position under the OLD base, before flipping state
|
|
275
|
+
const deltaX = parseFloat(self.getComputedStyle(this.#track).getPropertyValue('--toggle--dot-x')) || 0, oldAbsoluteX = this.#baseX + deltaX;
|
|
276
|
+
this.isOn = nextIsOn; // changes --toggle--dot-inset-inline-start/-end via aria-checked
|
|
277
|
+
const compensationX = oldAbsoluteX - this.#baseX; // baseX now reflects the NEW state
|
|
278
|
+
// make inset + transform jump together, instantly, so nothing is visibly out of sync
|
|
279
|
+
this.#track.style.setProperty('--toggle--dot-transition-duration', '0ms');
|
|
280
|
+
this.#track.style.setProperty('--toggle--dot-x', `${Math.round(compensationX)}px`);
|
|
281
|
+
void this.#track.offsetWidth; // force reflow so the instant jump is committed before re-enabling transitions
|
|
282
|
+
this.#track.style.removeProperty('--toggle--dot-transition-duration');
|
|
283
|
+
self.requestAnimationFrame(() => {
|
|
284
|
+
this.#track?.style.removeProperty('--toggle--dot-x'); // only transform animates from here — single source of motion
|
|
285
|
+
});
|
|
153
286
|
};
|
|
154
287
|
#sendValueToForm = (dispatchEvent = true) => {
|
|
155
288
|
// input.value has already been updated/synced !!
|
|
@@ -158,9 +291,8 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
158
291
|
if (this.hasAttribute('required') && !this.isOn) {
|
|
159
292
|
this.setValidity({ valueMissing: true });
|
|
160
293
|
}
|
|
161
|
-
else
|
|
294
|
+
else
|
|
162
295
|
this.setValidity({});
|
|
163
|
-
}
|
|
164
296
|
const entries = new FormData();
|
|
165
297
|
if (this.value)
|
|
166
298
|
entries.append(this.name, this.value);
|
|
@@ -168,17 +300,6 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
168
300
|
if (dispatchEvent)
|
|
169
301
|
this.dispatchEvent(new CustomEvent('toggle:change', { detail: { value: this.value, isOn: this.isOn }, bubbles: true, composed: true }));
|
|
170
302
|
};
|
|
171
|
-
#handleInputKeydown = (evt) => {
|
|
172
|
-
if (devFlags.debug)
|
|
173
|
-
console.debug(`${_a.name} ⚡️ ${evt?.type}`);
|
|
174
|
-
this.isOn = !this.isOn;
|
|
175
|
-
this.#sendValueToForm();
|
|
176
|
-
};
|
|
177
|
-
#handleInputInput = (evt) => {
|
|
178
|
-
if (devFlags.debug)
|
|
179
|
-
console.debug(`${_a.name} ⚡️ ${evt?.type}`);
|
|
180
|
-
this.#sendValueToForm();
|
|
181
|
-
};
|
|
182
303
|
/**
|
|
183
304
|
* Form participation property
|
|
184
305
|
*/
|
|
@@ -222,7 +343,7 @@ export class ToggleView extends FormAssociatedBase {
|
|
|
222
343
|
}
|
|
223
344
|
if (devFlags.debug)
|
|
224
345
|
console.debug(`${_a.name} ⚡️ validity-change`);
|
|
225
|
-
return this.#internals.setValidity(flags, this.#customValidity || message, anchor ?? this.#
|
|
346
|
+
return this.#internals.setValidity(flags, this.#customValidity || message, anchor ?? this.#track);
|
|
226
347
|
};
|
|
227
348
|
setCustomValidity = (message) => {
|
|
228
349
|
this.#customValidity = message;
|
package/generated/css/index.css
CHANGED
|
@@ -1138,6 +1138,7 @@
|
|
|
1138
1138
|
display: grid;
|
|
1139
1139
|
}
|
|
1140
1140
|
:where(labeled-content)::part(labeled-content-container),
|
|
1141
|
+
:where(labeled-content)::part(labeled-content-container),
|
|
1141
1142
|
:where(labeled-content)::part(labeled-content-label-stack),
|
|
1142
1143
|
:where(labeled-content)::part(labeled-content-value-stack),
|
|
1143
1144
|
:where(progress-view)::part(progress-control),
|
|
@@ -3440,7 +3441,15 @@
|
|
|
3440
3441
|
:where(toggle-view) {
|
|
3441
3442
|
grid-template-columns: minmax(0, 1fr);
|
|
3442
3443
|
grid-template-rows: minmax(0, 1fr);
|
|
3443
|
-
--toggle--
|
|
3444
|
+
--toggle--track-padding: 0.2rem;
|
|
3445
|
+
--toggle--track-bg: lightgray;
|
|
3446
|
+
--toggle--dot-size: 1.4rem;
|
|
3447
|
+
--toggle--dot-inset-inline-start: 0;
|
|
3448
|
+
--toggle--dot-inset-inline-end: 100%;
|
|
3449
|
+
--toggle--dot-x: 0px;
|
|
3450
|
+
--toggle--dot-transition-duration: 200ms;
|
|
3451
|
+
--toggle--dot-scale: scale(1);
|
|
3452
|
+
--toogle--track-brightness: brightness(1);
|
|
3444
3453
|
}
|
|
3445
3454
|
:where(toggle-view)::part(toggle-stack) {
|
|
3446
3455
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
@@ -3451,36 +3460,51 @@
|
|
|
3451
3460
|
align-items: center;
|
|
3452
3461
|
justify-items: end;
|
|
3453
3462
|
place-content: stretch;
|
|
3463
|
+
align-self: flex-start;
|
|
3464
|
+
cursor: pointer;
|
|
3465
|
+
padding-inline: var(--toggle--track-padding);
|
|
3466
|
+
padding-block: var(--toggle--track-padding);
|
|
3467
|
+
border-radius: var(--pill-border-radius);
|
|
3468
|
+
background: var(--toggle--track-bg);
|
|
3469
|
+
transition: background-color var(--toggle--dot-transition-duration) ease-out;
|
|
3454
3470
|
}
|
|
3455
|
-
:where(toggle-view)::part(toggle-
|
|
3456
|
-
|
|
3457
|
-
}
|
|
3458
|
-
:where(toggle-view)::part(toggle-form-input) {
|
|
3471
|
+
:where(toggle-view)::part(toggle-track) {
|
|
3472
|
+
container: toggle-track/size;
|
|
3459
3473
|
text-align: end;
|
|
3460
3474
|
position: relative;
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
border-radius: 2rem;
|
|
3475
|
+
outline: none;
|
|
3476
|
+
border-radius: var(--pill-border-radius);
|
|
3464
3477
|
inline-size: 4rem;
|
|
3465
|
-
block-size:
|
|
3466
|
-
|
|
3478
|
+
block-size: var(--toggle--dot-size);
|
|
3479
|
+
filter: var(--toogle--track-brightness, );
|
|
3480
|
+
transition: background-color var(--toggle--dot-transition-duration) ease-out;
|
|
3481
|
+
touch-action: none;
|
|
3482
|
+
}
|
|
3483
|
+
:where(toggle-view)::part(toggle-track):focus {
|
|
3484
|
+
--toogle--track-brightness: brightness(0.9);
|
|
3467
3485
|
}
|
|
3468
|
-
:where(toggle-view)::part(toggle-
|
|
3486
|
+
:where(toggle-view)::part(toggle-track)::before {
|
|
3469
3487
|
content: "";
|
|
3470
3488
|
display: grid;
|
|
3471
3489
|
position: absolute;
|
|
3472
|
-
inset: 0
|
|
3473
|
-
inline-size:
|
|
3474
|
-
block-size:
|
|
3475
|
-
border-radius:
|
|
3490
|
+
inset: 0 var(--toggle--dot-inset-inline-end) auto var(--toggle--dot-inset-inline-start);
|
|
3491
|
+
inline-size: var(--toggle--dot-size);
|
|
3492
|
+
block-size: var(--toggle--dot-size);
|
|
3493
|
+
border-radius: var(--pill-border-radius);
|
|
3476
3494
|
backdrop-filter: var(--liquid-glass-backdrop-filter);
|
|
3477
3495
|
box-shadow: var(--liquid-glass-box-shadow);
|
|
3496
|
+
transition: inset-inline-start var(--toggle--dot-transition-duration) ease-out, inset-inline-end var(--toggle--dot-transition-duration) ease-out, transform var(--toggle--dot-transition-duration) ease-out, scale var(--toggle--dot-press-duration) ease-out;
|
|
3497
|
+
transform: translateX(var(--toggle--dot-x));
|
|
3498
|
+
scale: var(--toggle--dot-scale, );
|
|
3499
|
+
transform-origin: center;
|
|
3478
3500
|
}
|
|
3479
3501
|
:where(form toggle-view)::part(toggle-label-stack) {
|
|
3480
3502
|
color: var(--secondary);
|
|
3481
3503
|
}
|
|
3482
3504
|
:where(toggle-view[aria-checked=true]) {
|
|
3483
|
-
--toggle--
|
|
3505
|
+
--toggle--track-bg: green;
|
|
3506
|
+
--toggle--dot-inset-inline-start: calc(100% - var(--toggle--dot-size));
|
|
3507
|
+
--toggle--dot-inset-inline-end: 0;
|
|
3484
3508
|
}
|
|
3485
3509
|
:where(toggle-view > :nth-child(n+2 of [slot=label])) {
|
|
3486
3510
|
--label-font: callout;
|
|
@@ -10528,6 +10552,10 @@
|
|
|
10528
10552
|
} */
|
|
10529
10553
|
}
|
|
10530
10554
|
@layer sw-final {
|
|
10555
|
+
:where(toggle-view[touch-glass]) {
|
|
10556
|
+
--toggle--dot-scale: 1.22;
|
|
10557
|
+
--toggle--dot-press-duration: 100ms;
|
|
10558
|
+
}
|
|
10531
10559
|
@media (pointer: coarse) {
|
|
10532
10560
|
:where([is=glass-button][touch-glass],
|
|
10533
10561
|
[is=glass-prominent-button][touch-glass]) {
|
package/package.json
CHANGED
|
@@ -9,7 +9,19 @@
|
|
|
9
9
|
|
|
10
10
|
grid-template-rows: minmax(0, 1fr);
|
|
11
11
|
|
|
12
|
-
--toggle--
|
|
12
|
+
--toggle--track-padding: 0.2rem;
|
|
13
|
+
--toggle--track-bg: lightgray;
|
|
14
|
+
|
|
15
|
+
--toggle--dot-size: 1.4rem;
|
|
16
|
+
|
|
17
|
+
--toggle--dot-inset-inline-start: 0;
|
|
18
|
+
--toggle--dot-inset-inline-end: 100%;
|
|
19
|
+
|
|
20
|
+
--toggle--dot-x: 0px;
|
|
21
|
+
--toggle--dot-transition-duration: 200ms;
|
|
22
|
+
--toggle--dot-scale: scale(1);
|
|
23
|
+
|
|
24
|
+
--toogle--track-brightness: brightness(1);
|
|
13
25
|
|
|
14
26
|
&::part(toggle-stack) {
|
|
15
27
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
@@ -30,50 +42,73 @@
|
|
|
30
42
|
justify-items: end;
|
|
31
43
|
|
|
32
44
|
place-content: stretch;
|
|
33
|
-
|
|
45
|
+
align-self: flex-start;
|
|
46
|
+
|
|
47
|
+
cursor: pointer;
|
|
34
48
|
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
padding-inline: var(--toggle--track-padding);
|
|
50
|
+
padding-block: var(--toggle--track-padding);
|
|
51
|
+
border-radius: var(--pill-border-radius);
|
|
52
|
+
background: var(--toggle--track-bg);
|
|
53
|
+
|
|
54
|
+
transition: background-color var(--toggle--dot-transition-duration) ease-out;
|
|
37
55
|
}
|
|
38
56
|
|
|
39
|
-
&::part(toggle-
|
|
57
|
+
&::part(toggle-track) {
|
|
58
|
+
container: toggle-track / size;
|
|
59
|
+
|
|
40
60
|
text-align: end;
|
|
41
61
|
|
|
42
62
|
position: relative;
|
|
43
63
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
64
|
+
outline: none;
|
|
65
|
+
|
|
66
|
+
// display: grid;
|
|
67
|
+
// outline: red solid 3px;
|
|
68
|
+
border-radius: var(--pill-border-radius);
|
|
47
69
|
inline-size: 4rem;
|
|
48
|
-
block-size:
|
|
49
|
-
background: var(--toggle--
|
|
70
|
+
block-size: var(--toggle--dot-size);
|
|
71
|
+
// background: var(--toggle--track-bg);
|
|
50
72
|
|
|
51
|
-
|
|
73
|
+
filter: var(--toogle--track-brightness,);
|
|
52
74
|
|
|
53
|
-
|
|
75
|
+
transition: background-color var(--toggle--dot-transition-duration) ease-out;
|
|
54
76
|
|
|
55
|
-
//
|
|
77
|
+
touch-action: none; // prevent scrolling while dragging
|
|
56
78
|
|
|
57
|
-
|
|
79
|
+
&:focus {
|
|
80
|
+
// outline: blue solid 5px;
|
|
81
|
+
// --toggle--track-bg: gray;
|
|
58
82
|
|
|
59
|
-
|
|
60
|
-
|
|
83
|
+
--toogle--track-brightness: brightness(0.9);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&::before {
|
|
87
|
+
content: '';
|
|
61
88
|
|
|
62
|
-
|
|
63
|
-
content: '';
|
|
89
|
+
display: grid;
|
|
64
90
|
|
|
65
|
-
|
|
91
|
+
position: absolute;
|
|
92
|
+
inset: 0 var(--toggle--dot-inset-inline-end) auto var(--toggle--dot-inset-inline-start);
|
|
93
|
+
inline-size: var(--toggle--dot-size);
|
|
94
|
+
block-size: var(--toggle--dot-size);
|
|
95
|
+
border-radius: var(--pill-border-radius);
|
|
66
96
|
|
|
67
|
-
|
|
68
|
-
inset: 0 auto auto 0;
|
|
69
|
-
inline-size: 1rem;
|
|
70
|
-
block-size: 1rem;
|
|
71
|
-
border-radius: 1rem;
|
|
72
|
-
// background: yellow;
|
|
97
|
+
backdrop-filter: var(--liquid-glass-backdrop-filter);
|
|
73
98
|
|
|
74
|
-
|
|
99
|
+
box-shadow: var(--liquid-glass-box-shadow);
|
|
75
100
|
|
|
76
|
-
|
|
101
|
+
transition:
|
|
102
|
+
inset-inline-start var(--toggle--dot-transition-duration) ease-out,
|
|
103
|
+
inset-inline-end var(--toggle--dot-transition-duration) ease-out,
|
|
104
|
+
transform var(--toggle--dot-transition-duration) ease-out,
|
|
105
|
+
scale var(--toggle--dot-press-duration) ease-out;
|
|
106
|
+
|
|
107
|
+
transform: translateX(var(--toggle--dot-x));
|
|
108
|
+
scale: var(--toggle--dot-scale,);
|
|
109
|
+
|
|
110
|
+
transform-origin: center;
|
|
111
|
+
}
|
|
77
112
|
}
|
|
78
113
|
}
|
|
79
114
|
|
|
@@ -85,7 +120,10 @@
|
|
|
85
120
|
|
|
86
121
|
&[aria-checked='true'] {
|
|
87
122
|
:where(&) {
|
|
88
|
-
--toggle--
|
|
123
|
+
--toggle--track-bg: green;
|
|
124
|
+
|
|
125
|
+
--toggle--dot-inset-inline-start: calc(100% - var(--toggle--dot-size));
|
|
126
|
+
--toggle--dot-inset-inline-end: 0;
|
|
89
127
|
}
|
|
90
128
|
}
|
|
91
129
|
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
@use '../mixins';
|
|
3
3
|
|
|
4
4
|
@layer #{vars.$final-layer} {
|
|
5
|
+
toggle-view {
|
|
6
|
+
:where(&[touch-glass]) {
|
|
7
|
+
--toggle--dot-scale: 1.22;
|
|
8
|
+
--toggle--dot-press-duration: 100ms;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
5
12
|
@media (pointer: coarse) {
|
|
6
13
|
[is='glass-button'],
|
|
7
14
|
[is='glass-prominent-button'] {
|
|
@@ -882,9 +882,6 @@
|
|
|
882
882
|
"name": "is-on",
|
|
883
883
|
"description": "Value Type: boolean"
|
|
884
884
|
},
|
|
885
|
-
{
|
|
886
|
-
"name": "keyboard-type"
|
|
887
|
-
},
|
|
888
885
|
{
|
|
889
886
|
"name": "required",
|
|
890
887
|
"description": "Value Type: boolean"
|
|
@@ -900,7 +897,7 @@
|
|
|
900
897
|
"description": "Value Type: boolean"
|
|
901
898
|
}
|
|
902
899
|
],
|
|
903
|
-
"description": "A control that switches between on and off states.\n---\n\n```ts\ninterface ToggleViewSignature {\n Attributes: {\n label?: string\n name?: string\n value?: string\n 'is-on'?: boolean\n
|
|
900
|
+
"description": "A control that switches between on and off states.\n---\n\n```ts\ninterface ToggleViewSignature {\n Attributes: {\n label?: string\n name?: string\n value?: string\n 'is-on'?: boolean\n required?: boolean\n disabled?: boolean\n }\n\n Slots: {\n label: HTMLElement[]\n 'validity-options': HTMLOptionElement[]\n }\n}\n\nclass ToggleView extends HTMLElement<ToggleViewSignature> {\n static formAssociated = true\n\n readonly toggleStyle: 'button' | 'switch'\n isOn: boolean\n readonly name: string // Form participation property\n value: string | null\n\n setValidity(): void\n setCustomValidity(): void\n}\n\ninterface GlobalEventMap<\n Targets = HTMLElementEventMap | DocumentEventMap | WindowEventMap,\n> {\n 'toggle:change': CustomEvent // User toggled the control\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'toggle-view': ToggleView // <toggle-view></toggle-view>\n }\n}\n\n```\n"
|
|
904
901
|
},
|
|
905
902
|
{
|
|
906
903
|
"name": "tool-bar-item-group",
|