use-scroll-animate 2.4.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +2 -0
  3. package/README_ja.md +2 -0
  4. package/README_zh.md +2 -0
  5. package/dist/chunks/{base-CuvCgqLy.js → base-08OYzphB.js} +2 -2
  6. package/dist/chunks/{base-CuvCgqLy.js.map → base-08OYzphB.js.map} +1 -1
  7. package/dist/chunks/{base-CJ7XfidP.cjs → base-5DFCAnvH.cjs} +3 -1
  8. package/dist/chunks/{base-CJ7XfidP.cjs.map → base-5DFCAnvH.cjs.map} +1 -1
  9. package/dist/chunks/{spring-CGO9Jd9b.cjs → spring-Bi4qY0pL.cjs} +2 -2
  10. package/dist/chunks/{spring-CGO9Jd9b.cjs.map → spring-Bi4qY0pL.cjs.map} +1 -1
  11. package/dist/chunks/{spring-BKUU7-Xm.js → spring-CpeFkxNd.js} +2 -2
  12. package/dist/chunks/{spring-BKUU7-Xm.js.map → spring-CpeFkxNd.js.map} +1 -1
  13. package/dist/components/background.cjs +1 -1
  14. package/dist/components/background.js +2 -2
  15. package/dist/components/cards.cjs +2 -2
  16. package/dist/components/cards.js +3 -3
  17. package/dist/components/click.cjs +985 -0
  18. package/dist/components/click.cjs.map +1 -0
  19. package/dist/components/click.css +9 -0
  20. package/dist/components/click.d.cts +250 -0
  21. package/dist/components/click.d.ts +250 -0
  22. package/dist/components/click.js +967 -0
  23. package/dist/components/click.js.map +1 -0
  24. package/dist/components/feedback.cjs +2 -2
  25. package/dist/components/feedback.css +1 -1
  26. package/dist/components/feedback.js +3 -3
  27. package/dist/components/interaction.cjs +2 -2
  28. package/dist/components/interaction.css +1 -1
  29. package/dist/components/interaction.js +3 -3
  30. package/dist/components/physics.cjs +2 -2
  31. package/dist/components/physics.js +4 -4
  32. package/dist/components/reveal.cjs +1 -1
  33. package/dist/components/reveal.js +2 -2
  34. package/dist/components/text.cjs +1 -1
  35. package/dist/components/text.js +2 -2
  36. package/dist/components/transitions.cjs +1 -1
  37. package/dist/components/transitions.js +2 -2
  38. package/dist/components/ui.cjs +1082 -0
  39. package/dist/components/ui.cjs.map +1 -0
  40. package/dist/components/ui.css +14 -0
  41. package/dist/components/ui.d.cts +251 -0
  42. package/dist/components/ui.d.ts +251 -0
  43. package/dist/components/ui.js +1064 -0
  44. package/dist/components/ui.js.map +1 -0
  45. package/dist/components.cjs +44 -4
  46. package/dist/components.cjs.map +1 -1
  47. package/dist/components.css +21 -2
  48. package/dist/components.d.cts +427 -2
  49. package/dist/components.d.ts +427 -2
  50. package/dist/components.js +14 -3
  51. package/dist/components.js.map +1 -1
  52. package/dist/components.umd.js +2 -2
  53. package/dist/components.umd.js.map +1 -1
  54. package/docs/components.md +33 -0
  55. package/package.json +24 -2
