@adia-ai/web-components 0.2.3 → 0.2.5
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/components/button/button.js +3 -0
- package/components/demo-toggle/demo-toggle.a2ui.json +144 -0
- package/components/demo-toggle/demo-toggle.css +120 -0
- package/components/demo-toggle/demo-toggle.js +144 -0
- package/components/demo-toggle/demo-toggle.test.js +102 -0
- package/components/demo-toggle/demo-toggle.yaml +144 -0
- package/components/fields/fields.a2ui.json +106 -0
- package/components/fields/fields.css +60 -0
- package/components/fields/fields.js +96 -0
- package/components/fields/fields.test.js +88 -0
- package/components/fields/fields.yaml +120 -0
- package/components/index.js +2 -0
- package/components/input/input.js +11 -0
- package/components/list/list.css +21 -0
- package/components/textarea/textarea.js +10 -0
- package/core/icons.js +12 -1
- package/package.json +10 -10
- package/styles/components.css +2 -0
- package/styles/typography.css +1 -1
- package/traits/_catalog.json +259 -4
- package/traits/active-state.test.js +1 -1
- package/traits/anchor-positioning.js +205 -52
- package/traits/anchor-positioning.test.js +77 -4
- package/traits/announcer-stage.js +157 -0
- package/traits/announcer.js +145 -0
- package/traits/announcer.test.js +268 -0
- package/traits/arrow-grid-nav.js +234 -0
- package/traits/arrow-grid-nav.test.js +375 -0
- package/traits/attention-pulse.js +1 -1
- package/traits/attention-pulse.test.js +1 -1
- package/traits/confetti-burst.js +67 -63
- package/traits/confetti-burst.test.js +16 -8
- package/traits/confetti-stage.js +143 -0
- package/traits/confetti.js +44 -47
- package/traits/confetti.test.js +24 -5
- package/traits/count-up.js +31 -6
- package/traits/count-up.test.js +1 -1
- package/traits/declarative.test.js +1 -1
- package/traits/dirty-state.test.js +1 -1
- package/traits/drag-ghost.js +43 -3
- package/traits/drag-ghost.test.js +1 -1
- package/traits/draggable-list-item.js +458 -0
- package/traits/draggable-list-item.test.js +51 -0
- package/traits/draggable.js +14 -4
- package/traits/draggable.test.js +1 -1
- package/traits/drop-target.js +223 -0
- package/traits/drop-target.test.js +241 -0
- package/traits/droppable-collection.js +89 -0
- package/traits/droppable-collection.test.js +99 -0
- package/traits/droppable.js +136 -0
- package/traits/droppable.test.js +54 -0
- package/traits/error-shake.js +157 -0
- package/traits/error-shake.test.js +114 -0
- package/traits/fade-presence.test.js +1 -1
- package/traits/focus-restore.js +135 -0
- package/traits/focus-restore.test.js +202 -0
- package/traits/focus-trap.test.js +1 -1
- package/traits/focusable.test.js +1 -1
- package/traits/glow-focus.js +1 -1
- package/traits/glow-focus.test.js +1 -1
- package/traits/gradient-shift.js +1 -1
- package/traits/gradient-shift.test.js +1 -1
- package/traits/haptic-feedback.test.js +1 -1
- package/traits/hotkey.test.js +1 -1
- package/traits/hoverable.test.js +1 -1
- package/traits/index.js +15 -0
- package/traits/inertia-drag.js +9 -0
- package/traits/inertia-drag.test.js +1 -1
- package/traits/input-mask.js +328 -0
- package/traits/input-mask.test.js +151 -0
- package/traits/intersection-observer.test.js +1 -1
- package/traits/keyboard-nav.test.js +1 -1
- package/traits/keyboard-reorderable.js +254 -0
- package/traits/keyboard-reorderable.test.js +45 -0
- package/traits/layout-animation.js +229 -0
- package/traits/layout-animation.test.js +114 -0
- package/traits/long-press.js +212 -0
- package/traits/long-press.test.js +244 -0
- package/traits/magnetic-hover.js +1 -1
- package/traits/magnetic-hover.test.js +1 -1
- package/traits/noise-texture.js +7 -3
- package/traits/noise-texture.test.js +1 -1
- package/traits/parallax.js +1 -1
- package/traits/parallax.test.js +1 -1
- package/traits/portal.test.js +1 -1
- package/traits/pressable.test.js +1 -1
- package/traits/resettable.js +29 -3
- package/traits/resettable.test.js +34 -1
- package/traits/resizable.test.js +1 -1
- package/traits/resize-observer.test.js +1 -1
- package/traits/ripple.js +1 -1
- package/traits/ripple.test.js +1 -1
- package/traits/roving-tabindex.test.js +1 -1
- package/traits/scale-press.test.js +1 -1
- package/traits/scroll-lock.test.js +1 -1
- package/traits/scroll-progress.js +201 -0
- package/traits/scroll-progress.test.js +182 -0
- package/traits/shimmer-loading.js +1 -1
- package/traits/shimmer-loading.test.js +1 -1
- package/traits/{_smoke.test.js → smoke.test.js} +1 -1
- package/traits/snap-to-grid.test.js +1 -1
- package/traits/sound-feedback.test.js +1 -1
- package/traits/spring-animate.test.js +1 -1
- package/traits/success-checkmark.js +222 -0
- package/traits/success-checkmark.test.js +120 -0
- package/traits/tilt-hover.js +1 -1
- package/traits/tilt-hover.test.js +1 -1
- package/traits/tossable.js +9 -0
- package/traits/tossable.test.js +1 -1
- package/traits/traits-host.test.js +1 -1
- package/traits/typeahead.test.js +1 -1
- package/traits/typewriter.js +1 -1
- package/traits/typewriter.test.js +1 -1
- package/traits/validation.test.js +1 -1
- package/traits/view-transition.js +140 -0
- package/traits/view-transition.test.js +268 -0
- /package/traits/{_motion.js → motion.js} +0 -0
- /package/traits/{_test-helpers.js → test-helpers.js} +0 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { focusRestore } from './focus-restore.js';
|
|
3
|
+
import { mountHost, connectTrait, spyEvent, resetDOM } from './test-helpers.js';
|
|
4
|
+
|
|
5
|
+
function focusableTrigger(label = 'Trigger') {
|
|
6
|
+
const btn = document.createElement('button');
|
|
7
|
+
btn.textContent = label;
|
|
8
|
+
document.body.appendChild(btn);
|
|
9
|
+
return btn;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function focusableChild(host, label = 'child', tag = 'button') {
|
|
13
|
+
const el = document.createElement(tag);
|
|
14
|
+
el.textContent = label;
|
|
15
|
+
if (tag !== 'button') el.setAttribute('tabindex', '0');
|
|
16
|
+
host.appendChild(el);
|
|
17
|
+
return el;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('focus-restore', () => {
|
|
21
|
+
beforeEach(resetDOM);
|
|
22
|
+
|
|
23
|
+
it('connect sets data-focus-restore-active', () => {
|
|
24
|
+
const host = mountHost();
|
|
25
|
+
connectTrait(focusRestore, host);
|
|
26
|
+
expect(host.hasAttribute('data-focus-restore-active')).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('disconnect clears data-focus-restore-active', () => {
|
|
30
|
+
const host = mountHost();
|
|
31
|
+
const inst = connectTrait(focusRestore, host);
|
|
32
|
+
inst.disconnect(host);
|
|
33
|
+
expect(host.hasAttribute('data-focus-restore-active')).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('captures activeElement on connect and restores it on disconnect', () => {
|
|
37
|
+
const trigger = focusableTrigger('Open');
|
|
38
|
+
trigger.focus();
|
|
39
|
+
expect(document.activeElement).toBe(trigger);
|
|
40
|
+
|
|
41
|
+
const host = mountHost();
|
|
42
|
+
const inst = connectTrait(focusRestore, host);
|
|
43
|
+
|
|
44
|
+
// Some other element steals focus while the surface is open.
|
|
45
|
+
const distract = focusableTrigger('Distract');
|
|
46
|
+
distract.focus();
|
|
47
|
+
expect(document.activeElement).toBe(distract);
|
|
48
|
+
|
|
49
|
+
inst.disconnect(host);
|
|
50
|
+
|
|
51
|
+
// Focus snaps back to the originally-captured trigger.
|
|
52
|
+
expect(document.activeElement).toBe(trigger);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('falls back to body when the captured target is removed from DOM', () => {
|
|
56
|
+
const trigger = focusableTrigger('Will be removed');
|
|
57
|
+
trigger.focus();
|
|
58
|
+
|
|
59
|
+
const host = mountHost();
|
|
60
|
+
const inst = connectTrait(focusRestore, host);
|
|
61
|
+
|
|
62
|
+
// Trigger gets nuked while the surface is open — common pattern when
|
|
63
|
+
// the container that opened the modal re-renders.
|
|
64
|
+
trigger.remove();
|
|
65
|
+
expect(trigger.isConnected).toBe(false);
|
|
66
|
+
|
|
67
|
+
inst.disconnect(host);
|
|
68
|
+
|
|
69
|
+
// Restore must not throw. Focus lands on body (or null) — never the
|
|
70
|
+
// removed trigger. The contract is "don't dangle" not "always lands".
|
|
71
|
+
expect(document.activeElement).not.toBe(trigger);
|
|
72
|
+
expect(document.activeElement === document.body || document.activeElement === null).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('falls back when captured target is disabled', () => {
|
|
76
|
+
const trigger = focusableTrigger('Will be disabled');
|
|
77
|
+
trigger.focus();
|
|
78
|
+
|
|
79
|
+
const host = mountHost();
|
|
80
|
+
const inst = connectTrait(focusRestore, host);
|
|
81
|
+
|
|
82
|
+
// Trigger gets disabled while surface is open.
|
|
83
|
+
trigger.setAttribute('disabled', '');
|
|
84
|
+
|
|
85
|
+
inst.disconnect(host);
|
|
86
|
+
|
|
87
|
+
// Disabled element shouldn't receive focus — fallback path engages.
|
|
88
|
+
expect(document.activeElement).not.toBe(trigger);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('dispatches focus-restored on disconnect with detail.restoredTo + detail.capturedTarget', () => {
|
|
92
|
+
const trigger = focusableTrigger('Open');
|
|
93
|
+
trigger.focus();
|
|
94
|
+
|
|
95
|
+
const host = mountHost();
|
|
96
|
+
const inst = connectTrait(focusRestore, host);
|
|
97
|
+
const spy = spyEvent(host, 'focus-restored');
|
|
98
|
+
|
|
99
|
+
inst.disconnect(host);
|
|
100
|
+
|
|
101
|
+
expect(spy.count).toBe(1);
|
|
102
|
+
expect(spy.last.capturedTarget).toBe(trigger);
|
|
103
|
+
expect(spy.last.restoredTo).toBe(trigger);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('data-focus-restore-on-mount="none" (default): does NOT move focus on connect', () => {
|
|
107
|
+
const trigger = focusableTrigger('Stay focused');
|
|
108
|
+
trigger.focus();
|
|
109
|
+
|
|
110
|
+
const host = mountHost();
|
|
111
|
+
focusableChild(host, 'inside');
|
|
112
|
+
connectTrait(focusRestore, host);
|
|
113
|
+
|
|
114
|
+
// Default behavior — captures, doesn't move focus.
|
|
115
|
+
expect(document.activeElement).toBe(trigger);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('data-focus-restore-on-mount="host": moves focus to the host on connect', () => {
|
|
119
|
+
const trigger = focusableTrigger('Open');
|
|
120
|
+
trigger.focus();
|
|
121
|
+
|
|
122
|
+
const host = mountHost('div', {
|
|
123
|
+
tabindex: '-1',
|
|
124
|
+
'data-focus-restore-on-mount': 'host',
|
|
125
|
+
});
|
|
126
|
+
connectTrait(focusRestore, host);
|
|
127
|
+
|
|
128
|
+
expect(document.activeElement).toBe(host);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('data-focus-restore-on-mount="first-focusable": focuses first tabbable descendant', () => {
|
|
132
|
+
const trigger = focusableTrigger('Open');
|
|
133
|
+
trigger.focus();
|
|
134
|
+
|
|
135
|
+
const host = mountHost('div', {
|
|
136
|
+
'data-focus-restore-on-mount': 'first-focusable',
|
|
137
|
+
});
|
|
138
|
+
const first = focusableChild(host, 'First');
|
|
139
|
+
focusableChild(host, 'Second');
|
|
140
|
+
connectTrait(focusRestore, host);
|
|
141
|
+
|
|
142
|
+
expect(document.activeElement).toBe(first);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('first-focusable: skips disabled descendants', () => {
|
|
146
|
+
const trigger = focusableTrigger('Open');
|
|
147
|
+
trigger.focus();
|
|
148
|
+
|
|
149
|
+
const host = mountHost('div', {
|
|
150
|
+
'data-focus-restore-on-mount': 'first-focusable',
|
|
151
|
+
});
|
|
152
|
+
const disabled = focusableChild(host, 'Disabled');
|
|
153
|
+
disabled.setAttribute('disabled', '');
|
|
154
|
+
const enabled = focusableChild(host, 'Enabled');
|
|
155
|
+
connectTrait(focusRestore, host);
|
|
156
|
+
|
|
157
|
+
expect(document.activeElement).toBe(enabled);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('on-mount captures BEFORE moving focus, so disconnect restores correctly', () => {
|
|
161
|
+
// Regression guard: the trait must capture activeElement before
|
|
162
|
+
// its own focus shift, otherwise disconnect would restore to the
|
|
163
|
+
// host (or first child), not the original trigger.
|
|
164
|
+
const trigger = focusableTrigger('Open');
|
|
165
|
+
trigger.focus();
|
|
166
|
+
|
|
167
|
+
const host = mountHost('div', {
|
|
168
|
+
tabindex: '-1',
|
|
169
|
+
'data-focus-restore-on-mount': 'host',
|
|
170
|
+
});
|
|
171
|
+
const inst = connectTrait(focusRestore, host);
|
|
172
|
+
expect(document.activeElement).toBe(host);
|
|
173
|
+
|
|
174
|
+
inst.disconnect(host);
|
|
175
|
+
expect(document.activeElement).toBe(trigger);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('connect → disconnect → connect cycle works', () => {
|
|
179
|
+
const trigger = focusableTrigger('Reusable');
|
|
180
|
+
trigger.focus();
|
|
181
|
+
|
|
182
|
+
const host = mountHost();
|
|
183
|
+
const inst1 = connectTrait(focusRestore, host);
|
|
184
|
+
inst1.disconnect(host);
|
|
185
|
+
expect(document.activeElement).toBe(trigger);
|
|
186
|
+
|
|
187
|
+
// Refocus and run again — fresh capture, fresh restore.
|
|
188
|
+
const trigger2 = focusableTrigger('Different trigger');
|
|
189
|
+
trigger2.focus();
|
|
190
|
+
const inst2 = connectTrait(focusRestore, host);
|
|
191
|
+
inst2.disconnect(host);
|
|
192
|
+
expect(document.activeElement).toBe(trigger2);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('schema declares the documented contract', () => {
|
|
196
|
+
expect(focusRestore.schema.name).toBe('focus-restore');
|
|
197
|
+
expect(focusRestore.schema.category).toBe('keyboard-navigation');
|
|
198
|
+
expect(focusRestore.schema.attributes).toContain('data-focus-restore-active');
|
|
199
|
+
expect(focusRestore.schema.events).toContain('focus-restored');
|
|
200
|
+
expect(focusRestore.schema.config).toContain('data-focus-restore-on-mount');
|
|
201
|
+
});
|
|
202
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { focusTrap } from './focus-trap.js';
|
|
3
|
-
import { mountHost, connectTrait, spyEvent, resetDOM } from './
|
|
3
|
+
import { mountHost, connectTrait, spyEvent, resetDOM } from './test-helpers.js';
|
|
4
4
|
|
|
5
5
|
function focusableChild(host, label) {
|
|
6
6
|
const btn = document.createElement('button');
|
package/traits/focusable.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { focusable } from './focusable.js';
|
|
3
|
-
import { mountHost, connectTrait, resetDOM } from './
|
|
3
|
+
import { mountHost, connectTrait, resetDOM } from './test-helpers.js';
|
|
4
4
|
|
|
5
5
|
describe('focusable', () => {
|
|
6
6
|
beforeEach(resetDOM);
|
package/traits/glow-focus.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { glowFocus } from './glow-focus.js';
|
|
3
|
-
import { mountHost, connectTrait, resetDOM } from './
|
|
3
|
+
import { mountHost, connectTrait, resetDOM } from './test-helpers.js';
|
|
4
4
|
|
|
5
5
|
describe('glow-focus', () => {
|
|
6
6
|
beforeEach(resetDOM);
|
package/traits/gradient-shift.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { gradientShift } from './gradient-shift.js';
|
|
3
|
-
import { mountHost, connectTrait, resetDOM } from './
|
|
3
|
+
import { mountHost, connectTrait, resetDOM } from './test-helpers.js';
|
|
4
4
|
|
|
5
5
|
describe('gradient-shift', () => {
|
|
6
6
|
beforeEach(resetDOM);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
|
2
2
|
import { hapticFeedback } from './haptic-feedback.js';
|
|
3
|
-
import { mountHost, connectTrait, resetDOM } from './
|
|
3
|
+
import { mountHost, connectTrait, resetDOM } from './test-helpers.js';
|
|
4
4
|
|
|
5
5
|
describe('haptic-feedback', () => {
|
|
6
6
|
let originalVibrate;
|
package/traits/hotkey.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { hotkey } from './hotkey.js';
|
|
3
|
-
import { mountHost, connectTrait, spyEvent, resetDOM } from './
|
|
3
|
+
import { mountHost, connectTrait, spyEvent, resetDOM } from './test-helpers.js';
|
|
4
4
|
|
|
5
5
|
describe('hotkey', () => {
|
|
6
6
|
beforeEach(resetDOM);
|
package/traits/hoverable.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { hoverable } from './hoverable.js';
|
|
3
|
-
import { mountHost, connectTrait, resetDOM } from './
|
|
3
|
+
import { mountHost, connectTrait, resetDOM } from './test-helpers.js';
|
|
4
4
|
|
|
5
5
|
describe('hoverable', () => {
|
|
6
6
|
beforeEach(resetDOM);
|
package/traits/index.js
CHANGED
|
@@ -13,6 +13,9 @@ export { pressable } from './pressable.js';
|
|
|
13
13
|
export { focusable } from './focusable.js';
|
|
14
14
|
export { hoverable } from './hoverable.js';
|
|
15
15
|
export { activeState } from './active-state.js';
|
|
16
|
+
export { longPress } from './long-press.js';
|
|
17
|
+
export { droppable } from './droppable.js';
|
|
18
|
+
export { droppableCollection } from './droppable-collection.js';
|
|
16
19
|
|
|
17
20
|
// keyboard-navigation
|
|
18
21
|
export { keyboardNav } from './keyboard-nav.js';
|
|
@@ -20,11 +23,15 @@ export { rovingTabindex } from './roving-tabindex.js';
|
|
|
20
23
|
export { typeahead } from './typeahead.js';
|
|
21
24
|
export { hotkey } from './hotkey.js';
|
|
22
25
|
export { focusTrap } from './focus-trap.js';
|
|
26
|
+
export { focusRestore } from './focus-restore.js';
|
|
27
|
+
export { arrowGridNav } from './arrow-grid-nav.js';
|
|
28
|
+
export { keyboardReorderable } from './keyboard-reorderable.js';
|
|
23
29
|
|
|
24
30
|
// forms-data
|
|
25
31
|
export { validation } from './validation.js';
|
|
26
32
|
export { dirtyState } from './dirty-state.js';
|
|
27
33
|
export { resettable } from './resettable.js';
|
|
34
|
+
export { inputMask } from './input-mask.js';
|
|
28
35
|
|
|
29
36
|
// layout-measurement
|
|
30
37
|
export { resizeObserver } from './resize-observer.js';
|
|
@@ -32,6 +39,7 @@ export { intersectionObserver } from './intersection-observer.js';
|
|
|
32
39
|
export { anchorPositioning } from './anchor-positioning.js';
|
|
33
40
|
export { portal } from './portal.js';
|
|
34
41
|
export { scrollLock } from './scroll-lock.js';
|
|
42
|
+
export { scrollProgress } from './scroll-progress.js';
|
|
35
43
|
|
|
36
44
|
// motion-positioning
|
|
37
45
|
export { draggable } from './draggable.js';
|
|
@@ -40,6 +48,10 @@ export { resizable } from './resizable.js';
|
|
|
40
48
|
export { inertiaDrag } from './inertia-drag.js';
|
|
41
49
|
export { snapToGrid } from './snap-to-grid.js';
|
|
42
50
|
export { dragGhost } from './drag-ghost.js';
|
|
51
|
+
export { dropTarget } from './drop-target.js';
|
|
52
|
+
export { layoutAnimation } from './layout-animation.js';
|
|
53
|
+
export { viewTransition } from './view-transition.js';
|
|
54
|
+
export { draggableListItem } from './draggable-list-item.js';
|
|
43
55
|
|
|
44
56
|
// animation-feedback
|
|
45
57
|
export { ripple } from './ripple.js';
|
|
@@ -47,6 +59,8 @@ export { springAnimate } from './spring-animate.js';
|
|
|
47
59
|
export { fadePresence } from './fade-presence.js';
|
|
48
60
|
export { scalePress } from './scale-press.js';
|
|
49
61
|
export { tiltHover } from './tilt-hover.js';
|
|
62
|
+
export { errorShake } from './error-shake.js';
|
|
63
|
+
export { successCheckmark } from './success-checkmark.js';
|
|
50
64
|
|
|
51
65
|
// visual-dynamics
|
|
52
66
|
export { glowFocus } from './glow-focus.js';
|
|
@@ -66,3 +80,4 @@ export { hapticFeedback } from './haptic-feedback.js';
|
|
|
66
80
|
export { typewriter } from './typewriter.js';
|
|
67
81
|
export { countUp } from './count-up.js';
|
|
68
82
|
export { attentionPulse } from './attention-pulse.js';
|
|
83
|
+
export { announcer } from './announcer.js';
|
package/traits/inertia-drag.js
CHANGED
|
@@ -27,7 +27,16 @@ export const inertiaDrag = defineTrait({
|
|
|
27
27
|
let lastClientY = 0;
|
|
28
28
|
|
|
29
29
|
function parseTranslate() {
|
|
30
|
+
// The trait writes to `style.translate` (independent of `transform` in
|
|
31
|
+
// the modern CSS model). Read translate first so subsequent drags pick
|
|
32
|
+
// up the current position, then fall back to the transform matrix for
|
|
33
|
+
// callers that nudged via `transform`.
|
|
30
34
|
const style = getComputedStyle(host);
|
|
35
|
+
const t = style.translate;
|
|
36
|
+
if (t && t !== 'none') {
|
|
37
|
+
const parts = t.split(/\s+/).map(parseFloat);
|
|
38
|
+
return { x: parts[0] || 0, y: parts[1] || 0 };
|
|
39
|
+
}
|
|
31
40
|
const matrix = new DOMMatrixReadOnly(style.transform);
|
|
32
41
|
return { x: matrix.m41, y: matrix.m42 };
|
|
33
42
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { inertiaDrag } from './inertia-drag.js';
|
|
3
|
-
import { mountHost, connectTrait, resetDOM } from './
|
|
3
|
+
import { mountHost, connectTrait, resetDOM } from './test-helpers.js';
|
|
4
4
|
|
|
5
5
|
function pointer(host, type, x, y) {
|
|
6
6
|
host.dispatchEvent(new PointerEvent(type, { clientX: x, clientY: y, pointerId: 1, bubbles: true }));
|