@@ -0,0 +1,985 @@
1
+ 'use strict';
2
+
3
+ var base = require('../chunks/base-5DFCAnvH.cjs');
4
+ var spring = require('../chunks/spring-Bi4qY0pL.cjs');
5
+
6
+ /**
7
+ * Click-effect helpers (v2.5): `burst()`, `confetti()`, `shake()`, `haptic()`.
8
+ * Particles live in one fixed, pointer-transparent layer and are removed when
9
+ * their animation ends. Under reduced motion particles are skipped and
10
+ * `shake()` only flashes an outline.
11
+ */
12
+ let layer = null;
13
+ function fxLayer() {
14
+ if (layer && layer.isConnected)
15
+ return layer;
16
+ layer = document.createElement('div');
17
+ layer.className = 'usa-fx-layer';
18
+ layer.setAttribute('aria-hidden', 'true');
19
+ layer.style.cssText = 'position:fixed;inset:0;pointer-events:none;z-index:2147483000;overflow:hidden;contain:strict';
20
+ document.body.appendChild(layer);
21
+ return layer;
22
+ }
23
+ const PALETTE = ['#7c5cff', '#22d3ee', '#f472b6', '#facc15', '#34d399', '#fb923c'];
24
+ const GLYPH = { star: '★', heart: '♥' };
25
+ function particle(x, y, size, color, shape) {
26
+ const p = document.createElement('span');
27
+ const glyph = GLYPH[shape] || (shape !== 'circle' && shape !== 'square' ? shape : '');
28
+ p.style.cssText = `position:absolute;left:${x}px;top:${y}px;width:${size}px;height:${size}px;margin:${-size / 2}px 0 0 ${-size / 2}px;will-change:transform,opacity;` +
29
+ (glyph ? `font-size:${size * 2}px;line-height:${size}px;text-align:center;color:${color}` : `background:${color};border-radius:${shape === 'square' ? '2px' : '50%'}`);
30
+ if (glyph)
31
+ p.textContent = glyph;
32
+ fxLayer().appendChild(p);
33
+ return p;
34
+ }
35
+ const done = (a, el) => {
36
+ if (a)
37
+ a.onfinish = () => el.remove();
38
+ else
39
+ el.remove();
40
+ };
41
+ /** Particles radiating from client point (x, y). Returns the number spawned. */
42
+ function burst(x, y, options = {}) {
43
+ if (typeof document === 'undefined' || base.prefersReducedMotion())
44
+ return 0;
45
+ const { count = 12, colors = PALETTE, distance = 48, size = 6, shape = 'circle', duration = 600 } = options;
46
+ for (let i = 0; i < count; i++) {
47
+ const angle = (i / count) * Math.PI * 2 + Math.random() * 0.4;
48
+ const d = distance * (0.7 + Math.random() * 0.5);
49
+ const p = particle(x, y, size, colors[i % colors.length], shape);
50
+ const a = typeof p.animate === 'function'
51
+ ? p.animate([
52
+ { transform: 'translate(0,0) scale(1)', opacity: 1 },
53
+ { transform: `translate(${Math.cos(angle) * d}px, ${Math.sin(angle) * d}px) scale(0.2)`, opacity: 0 },
54
+ ], { duration: duration * (0.8 + Math.random() * 0.4), easing: 'cubic-bezier(0.22, 1, 0.36, 1)', fill: 'forwards' })
55
+ : null;
56
+ done(a, p);
57
+ }
58
+ return count;
59
+ }
60
+ /** A confetti cannon (paper pieces with gravity, drift and spin). */
61
+ function confetti(options = {}) {
62
+ if (typeof document === 'undefined' || base.prefersReducedMotion())
63
+ return 0;
64
+ const W = window.innerWidth || 800;
65
+ const H = window.innerHeight || 600;
66
+ const { x = W / 2, y = H * 0.66, count = 80, spread = 70, velocity = 1, colors = PALETTE, duration = 1600 } = options;
67
+ for (let i = 0; i < count; i++) {
68
+ const angle = ((-90 + (Math.random() - 0.5) * spread) * Math.PI) / 180;
69
+ const speed = (260 + Math.random() * 320) * velocity;
70
+ const vx = Math.cos(angle) * speed;
71
+ const vy = Math.sin(angle) * speed;
72
+ const p = particle(x, y, 6 + Math.random() * 5, colors[i % colors.length], Math.random() > 0.5 ? 'square' : 'circle');
73
+ p.style.height = `${4 + Math.random() * 3}px`;
74
+ const frames = [];
75
+ const steps = 8;
76
+ const T = duration / 1000;
77
+ const spin = (Math.random() - 0.5) * 1440;
78
+ for (let s = 0; s <= steps; s++) {
79
+ const t = (s / steps) * T;
80
+ const g = 900;
81
+ frames.push({
82
+ transform: `translate(${(vx * t * 0.8).toFixed(1)}px, ${(vy * t + 0.5 * g * t * t).toFixed(1)}px) rotate(${((spin * s) / steps).toFixed(0)}deg) rotateX(${s * 120}deg)`,
83
+ opacity: s === steps ? 0 : 1,
84
+ });
85
+ }
86
+ const a = typeof p.animate === 'function' ? p.animate(frames, { duration: duration * (0.85 + Math.random() * 0.3), easing: 'linear', fill: 'forwards' }) : null;
87
+ done(a, p);
88
+ }
89
+ return count;
90
+ }
91
+ /** Horizontal error shake (`intensity` px, default 8). Reduced motion: a red outline flash. */
92
+ function shake(el, intensity = 8, duration = 480) {
93
+ const t = el;
94
+ if (typeof t.animate !== 'function')
95
+ return null;
96
+ if (base.prefersReducedMotion())
97
+ return t.animate([{ outline: '2px solid #e5484d' }, { outline: '2px solid transparent' }], { duration: 600 });
98
+ const k = intensity;
99
+ return t.animate([0, -k, k, -k * 0.75, k * 0.75, -k * 0.4, k * 0.4, 0].map((v) => ({ transform: `translateX(${v}px)` })), { duration, easing: 'ease-in-out' });
100
+ }
101
+ /** `navigator.vibrate()` where supported (Android Chrome, some WebViews). Returns whether it ran. */
102
+ function haptic(pattern = 10) {
103
+ try {
104
+ return typeof navigator !== 'undefined' && typeof navigator.vibrate === 'function' ? navigator.vibrate(pattern) : false;
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
110
+
111
+ var css$6 = "usa-click{position:relative;display:inline-block;overflow:hidden;isolation:isolate;border-radius:inherit;-webkit-tap-highlight-color:transparent;touch-action:manipulation}usa-click[block]{display:block}usa-click .usa-click-wave{position:absolute;border-radius:50%;pointer-events:none;z-index:-1;transform:scale(0);background:radial-gradient(circle,var(--usa-wave) 0 55%,color-mix(in srgb,var(--usa-wave) 40%,transparent) 70%,transparent 72%)}";
112
+
113
+ const CLICK_EFFECTS = ['ripple', 'burst', 'confetti', 'squish', 'press-spring', 'shake'];
114
+ function defineClick(tag = 'usa-click') {
115
+ return base.defineElement(tag, (Base) => class UsaClick extends Base {
116
+ constructor() {
117
+ super(...arguments);
118
+ this._press = null;
119
+ }
120
+ static get observedAttributes() {
121
+ return ['effect', 'disabled'];
122
+ }
123
+ get effects() {
124
+ return this.str('effect', 'ripple').split(/[\s,]+/).filter(Boolean);
125
+ }
126
+ mount() {
127
+ this.listen(this, 'pointerdown', (e) => {
128
+ if (this.flag('disabled') || (e.pointerType === 'mouse' && e.button !== 0))
129
+ return;
130
+ this.down();
131
+ if (this.effects.includes('ripple'))
132
+ this.ripple(e.clientX, e.clientY);
133
+ });
134
+ const up = () => this.up();
135
+ this.listen(this, 'pointerup', up);
136
+ this.listen(this, 'pointerleave', up);
137
+ this.listen(this, 'pointercancel', up);
138
+ this.listen(this, 'click', (e) => {
139
+ if (this.flag('disabled'))
140
+ return;
141
+ const kb = e.detail === 0;
142
+ const r = this.getBoundingClientRect();
143
+ const x = kb ? r.left + r.width / 2 : e.clientX;
144
+ const y = kb ? r.top + r.height / 2 : e.clientY;
145
+ if (kb && this.effects.includes('ripple'))
146
+ this.ripple(x, y);
147
+ this.play(x, y);
148
+ if (this.effects.includes('shake') && this.str('trigger') === 'click')
149
+ this.shake();
150
+ });
151
+ this.listen(this, 'keydown', (e) => {
152
+ if ((e.key === 'Enter' || e.key === ' ') && !e.repeat)
153
+ this.down();
154
+ });
155
+ this.listen(this, 'keyup', up);
156
+ if (this.effects.includes('shake'))
157
+ this.listen(this, 'invalid', () => this.shake(), { capture: true });
158
+ }
159
+ /** Particles + haptics at client (x, y) (default: centre). */
160
+ play(x, y) {
161
+ if (x === undefined || y === undefined) {
162
+ const r = this.getBoundingClientRect();
163
+ x = r.left + r.width / 2;
164
+ y = r.top + r.height / 2;
165
+ }
166
+ const fx = this.effects;
167
+ const colors = this.str('color') ? this.str('color').split(',') : undefined;
168
+ if (fx.includes('burst'))
169
+ burst(x, y, { count: this.num('count', 12), shape: this.str('shape', 'circle'), colors });
170
+ if (fx.includes('confetti'))
171
+ confetti({ x, y, count: this.num('count', 60), colors, spread: 90, velocity: 0.8 });
172
+ if (this.hasAttribute('haptic'))
173
+ haptic(this.num('haptic', 10));
174
+ this.emit('click-effect', { x, y, effects: fx });
175
+ }
176
+ shake() {
177
+ shake(this);
178
+ if (this.hasAttribute('haptic'))
179
+ haptic([30, 40, 30]);
180
+ }
181
+ ripple(x, y) {
182
+ if (this.reduced)
183
+ return;
184
+ const r = this.getBoundingClientRect();
185
+ const cx = x - r.left;
186
+ const cy = y - r.top;
187
+ const radius = Math.hypot(Math.max(cx, r.width - cx), Math.max(cy, r.height - cy));
188
+ const wave = document.createElement('span');
189
+ wave.className = 'usa-click-wave';
190
+ wave.setAttribute('aria-hidden', 'true');
191
+ wave.style.cssText = `width:${radius * 2}px;height:${radius * 2}px;left:${cx - radius}px;top:${cy - radius}px;--usa-wave:${this.str('color', 'currentColor').split(',')[0]}`;
192
+ this.append(wave);
193
+ const a = this.motion(wave, [{ transform: 'scale(0)', opacity: 0.35 }, { transform: 'scale(1)', opacity: 0.25, offset: 0.6 }, { transform: 'scale(1.05)', opacity: 0 }], {
194
+ duration: 650,
195
+ easing: base.EASE_OUT,
196
+ fill: 'forwards',
197
+ });
198
+ if (a)
199
+ a.onfinish = () => wave.remove();
200
+ else
201
+ wave.remove();
202
+ }
203
+ down() {
204
+ if (this.hasAttribute('data-pressed'))
205
+ return;
206
+ const fx = this.effects;
207
+ if (!fx.includes('squish') && !fx.includes('press-spring'))
208
+ return;
209
+ this.setAttribute('data-pressed', '');
210
+ this._press?.cancel();
211
+ const to = this.reduced ? { opacity: 0.75 } : fx.includes('squish') ? { transform: 'scale(1.08, 0.86)' } : { transform: 'scale(0.94)' };
212
+ const from = this.reduced ? { opacity: 1 } : { transform: 'none' };
213
+ this._press = this.motion(this, [from, to], {
214
+ duration: 110,
215
+ easing: 'ease-out',
216
+ fill: 'forwards',
217
+ });
218
+ }
219
+ up() {
220
+ if (!this.hasAttribute('data-pressed'))
221
+ return;
222
+ this.removeAttribute('data-pressed');
223
+ const fx = this.effects;
224
+ this._press?.cancel();
225
+ if (this.reduced) {
226
+ this._press = this.motion(this, [{ opacity: 0.75 }, { opacity: 1 }], { duration: 150 });
227
+ return;
228
+ }
229
+ const from = fx.includes('squish') ? 'scale(1.08, 0.86)' : 'scale(0.94)';
230
+ const frames = fx.includes('squish')
231
+ ? [{ transform: from }, { transform: 'scale(0.92, 1.1)', offset: 0.3 }, { transform: 'scale(1.03, 0.97)', offset: 0.6 }, { transform: 'none' }]
232
+ : [{ transform: from }, { transform: 'none' }];
233
+ this._press = this.motion(this, frames, fx.includes('squish') ? { duration: 520, easing: 'ease-out' } : spring.springEasing('bouncy'));
234
+ }
235
+ }, { id: 'click', text: css$6 });
236
+ }
237
+
238
+ var css$5 = "usa-button{position:relative;display:inline-block;isolation:isolate;-webkit-tap-highlight-color:transparent;touch-action:manipulation;vertical-align:middle}usa-button[role=\"button\"]{cursor:pointer}usa-button .usa-button-face{position:relative;overflow:hidden;will-change:transform;transform-origin:50% 60%;white-space:nowrap}usa-button[deform~=\"gooey\"] .usa-button-face{overflow:visible}usa-button[deform~=\"dent\"] .usa-button-face::after{content:\"\";position:absolute;inset:0;border-radius:inherit;pointer-events:none;opacity:0;transition:opacity 0.2s ease;background:radial-gradient(circle at var(--usa-dent-x,50%) var(--usa-dent-y,50%),rgb(0 0 0 / 0.28),transparent 60%)}usa-button[deform~=\"dent\"][data-pressed] .usa-button-face::after{opacity:1}usa-button .usa-button-goo{position:absolute;inset:0;z-index:-1;pointer-events:none;filter:url(#usa-goo)}usa-button .usa-button-goo i{position:absolute;width:22px;height:22px;border-radius:50%;background:var(--usa-goo-bg);transform:translate(-50%,-50%) scale(0.4)}usa-button .usa-button-face[data-shape=\"circle\"],usa-button .usa-button-face[data-shape=\"icon\"]{padding-inline:0;aspect-ratio:1;border-radius:999px;display:inline-grid;place-items:center}usa-button .usa-button-face [data-label],usa-button .usa-button-face [data-icon]{transition:opacity 0.2s ease}usa-button .usa-button-face[data-shape=\"circle\"] [data-label],usa-button .usa-button-face[data-shape=\"icon\"] [data-label]{position:absolute;opacity:0;pointer-events:none}usa-button .usa-button-face[data-shape=\"circle\"] [data-icon]{opacity:0}usa-button .usa-button-status{position:absolute;inset:0;display:grid;place-items:center;pointer-events:none}usa-button .usa-button-status svg{grid-area:1 / 1;width:1.25em;height:1.25em;fill:none;stroke:currentColor;stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round;opacity:0}usa-button .usa-button-spin circle{stroke-dasharray:60 100;transform-origin:50% 50%;animation:usa-btn-spin 0.8s linear infinite}usa-button .usa-button-ok path,usa-button .usa-button-err path{stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset 0.35s ease 0.1s}usa-button .usa-button-face[data-state=\"loading\"] .usa-button-spin,usa-button .usa-button-face[data-state=\"success\"] .usa-button-ok,usa-button .usa-button-face[data-state=\"error\"] .usa-button-err{opacity:1}usa-button .usa-button-face[data-state=\"success\"] .usa-button-ok path,usa-button .usa-button-face[data-state=\"error\"] .usa-button-err path{stroke-dashoffset:0}usa-button .usa-button-face:is([data-state=\"loading\"],[data-state=\"success\"],[data-state=\"error\"])>:not(.usa-button-status){opacity:0}usa-button .usa-button-face[data-state=\"success\"]{background:#16a34a;border-color:#16a34a;color:#fff}usa-button .usa-button-face[data-state=\"error\"]{background:#e5484d;border-color:#e5484d;color:#fff}usa-button .usa-button-face[data-state]{transition:background-color 0.25s ease,color 0.25s ease,border-radius 0.3s ease}@keyframes usa-btn-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){usa-button .usa-button-spin circle{animation-duration:2.4s}usa-button .usa-button-face,usa-button .usa-button-face *{transition:none !important}}";
239
+
240
+ const BUTTON_DEFORMS = ['squash', 'wobble', 'gooey', 'dent'];
241
+ let gooInjected = false;
242
+ function injectGoo() {
243
+ if (gooInjected || typeof document === 'undefined')
244
+ return;
245
+ gooInjected = true;
246
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
247
+ svg.setAttribute('aria-hidden', 'true');
248
+ svg.setAttribute('width', '0');
249
+ svg.setAttribute('height', '0');
250
+ svg.style.position = 'absolute';
251
+ svg.innerHTML = '<filter id="usa-goo"><feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/><feColorMatrix in="b" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 22 -9" result="g"/><feComposite in="SourceGraphic" in2="g" operator="atop"/></filter>';
252
+ document.body.appendChild(svg);
253
+ }
254
+ function defineButton(tag = 'usa-button') {
255
+ return base.defineElement(tag, (Base) => class UsaButton extends Base {
256
+ constructor() {
257
+ super(...arguments);
258
+ this._press = null;
259
+ this._status = null;
260
+ this._shapeBefore = null;
261
+ }
262
+ static get observedAttributes() {
263
+ return ['deform', 'state', 'shape', 'disabled'];
264
+ }
265
+ get target() {
266
+ return this.querySelector(':scope > button, :scope > a, :scope > [role="button"]') || this;
267
+ }
268
+ deforms() {
269
+ return this.str('deform').split(/[\s,]+/).filter(Boolean);
270
+ }
271
+ get shape() {
272
+ return this.str('shape', 'pill') || 'pill';
273
+ }
274
+ set shape(v) {
275
+ this.morphTo(v);
276
+ }
277
+ get state() {
278
+ return this.str('state', 'idle') || 'idle';
279
+ }
280
+ set state(v) {
281
+ this.setAttribute('state', v);
282
+ }
283
+ mount() {
284
+ const t = this.target;
285
+ if (t === this) {
286
+ this.setAttribute('role', 'button');
287
+ if (!this.hasAttribute('tabindex'))
288
+ this.tabIndex = 0;
289
+ }
290
+ t.classList.add('usa-button-face');
291
+ if (this.str('morph') === 'submit' && !t.querySelector('.usa-button-status')) {
292
+ const s = document.createElement('span');
293
+ s.className = 'usa-button-status';
294
+ s.setAttribute('aria-hidden', 'true');
295
+ s.innerHTML =
296
+ '<svg class="usa-button-spin" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" pathLength="100"/></svg>' +
297
+ '<svg class="usa-button-ok" viewBox="0 0 24 24"><path d="M5 12.5l4.2 4.2L19 7" pathLength="1"/></svg>' +
298
+ '<svg class="usa-button-err" viewBox="0 0 24 24"><path d="M7 7l10 10M17 7L7 17" pathLength="1"/></svg>';
299
+ t.append(s);
300
+ const live = document.createElement('span');
301
+ live.className = 'usa-sr';
302
+ live.setAttribute('role', 'status');
303
+ this.append(live);
304
+ this._status = live;
305
+ }
306
+ if (this.deforms().includes('gooey'))
307
+ injectGoo();
308
+ this.applyState();
309
+ this.listen(t, 'pointerdown', (e) => {
310
+ if (this.isOff() || (e.pointerType === 'mouse' && e.button !== 0))
311
+ return;
312
+ this.down(e.clientX, e.clientY);
313
+ });
314
+ for (const ev of ['pointerup', 'pointerleave', 'pointercancel'])
315
+ this.listen(t, ev, () => this.up());
316
+ this.listen(t, 'keydown', (e) => (e.key === 'Enter' || e.key === ' ') && !e.repeat && this.down());
317
+ this.listen(t, 'keyup', () => this.up());
318
+ this.listen(t, 'click', (e) => {
319
+ if (this.isOff()) {
320
+ if (this.state === 'loading')
321
+ e.preventDefault();
322
+ return;
323
+ }
324
+ if (this.deforms().includes('wobble'))
325
+ this.wobble();
326
+ if (this.hasAttribute('haptic'))
327
+ haptic(this.num('haptic', 10));
328
+ if (this.str('morph') === 'submit' && this.state === 'idle')
329
+ this.submit();
330
+ });
331
+ if (t === this)
332
+ this.listen(this, 'keydown', (e) => {
333
+ if ((e.key === 'Enter' || e.key === ' ') && !e.repeat) {
334
+ e.preventDefault();
335
+ this.click();
336
+ }
337
+ });
338
+ }
339
+ unmount() {
340
+ clearTimeout(this._timer);
341
+ this._press?.cancel();
342
+ }
343
+ changed(name) {
344
+ if (name === 'state')
345
+ this.applyState();
346
+ else if (name === 'shape')
347
+ this.target.setAttribute('data-shape', this.shape);
348
+ else {
349
+ super.changed(name);
350
+ }
351
+ }
352
+ isOff() {
353
+ return this.flag('disabled') || this.state === 'loading';
354
+ }
355
+ /* ------------------------------------------------ press deformations */
356
+ down(x, y) {
357
+ if (this.reduced || this.hasAttribute('data-pressed'))
358
+ return;
359
+ const d = this.deforms();
360
+ if (!d.length)
361
+ return;
362
+ this.setAttribute('data-pressed', '');
363
+ const t = this.target;
364
+ const r = t.getBoundingClientRect();
365
+ const px = x === undefined ? 0.5 : base.clamp((x - r.left) / (r.width || 1), 0, 1);
366
+ const py = y === undefined ? 0.5 : base.clamp((y - r.top) / (r.height || 1), 0, 1);
367
+ t.style.setProperty('--usa-dent-x', `${(px * 100).toFixed(1)}%`);
368
+ t.style.setProperty('--usa-dent-y', `${(py * 100).toFixed(1)}%`);
369
+ const parts = [];
370
+ if (d.includes('dent'))
371
+ parts.push(`perspective(600px) rotateX(${((0.5 - py) * -14).toFixed(2)}deg) rotateY(${((px - 0.5) * 14).toFixed(2)}deg) scale(0.97)`);
372
+ if (d.includes('squash'))
373
+ parts.push('scale(1.12, 0.84)');
374
+ if (d.includes('gooey')) {
375
+ parts.push('scale(0.96)');
376
+ this.goo(px, py);
377
+ }
378
+ if (!parts.length)
379
+ return;
380
+ this._press?.cancel();
381
+ this._press = this.motion(t, [{ transform: 'none' }, { transform: parts.join(' ') }], { duration: 110, easing: 'ease-out', fill: 'forwards' });
382
+ }
383
+ up() {
384
+ if (!this.hasAttribute('data-pressed'))
385
+ return;
386
+ this.removeAttribute('data-pressed');
387
+ const t = this.target;
388
+ const a = this._press;
389
+ const from = a?.effect?.getKeyframes?.().slice(-1)[0]?.transform;
390
+ a?.cancel();
391
+ if (!from)
392
+ return;
393
+ this._press = this.motion(t, [{ transform: from }, { transform: 'none' }], { ...spring.springEasing(this.deforms().includes('squash') ? 'bouncy' : 'wobbly') });
394
+ }
395
+ wobble() {
396
+ if (this.reduced)
397
+ return;
398
+ const t = this.target;
399
+ const r = getComputedStyle(t).borderRadius || '12px';
400
+ this.motion(t, [
401
+ { borderRadius: r },
402
+ { borderRadius: '42% 58% 50% 50% / 60% 45% 55% 40%', offset: 0.2 },
403
+ { borderRadius: '58% 42% 45% 55% / 40% 60% 40% 60%', offset: 0.45 },
404
+ { borderRadius: '48% 52% 52% 48% / 52% 48% 52% 48%', offset: 0.7 },
405
+ { borderRadius: r },
406
+ ], { duration: 700, easing: 'ease-out' });
407
+ }
408
+ goo(px, py) {
409
+ const t = this.target;
410
+ const layer = document.createElement('span');
411
+ layer.className = 'usa-button-goo';
412
+ layer.setAttribute('aria-hidden', 'true');
413
+ layer.style.setProperty('--usa-goo-bg', getComputedStyle(t).backgroundColor || 'currentColor');
414
+ const drops = [];
415
+ for (let i = 0; i < 4; i++) {
416
+ const d = document.createElement('i');
417
+ d.style.left = `${(px * 100).toFixed(1)}%`;
418
+ d.style.top = `${(py * 100).toFixed(1)}%`;
419
+ layer.append(d);
420
+ drops.push(d);
421
+ }
422
+ this.prepend(layer);
423
+ let left = drops.length;
424
+ drops.forEach((d, i) => {
425
+ const ang = (i / drops.length) * Math.PI * 2 + 0.6;
426
+ const dist = 26 + (i % 2) * 12;
427
+ const a = this.motion(d, [
428
+ { transform: 'translate(-50%, -50%) scale(0.4)' },
429
+ { transform: `translate(calc(-50% + ${(Math.cos(ang) * dist).toFixed(1)}px), calc(-50% + ${(Math.sin(ang) * dist).toFixed(1)}px)) scale(1)`, offset: 0.45 },
430
+ { transform: 'translate(-50%, -50%) scale(0.2)' },
431
+ ], { duration: 700, easing: 'cubic-bezier(0.34, 1.3, 0.64, 1)', fill: 'forwards' });
432
+ const end = () => --left === 0 && layer.remove();
433
+ if (a)
434
+ a.onfinish = end;
435
+ else
436
+ end();
437
+ });
438
+ }
439
+ /* ------------------------------------------------ shape morph */
440
+ async morphTo(shape) {
441
+ const t = this.target;
442
+ const before = t.getBoundingClientRect();
443
+ this.setAttribute('shape', shape);
444
+ t.setAttribute('data-shape', shape);
445
+ if (this.reduced)
446
+ return;
447
+ const after = t.getBoundingClientRect();
448
+ if (!before.width || !after.width || Math.abs(before.width - after.width) < 0.5)
449
+ return;
450
+ const a = this.motion(t, [{ width: `${before.width}px` }, { width: `${after.width}px` }], spring.springEasing('stiff'));
451
+ await a?.finished.catch(() => undefined);
452
+ }
453
+ /* ------------------------------------------------ submit morph */
454
+ submit() {
455
+ let settled = false;
456
+ const done = (ok = true) => {
457
+ if (settled)
458
+ return;
459
+ settled = true;
460
+ this.state = ok ? 'success' : 'error';
461
+ };
462
+ this.state = 'loading';
463
+ this.emit('submit', { done });
464
+ }
465
+ applyState() {
466
+ if (this.str('morph') !== 'submit')
467
+ return;
468
+ const t = this.target;
469
+ const s = this.state;
470
+ clearTimeout(this._timer);
471
+ t.setAttribute('data-state', s);
472
+ if (s === 'loading') {
473
+ if (this._shapeBefore === null)
474
+ this._shapeBefore = this.shape;
475
+ t.setAttribute('aria-busy', 'true');
476
+ this.morphTo('circle');
477
+ }
478
+ else {
479
+ t.removeAttribute('aria-busy');
480
+ }
481
+ if (s === 'error') {
482
+ shake(t);
483
+ if (this.hasAttribute('haptic'))
484
+ haptic([30, 40, 30]);
485
+ }
486
+ if (s === 'success' && !this.reduced) {
487
+ const ok = t.querySelector('.usa-button-ok');
488
+ if (ok)
489
+ this.motion(ok, [{ transform: 'scale(0.4)' }, { transform: 'scale(1)' }], spring.springEasing('bouncy'));
490
+ }
491
+ if (this._status)
492
+ this._status.textContent = s === 'loading' ? 'Loading…' : s === 'success' ? 'Done' : s === 'error' ? 'Failed' : '';
493
+ if (s === 'success' || s === 'error') {
494
+ this._timer = setTimeout(() => {
495
+ this.state = 'idle';
496
+ }, this.num('reset', 1800));
497
+ }
498
+ if (s === 'idle' && this._shapeBefore !== null) {
499
+ const back = this._shapeBefore;
500
+ this._shapeBefore = null;
501
+ this.morphTo(back);
502
+ }
503
+ this.emit('state', { state: s });
504
+ }
505
+ }, { id: 'button', text: css$5 });
506
+ }
507
+
508
+ var css$4 = "usa-icon-morph{display:inline-grid;place-items:center;line-height:0;color:inherit;-webkit-tap-highlight-color:transparent;vertical-align:middle}usa-icon-morph svg{fill:currentColor;overflow:visible}usa-icon-morph[toggle]{cursor:pointer;border-radius:8px}usa-icon-morph[toggle]:focus-visible{outline:2px solid var(--usa-accent,#7c5cff);outline-offset:3px}";
509
+
510
+ const C = [[12, 12], [12, 12], [12, 12], [12, 12]];
511
+ /**
512
+ * Morphable icons: every icon is three quads (four points each) on a 24×24
513
+ * grid, so any icon can morph into any other by interpolating points.
514
+ */
515
+ const MORPH_ICONS = {
516
+ play: [[[7, 5], [12.5, 8.25], [12.5, 15.75], [7, 19]], [[12.5, 8.25], [19, 12], [19, 12], [12.5, 15.75]], C],
517
+ pause: [[[6, 5], [10, 5], [10, 19], [6, 19]], [[14, 5], [18, 5], [18, 19], [14, 19]], C],
518
+ menu: [[[4, 6], [20, 6], [20, 8], [4, 8]], [[4, 11], [20, 11], [20, 13], [4, 13]], [[4, 16], [20, 16], [20, 18], [4, 18]]],
519
+ close: [[[5.2, 6.6], [6.6, 5.2], [18.8, 17.4], [17.4, 18.8]], C, [[17.4, 5.2], [18.8, 6.6], [6.6, 18.8], [5.2, 17.4]]],
520
+ plus: [[[11, 4], [13, 4], [13, 20], [11, 20]], [[4, 11], [20, 11], [20, 13], [4, 13]], C],
521
+ minus: [[[4, 11], [20, 11], [20, 13], [4, 13]], [[4, 11], [20, 11], [20, 13], [4, 13]], C],
522
+ check: [[[4.3, 12.7], [5.7, 11.3], [10.4, 16], [9, 17.4]], [[9, 17.4], [7.6, 16], [18.3, 5.3], [19.7, 6.7]], C],
523
+ 'arrow-right': [[[4, 11], [17, 11], [17, 13], [4, 13]], [[12.6, 6.4], [14, 5], [21, 12], [19.6, 13.4]], [[19.6, 10.6], [21, 12], [14, 19], [12.6, 17.6]]],
524
+ };
525
+ /** SVG path data for an icon, or for the interpolation `t` (0–1) between two. */
526
+ function morphPath(from, to = from, t = 0) {
527
+ const a = MORPH_ICONS[from] || MORPH_ICONS.menu;
528
+ const b = MORPH_ICONS[to] || a;
529
+ return a
530
+ .map((q, i) => {
531
+ const pts = q.map((p, j) => {
532
+ const r = b[i][j];
533
+ return `${(p[0] + (r[0] - p[0]) * t).toFixed(2)} ${(p[1] + (r[1] - p[1]) * t).toFixed(2)}`;
534
+ });
535
+ return `M${pts.join('L')}Z`;
536
+ })
537
+ .join('');
538
+ }
539
+ function defineIconMorph(tag = 'usa-icon-morph') {
540
+ return base.defineElement(tag, (Base) => class UsaIconMorph extends Base {
541
+ constructor() {
542
+ super(...arguments);
543
+ this._i = 0;
544
+ this._from = 'play';
545
+ this._to = 'play';
546
+ }
547
+ static get observedAttributes() {
548
+ return ['icons', 'size', 'toggle'];
549
+ }
550
+ list() {
551
+ return this.str('icons', 'play,pause').split(',').map((s) => s.trim()).filter((s) => MORPH_ICONS[s]);
552
+ }
553
+ get index() {
554
+ return this._i;
555
+ }
556
+ set index(v) {
557
+ this.show(v);
558
+ }
559
+ get icon() {
560
+ return this.list()[this._i] || 'play';
561
+ }
562
+ draw(t) {
563
+ this.querySelector('path')?.setAttribute('d', morphPath(this._from, this._to, t));
564
+ }
565
+ mount() {
566
+ const size = this.num('size', 24);
567
+ this.innerHTML = `<svg viewBox="0 0 24 24" width="${size}" height="${size}" aria-hidden="true" focusable="false"><path/></svg>`;
568
+ this._i = Math.max(0, Math.min(this.list().length - 1, this.num('index', 0)));
569
+ this._from = this._to = this.icon;
570
+ this._t = spring.createSpring({ value: 1, spring: this.str('preset', 'wobbly'), onUpdate: (v) => this.draw(v) });
571
+ this.draw(1);
572
+ if (this.flag('toggle')) {
573
+ this.setAttribute('role', 'button');
574
+ if (!this.hasAttribute('tabindex'))
575
+ this.tabIndex = 0;
576
+ this.listen(this, 'click', () => this.next());
577
+ this.listen(this, 'keydown', (e) => {
578
+ if ((e.key === 'Enter' || e.key === ' ') && !e.repeat) {
579
+ e.preventDefault();
580
+ this.next();
581
+ }
582
+ });
583
+ }
584
+ this.label();
585
+ }
586
+ unmount() {
587
+ this._t?.stop();
588
+ }
589
+ label() {
590
+ const labels = this.str('labels').split(',').map((s) => s.trim());
591
+ const l = labels[this._i];
592
+ if (l)
593
+ this.setAttribute('aria-label', l);
594
+ if (!this.flag('toggle') && !l)
595
+ this.setAttribute('aria-hidden', 'true');
596
+ }
597
+ show(icon) {
598
+ const list = this.list();
599
+ const i = typeof icon === 'number' ? ((icon % list.length) + list.length) % list.length : list.indexOf(icon);
600
+ if (i < 0 || !this._t)
601
+ return;
602
+ const name = list[i];
603
+ // morph from wherever we are now (interruptible)
604
+ const cur = this._t.value;
605
+ this._from = cur >= 0.5 ? this._to : this._from;
606
+ this._to = name;
607
+ this._i = i;
608
+ this._t.jump(0);
609
+ this._t.set(1);
610
+ this.label();
611
+ this.emit('change', { index: i, icon: name });
612
+ }
613
+ next() {
614
+ this.show(this._i + 1);
615
+ }
616
+ }, { id: 'icon-morph', text: css$4 });
617
+ }
618
+
619
+ var css$3 = "usa-like{--usa-like-color:#f43f5e;display:inline-flex;align-items:center;gap:0.35em;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent;vertical-align:middle}usa-like .usa-like-heart{fill:transparent;stroke:currentColor;stroke-width:1.8;transition:fill 0.2s ease,stroke 0.2s ease;overflow:visible}usa-like[liked] .usa-like-heart{fill:var(--usa-like-color);stroke:var(--usa-like-color)}usa-like .usa-like-count{font-variant-numeric:tabular-nums}usa-like[disabled]{opacity:0.5;cursor:not-allowed}usa-like:focus-visible{outline:2px solid var(--usa-like-color);outline-offset:3px;border-radius:8px}";
620
+
621
+ const HEART = 'M12 21s-7.5-4.6-9.6-9.2C.9 8.4 3 4.5 6.7 4.5c2.1 0 3.6 1.2 5.3 3.2 1.7-2 3.2-3.2 5.3-3.2 3.7 0 5.8 3.9 4.3 7.3C19.5 16.4 12 21 12 21z';
622
+ function defineLike(tag = 'usa-like') {
623
+ return base.defineElement(tag, (Base) => class UsaLike extends Base {
624
+ static get observedAttributes() {
625
+ return ['liked', 'count', 'label', 'disabled'];
626
+ }
627
+ get liked() {
628
+ return this.flag('liked');
629
+ }
630
+ set liked(v) {
631
+ this.setFlag('liked', v);
632
+ }
633
+ get count() {
634
+ return this.hasAttribute('count') ? this.num('count', 0) : null;
635
+ }
636
+ set count(v) {
637
+ if (v === null)
638
+ this.removeAttribute('count');
639
+ else
640
+ this.setAttribute('count', String(v));
641
+ }
642
+ mount() {
643
+ if (!this.querySelector(':scope > .usa-like-heart')) {
644
+ const size = this.num('size', 24);
645
+ this.insertAdjacentHTML('afterbegin', `<svg class="usa-like-heart" viewBox="0 0 24 24" width="${size}" height="${size}" aria-hidden="true"><path d="${HEART}"/></svg><span class="usa-like-count" aria-hidden="true"></span>`);
646
+ }
647
+ if (this.str('color'))
648
+ this.style.setProperty('--usa-like-color', this.str('color'));
649
+ this.setAttribute('role', 'button');
650
+ if (!this.hasAttribute('tabindex'))
651
+ this.tabIndex = 0;
652
+ this.sync();
653
+ this.listen(this, 'click', () => this.toggle());
654
+ this.listen(this, 'keydown', (e) => {
655
+ if ((e.key === 'Enter' || e.key === ' ') && !e.repeat) {
656
+ e.preventDefault();
657
+ this.toggle();
658
+ }
659
+ });
660
+ }
661
+ changed() {
662
+ this.sync();
663
+ }
664
+ sync() {
665
+ const c = this.count;
666
+ const label = this.str('label', 'Like');
667
+ this.setAttribute('aria-pressed', String(this.liked));
668
+ this.setAttribute('aria-label', c === null ? label : `${label} (${c})`);
669
+ this.toggleAttribute('aria-disabled', this.flag('disabled'));
670
+ const out = this.querySelector('.usa-like-count');
671
+ if (out)
672
+ out.textContent = c === null ? '' : new Intl.NumberFormat().format(c);
673
+ }
674
+ toggle(force) {
675
+ if (this.flag('disabled'))
676
+ return;
677
+ const next = force === undefined ? !this.liked : force;
678
+ if (next === this.liked)
679
+ return;
680
+ this.liked = next;
681
+ if (this.count !== null)
682
+ this.count = Math.max(0, this.count + (next ? 1 : -1));
683
+ this.sync();
684
+ const heart = this.querySelector('.usa-like-heart');
685
+ if (next && heart && !this.reduced) {
686
+ this.motion(heart, [{ transform: 'scale(0.4)' }, { transform: 'scale(1)' }], spring.springEasing('bouncy'));
687
+ const r = heart.getBoundingClientRect();
688
+ burst(r.left + r.width / 2, r.top + r.height / 2, { count: 10, distance: 28, size: 5, colors: [getComputedStyle(this).getPropertyValue('--usa-like-color').trim() || '#f43f5e', '#fb923c', '#facc15'] });
689
+ }
690
+ if (this.hasAttribute('haptic'))
691
+ haptic(this.num('haptic', 12));
692
+ this.dispatchEvent(new Event('change', { bubbles: true }));
693
+ this.emit('change', { liked: next, count: this.count });
694
+ }
695
+ }, { id: 'like', text: css$3 });
696
+ }
697
+
698
+ var css$2 = "usa-hold{--usa-hold-color:#e5484d;position:relative;display:inline-flex;align-items:center;gap:0.5em;cursor:pointer;user-select:none;-webkit-user-select:none;touch-action:manipulation;-webkit-tap-highlight-color:transparent}usa-hold .usa-hold-ring{width:1.6em;height:1.6em;transform:rotate(-90deg);flex:none}usa-hold .usa-hold-ring circle{fill:none;stroke-width:3.5;stroke-linecap:round}usa-hold .usa-hold-ring circle:first-child{stroke:color-mix(in srgb,currentColor 18%,transparent)}usa-hold .usa-hold-ring circle:last-child{stroke:var(--usa-hold-color);stroke-dasharray:100;stroke-dashoffset:100}usa-hold[data-holding]{transform:scale(calc(1 - var(--usa-hold,0) * 0.05))}usa-hold[data-done] .usa-hold-ring{animation:usa-hold-pop 0.4s cubic-bezier(0.34,1.56,0.64,1)}@keyframes usa-hold-pop{50%{transform:rotate(-90deg) scale(1.3)}}usa-hold[disabled]{opacity:0.5;cursor:not-allowed}usa-hold:focus-visible{outline:2px solid var(--usa-hold-color);outline-offset:3px;border-radius:10px}@media (prefers-reduced-motion:reduce){usa-hold[data-holding]{transform:none}usa-hold[data-done] .usa-hold-ring{animation:none}}";
699
+
700
+ function defineHold(tag = 'usa-hold') {
701
+ return base.defineElement(tag, (Base) => class UsaHold extends Base {
702
+ constructor() {
703
+ super(...arguments);
704
+ this._p = 0;
705
+ this._frame = 0;
706
+ this._holding = false;
707
+ }
708
+ static get observedAttributes() {
709
+ return ['duration', 'disabled'];
710
+ }
711
+ get progress() {
712
+ return this._p;
713
+ }
714
+ set(p) {
715
+ this._p = p;
716
+ this.style.setProperty('--usa-hold', p.toFixed(4));
717
+ const c = this.querySelector('.usa-hold-ring circle:last-child');
718
+ if (c)
719
+ c.style.strokeDashoffset = String(100 - p * 100);
720
+ }
721
+ mount() {
722
+ if (!this.querySelector(':scope > .usa-hold-ring')) {
723
+ this.insertAdjacentHTML('beforeend', '<svg class="usa-hold-ring" viewBox="0 0 36 36" aria-hidden="true"><circle cx="18" cy="18" r="15.9" pathLength="100"/><circle cx="18" cy="18" r="15.9" pathLength="100"/></svg>');
724
+ }
725
+ if (this.str('color'))
726
+ this.style.setProperty('--usa-hold-color', this.str('color'));
727
+ this.setAttribute('role', 'button');
728
+ if (!this.hasAttribute('tabindex'))
729
+ this.tabIndex = 0;
730
+ if (this.str('label'))
731
+ this.setAttribute('aria-label', this.str('label'));
732
+ this.setAttribute('aria-description', 'Press and hold to confirm');
733
+ this.set(0);
734
+ this.listen(this, 'pointerdown', (e) => (e.pointerType !== 'mouse' || e.button === 0) && this.start());
735
+ for (const t of ['pointerup', 'pointerleave', 'pointercancel'])
736
+ this.listen(this, t, () => this.stop());
737
+ this.listen(this, 'keydown', (e) => {
738
+ if (e.key === 'Enter' || e.key === ' ') {
739
+ e.preventDefault();
740
+ if (!e.repeat)
741
+ this.start();
742
+ }
743
+ });
744
+ this.listen(this, 'keyup', (e) => (e.key === 'Enter' || e.key === ' ') && this.stop());
745
+ this.listen(this, 'contextmenu', (e) => this._holding && e.preventDefault());
746
+ }
747
+ unmount() {
748
+ base.caf(this._frame);
749
+ this._holding = false;
750
+ }
751
+ start() {
752
+ if (this.flag('disabled') || this._holding)
753
+ return;
754
+ this._holding = true;
755
+ this.setAttribute('data-holding', '');
756
+ const dur = Math.max(100, this.num('duration', 1200));
757
+ let last = base.now();
758
+ const tick = () => {
759
+ const t = base.now();
760
+ const p = Math.min(1, this._p + (t - last) / dur);
761
+ last = t;
762
+ this.set(p);
763
+ this.emit('progress', { progress: p });
764
+ if (p >= 1) {
765
+ this._holding = false;
766
+ this.removeAttribute('data-holding');
767
+ this.setAttribute('data-done', '');
768
+ if (this.hasAttribute('haptic'))
769
+ haptic(20);
770
+ this.emit('confirm');
771
+ setTimeout(() => {
772
+ this.removeAttribute('data-done');
773
+ this.rewind();
774
+ }, 700);
775
+ return;
776
+ }
777
+ this._frame = base.raf(tick);
778
+ };
779
+ this._frame = base.raf(tick);
780
+ }
781
+ stop() {
782
+ if (!this._holding)
783
+ return;
784
+ this._holding = false;
785
+ base.caf(this._frame);
786
+ this.removeAttribute('data-holding');
787
+ if (this._p < 1) {
788
+ this.emit('cancel', { progress: this._p });
789
+ this.rewind();
790
+ }
791
+ }
792
+ rewind() {
793
+ let last = base.now();
794
+ const back = () => {
795
+ if (this._holding)
796
+ return;
797
+ const t = base.now();
798
+ const p = Math.max(0, this._p - (t - last) / 250);
799
+ last = t;
800
+ this.set(p);
801
+ if (p > 0)
802
+ this._frame = base.raf(back);
803
+ };
804
+ this._frame = base.raf(back);
805
+ }
806
+ cancel() {
807
+ this.stop();
808
+ }
809
+ }, { id: 'hold', text: css$2 });
810
+ }
811
+
812
+ var css$1 = "usa-double-tap{position:relative;display:block;touch-action:manipulation;-webkit-tap-highlight-color:transparent;user-select:none;-webkit-user-select:none}usa-double-tap .usa-double-tap-icon{position:absolute;pointer-events:none;font-size:64px;line-height:1;color:#f43f5e;transform:translate(-50%,-50%);text-shadow:0 6px 18px rgb(0 0 0 / 0.35);z-index:2}";
813
+
814
+ function defineDoubleTap(tag = 'usa-double-tap') {
815
+ return base.defineElement(tag, (Base) => class UsaDoubleTap extends Base {
816
+ mount() {
817
+ let last = 0;
818
+ let lx = 0;
819
+ let ly = 0;
820
+ this.listen(this, 'pointerup', (e) => {
821
+ if (this.flag('disabled'))
822
+ return;
823
+ const t = e.timeStamp || Date.now();
824
+ if (t - last < this.num('delay', 300) && Math.hypot(e.clientX - lx, e.clientY - ly) < 40) {
825
+ last = 0;
826
+ this.pop(e.clientX, e.clientY);
827
+ }
828
+ else {
829
+ last = t;
830
+ lx = e.clientX;
831
+ ly = e.clientY;
832
+ }
833
+ });
834
+ this.listen(this, 'dblclick', (e) => e.preventDefault());
835
+ this.listen(this, 'keydown', (e) => e.key.toLowerCase() === 'l' && !e.repeat && this.pop());
836
+ }
837
+ pop(x, y) {
838
+ const r = this.getBoundingClientRect();
839
+ if (x === undefined || y === undefined) {
840
+ x = r.left + r.width / 2;
841
+ y = r.top + r.height / 2;
842
+ }
843
+ const icon = document.createElement('span');
844
+ icon.className = 'usa-double-tap-icon';
845
+ icon.setAttribute('aria-hidden', 'true');
846
+ icon.textContent = this.str('icon', '♥');
847
+ icon.style.left = `${x - r.left}px`;
848
+ icon.style.top = `${y - r.top}px`;
849
+ if (this.str('color'))
850
+ icon.style.color = this.str('color');
851
+ this.append(icon);
852
+ const frames = this.reduced
853
+ ? [{ opacity: 0 }, { opacity: 1, offset: 0.3 }, { opacity: 0 }]
854
+ : [
855
+ { opacity: 0, transform: 'translate(-50%, -50%) scale(0.2) rotate(-15deg)' },
856
+ { opacity: 1, transform: 'translate(-50%, -50%) scale(1.15) rotate(5deg)', offset: 0.3 },
857
+ { opacity: 1, transform: 'translate(-50%, -50%) scale(1) rotate(0deg)', offset: 0.6 },
858
+ { opacity: 0, transform: 'translate(-50%, -110%) scale(0.9)' },
859
+ ];
860
+ const a = this.motion(icon, frames, { duration: 900, easing: 'ease-out', fill: 'forwards' });
861
+ if (a)
862
+ a.onfinish = () => icon.remove();
863
+ else
864
+ icon.remove();
865
+ burst(x, y, { count: 8, distance: 40, size: 5, colors: [this.str('color', '#f43f5e'), '#fb923c', '#facc15'] });
866
+ if (this.hasAttribute('haptic'))
867
+ haptic(15);
868
+ this.emit('double-tap', { x: x - r.left, y: y - r.top });
869
+ }
870
+ }, { id: 'double-tap', text: css$1 });
871
+ }
872
+
873
+ var css = "usa-checkbox{--usa-checkbox-on:var(--usa-accent,#7c5cff);display:inline-flex;align-items:center;gap:0.55em;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent;vertical-align:middle}usa-checkbox .usa-checkbox-box{flex:none;width:1.25em;height:1.25em;border-radius:0.3em;border:1.5px solid color-mix(in srgb,currentColor 55%,transparent);display:grid;place-items:center;transition:background-color 0.2s ease,border-color 0.2s ease;box-sizing:border-box}usa-checkbox[shape=\"circle\"] .usa-checkbox-box{border-radius:50%}usa-checkbox svg{width:85%;height:85%;fill:none;stroke:#fff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round}usa-checkbox svg path{stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset 0.28s cubic-bezier(0.65,0,0.35,1) 0.05s}usa-checkbox[checked]:not([indeterminate]) .usa-checkbox-check,usa-checkbox[indeterminate] .usa-checkbox-dash{stroke-dashoffset:0}usa-checkbox[checked] .usa-checkbox-box,usa-checkbox[indeterminate] .usa-checkbox-box{background:var(--usa-checkbox-on);border-color:var(--usa-checkbox-on)}usa-checkbox[disabled]{opacity:0.45;cursor:not-allowed}usa-checkbox:focus-visible{outline:none}usa-checkbox:focus-visible .usa-checkbox-box{outline:2px solid var(--usa-checkbox-on);outline-offset:2px}@media (prefers-reduced-motion:reduce){usa-checkbox svg path,usa-checkbox .usa-checkbox-box{transition:none}}";
874
+
875
+ function defineCheckbox(tag = 'usa-checkbox') {
876
+ return base.defineElement(tag, (Base) => {
877
+ class UsaCheckbox extends Base {
878
+ static get observedAttributes() {
879
+ return ['checked', 'indeterminate', 'disabled', 'label'];
880
+ }
881
+ constructor() {
882
+ super();
883
+ this._internals = null;
884
+ try {
885
+ this._internals = this.attachInternals?.() ?? null;
886
+ }
887
+ catch {
888
+ this._internals = null;
889
+ }
890
+ }
891
+ get checked() {
892
+ return this.flag('checked');
893
+ }
894
+ set checked(v) {
895
+ this.setFlag('checked', v);
896
+ }
897
+ get indeterminate() {
898
+ return this.flag('indeterminate');
899
+ }
900
+ set indeterminate(v) {
901
+ this.setFlag('indeterminate', v);
902
+ }
903
+ mount() {
904
+ if (!this.querySelector(':scope > .usa-checkbox-box')) {
905
+ this.insertAdjacentHTML('afterbegin', '<span class="usa-checkbox-box" aria-hidden="true"><svg viewBox="0 0 24 24"><path class="usa-checkbox-check" d="M5 12.5l4.2 4.2L19 7" pathLength="1"/><path class="usa-checkbox-dash" d="M6 12h12" pathLength="1"/></svg></span>');
906
+ }
907
+ this.setAttribute('role', 'checkbox');
908
+ if (!this.hasAttribute('tabindex'))
909
+ this.tabIndex = 0;
910
+ this.sync();
911
+ this.listen(this, 'click', () => this.toggle());
912
+ this.listen(this, 'keydown', (e) => {
913
+ if (e.key === ' ' && !e.repeat) {
914
+ e.preventDefault();
915
+ this.toggle();
916
+ }
917
+ });
918
+ }
919
+ changed() {
920
+ this.sync();
921
+ }
922
+ sync() {
923
+ this.setAttribute('aria-checked', this.indeterminate ? 'mixed' : String(this.checked));
924
+ if (this.str('label'))
925
+ this.setAttribute('aria-label', this.str('label'));
926
+ this.toggleAttribute('aria-disabled', this.flag('disabled'));
927
+ this._internals?.setFormValue?.(this.checked ? this.str('value', 'on') : null);
928
+ }
929
+ toggle(force) {
930
+ if (this.flag('disabled'))
931
+ return;
932
+ const next = force === undefined ? !this.checked || this.indeterminate : force;
933
+ this.indeterminate = false;
934
+ this.checked = next;
935
+ this.sync();
936
+ const box = this.querySelector('.usa-checkbox-box');
937
+ if (box && !this.reduced)
938
+ this.motion(box, [{ transform: 'scale(0.75)' }, { transform: 'scale(1)' }], spring.springEasing('bouncy'));
939
+ this.dispatchEvent(new Event('change', { bubbles: true }));
940
+ this.emit('change', { checked: next });
941
+ }
942
+ }
943
+ UsaCheckbox.formAssociated = true;
944
+ return UsaCheckbox;
945
+ }, { id: 'checkbox', text: css });
946
+ }
947
+
948
+ /**
949
+ * use-scroll-animate/components/click — click & tap effects (v2.5).
950
+ * `<usa-click>` (ripple, burst, confetti, squish, press-spring, shake),
951
+ * `<usa-button>` (button click deformation: squash, wobble, gooey, dent;
952
+ * shape morph; submit → loading → success), `<usa-icon-morph>`,
953
+ * `<usa-like>`, `<usa-hold>`, `<usa-double-tap>`, `<usa-checkbox>`, plus
954
+ * `burst()`, `confetti()`, `shake()` and `haptic()`.
955
+ */
956
+ /** Register every component of this category under its default tag. */
957
+ function defineClickComponents() {
958
+ defineClick();
959
+ defineButton();
960
+ defineIconMorph();
961
+ defineLike();
962
+ defineHold();
963
+ defineDoubleTap();
964
+ defineCheckbox();
965
+ }
966
+
967
+ exports.configureComponents = base.configureComponents;
968
+ exports.prefersReducedMotion = base.prefersReducedMotion;
969
+ exports.BUTTON_DEFORMS = BUTTON_DEFORMS;
970
+ exports.CLICK_EFFECTS = CLICK_EFFECTS;
971
+ exports.MORPH_ICONS = MORPH_ICONS;
972
+ exports.burst = burst;
973
+ exports.confetti = confetti;
974
+ exports.defineButton = defineButton;
975
+ exports.defineCheckbox = defineCheckbox;
976
+ exports.defineClick = defineClick;
977
+ exports.defineClickComponents = defineClickComponents;
978
+ exports.defineDoubleTap = defineDoubleTap;
979
+ exports.defineHold = defineHold;
980
+ exports.defineIconMorph = defineIconMorph;
981
+ exports.defineLike = defineLike;
982
+ exports.haptic = haptic;
983
+ exports.morphPath = morphPath;
984
+ exports.shake = shake;
985
+ //# sourceMappingURL=click.cjs.map