@present-day/reveal-row 0.1.2 → 0.1.6
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/README.md +3 -0
- package/dist/index.d.mts +41 -4
- package/dist/index.d.ts +41 -4
- package/dist/index.js +172 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +169 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Horizontally scrollable row that reveals one or two action columns — **right**, **left**, or **both** sides. Three snap positions: left · center · right. Styling is entirely via `classNames` props (no bundled CSS). Scroll physics use inline `style` on the scroll track so the component works with zero external CSS.
|
|
4
4
|
|
|
5
|
+
<img width="295" height="640" alt="Simulator Screen Recording - iPhone 15 - 2026-04-25 at 22 26 41" src="https://github.com/user-attachments/assets/932021d4-5224-479f-9df9-c7045bf12afb" style="float:right" />
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
## Install
|
|
6
9
|
|
|
7
10
|
```bash
|
package/dist/index.d.mts
CHANGED
|
@@ -18,6 +18,29 @@ declare const REVEAL_HANDLE_POSITION: {
|
|
|
18
18
|
readonly end: "end";
|
|
19
19
|
};
|
|
20
20
|
type RevealHandlePosition = (typeof REVEAL_HANDLE_POSITION)[keyof typeof REVEAL_HANDLE_POSITION];
|
|
21
|
+
declare const REVEAL_ROW_ELEMENTS: {
|
|
22
|
+
readonly div: "div";
|
|
23
|
+
readonly section: "section";
|
|
24
|
+
readonly article: "article";
|
|
25
|
+
readonly main: "main";
|
|
26
|
+
readonly aside: "aside";
|
|
27
|
+
readonly header: "header";
|
|
28
|
+
readonly footer: "footer";
|
|
29
|
+
readonly nav: "nav";
|
|
30
|
+
readonly li: "li";
|
|
31
|
+
};
|
|
32
|
+
type RevealRowElement = (typeof REVEAL_ROW_ELEMENTS)[keyof typeof REVEAL_ROW_ELEMENTS];
|
|
33
|
+
declare const ANIMATION_PRESET: {
|
|
34
|
+
readonly none: "none";
|
|
35
|
+
readonly quick: "quick";
|
|
36
|
+
readonly smooth: "smooth";
|
|
37
|
+
};
|
|
38
|
+
type AnimationPreset = (typeof ANIMATION_PRESET)[keyof typeof ANIMATION_PRESET];
|
|
39
|
+
type AnimationConfig = {
|
|
40
|
+
duration: number;
|
|
41
|
+
easing: string;
|
|
42
|
+
};
|
|
43
|
+
declare const ANIMATION_PRESETS: Record<AnimationPreset, AnimationConfig>;
|
|
21
44
|
type RevealRowClassNames = {
|
|
22
45
|
root?: string;
|
|
23
46
|
main?: string;
|
|
@@ -28,8 +51,8 @@ type RevealRowClassNames = {
|
|
|
28
51
|
handleIcon?: string;
|
|
29
52
|
};
|
|
30
53
|
type RevealRowHandle = {
|
|
31
|
-
close: () => void;
|
|
32
|
-
reveal: (position: RevealPosition) => void;
|
|
54
|
+
close: (animated?: boolean | AnimationPreset | AnimationConfig) => void;
|
|
55
|
+
reveal: (position: RevealPosition, animated?: boolean | AnimationPreset | AnimationConfig) => void;
|
|
33
56
|
};
|
|
34
57
|
type RevealRowProps = {
|
|
35
58
|
/** Primary row content (e.g. title, subtitle). */
|
|
@@ -40,6 +63,11 @@ type RevealRowProps = {
|
|
|
40
63
|
* Trailing action column (e.g. add). Omitted in `left` mode.
|
|
41
64
|
*/
|
|
42
65
|
right?: ReactNode;
|
|
66
|
+
/**
|
|
67
|
+
* The HTML element to use for the root container.
|
|
68
|
+
* @default 'div'
|
|
69
|
+
*/
|
|
70
|
+
as?: RevealRowElement;
|
|
43
71
|
/**
|
|
44
72
|
* If both `left` and `right` are set, defaults to `both`. If only one side,
|
|
45
73
|
* mode is derived unless overridden.
|
|
@@ -62,7 +90,7 @@ type RevealRowProps = {
|
|
|
62
90
|
handleAriaLabel?: string;
|
|
63
91
|
/** Fires when the settled position changes. */
|
|
64
92
|
onRevealChange?: (position: RevealPosition) => void;
|
|
65
|
-
onScroll?: (event: UIEvent<
|
|
93
|
+
onScroll?: (event: UIEvent<HTMLElement>) => void;
|
|
66
94
|
/** Resets to closed; default true. */
|
|
67
95
|
resetWhenDisabled?: boolean;
|
|
68
96
|
disabled?: boolean;
|
|
@@ -73,6 +101,15 @@ type RevealRowProps = {
|
|
|
73
101
|
isActive?: boolean;
|
|
74
102
|
className?: string;
|
|
75
103
|
style?: CSSProperties;
|
|
104
|
+
/**
|
|
105
|
+
* Default animation preset for close/reveal animations when action buttons are clicked.
|
|
106
|
+
* @default 'quick'
|
|
107
|
+
*/
|
|
108
|
+
animationPreset?: AnimationPreset;
|
|
109
|
+
/**
|
|
110
|
+
* Custom animation configuration overriding the preset.
|
|
111
|
+
*/
|
|
112
|
+
animationConfig?: AnimationConfig;
|
|
76
113
|
};
|
|
77
114
|
|
|
78
115
|
/**
|
|
@@ -86,4 +123,4 @@ declare function getScrollClosed(wL: number, _wR: number, _maxScroll: number, mo
|
|
|
86
123
|
|
|
87
124
|
declare const RevealRow: react.ForwardRefExoticComponent<RevealRowProps & react.RefAttributes<RevealRowHandle>>;
|
|
88
125
|
|
|
89
|
-
export { REVEAL_HANDLE_POSITION, REVEAL_MODE, REVEAL_POSITION, type RevealHandlePosition, type RevealMode, type RevealPosition, RevealRow, type RevealRowClassNames, type RevealRowHandle, type RevealRowProps, getRevealFromScroll, getScrollClosed };
|
|
126
|
+
export { ANIMATION_PRESET, ANIMATION_PRESETS, type AnimationConfig, type AnimationPreset, REVEAL_HANDLE_POSITION, REVEAL_MODE, REVEAL_POSITION, REVEAL_ROW_ELEMENTS, type RevealHandlePosition, type RevealMode, type RevealPosition, RevealRow, type RevealRowClassNames, type RevealRowElement, type RevealRowHandle, type RevealRowProps, getRevealFromScroll, getScrollClosed };
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,29 @@ declare const REVEAL_HANDLE_POSITION: {
|
|
|
18
18
|
readonly end: "end";
|
|
19
19
|
};
|
|
20
20
|
type RevealHandlePosition = (typeof REVEAL_HANDLE_POSITION)[keyof typeof REVEAL_HANDLE_POSITION];
|
|
21
|
+
declare const REVEAL_ROW_ELEMENTS: {
|
|
22
|
+
readonly div: "div";
|
|
23
|
+
readonly section: "section";
|
|
24
|
+
readonly article: "article";
|
|
25
|
+
readonly main: "main";
|
|
26
|
+
readonly aside: "aside";
|
|
27
|
+
readonly header: "header";
|
|
28
|
+
readonly footer: "footer";
|
|
29
|
+
readonly nav: "nav";
|
|
30
|
+
readonly li: "li";
|
|
31
|
+
};
|
|
32
|
+
type RevealRowElement = (typeof REVEAL_ROW_ELEMENTS)[keyof typeof REVEAL_ROW_ELEMENTS];
|
|
33
|
+
declare const ANIMATION_PRESET: {
|
|
34
|
+
readonly none: "none";
|
|
35
|
+
readonly quick: "quick";
|
|
36
|
+
readonly smooth: "smooth";
|
|
37
|
+
};
|
|
38
|
+
type AnimationPreset = (typeof ANIMATION_PRESET)[keyof typeof ANIMATION_PRESET];
|
|
39
|
+
type AnimationConfig = {
|
|
40
|
+
duration: number;
|
|
41
|
+
easing: string;
|
|
42
|
+
};
|
|
43
|
+
declare const ANIMATION_PRESETS: Record<AnimationPreset, AnimationConfig>;
|
|
21
44
|
type RevealRowClassNames = {
|
|
22
45
|
root?: string;
|
|
23
46
|
main?: string;
|
|
@@ -28,8 +51,8 @@ type RevealRowClassNames = {
|
|
|
28
51
|
handleIcon?: string;
|
|
29
52
|
};
|
|
30
53
|
type RevealRowHandle = {
|
|
31
|
-
close: () => void;
|
|
32
|
-
reveal: (position: RevealPosition) => void;
|
|
54
|
+
close: (animated?: boolean | AnimationPreset | AnimationConfig) => void;
|
|
55
|
+
reveal: (position: RevealPosition, animated?: boolean | AnimationPreset | AnimationConfig) => void;
|
|
33
56
|
};
|
|
34
57
|
type RevealRowProps = {
|
|
35
58
|
/** Primary row content (e.g. title, subtitle). */
|
|
@@ -40,6 +63,11 @@ type RevealRowProps = {
|
|
|
40
63
|
* Trailing action column (e.g. add). Omitted in `left` mode.
|
|
41
64
|
*/
|
|
42
65
|
right?: ReactNode;
|
|
66
|
+
/**
|
|
67
|
+
* The HTML element to use for the root container.
|
|
68
|
+
* @default 'div'
|
|
69
|
+
*/
|
|
70
|
+
as?: RevealRowElement;
|
|
43
71
|
/**
|
|
44
72
|
* If both `left` and `right` are set, defaults to `both`. If only one side,
|
|
45
73
|
* mode is derived unless overridden.
|
|
@@ -62,7 +90,7 @@ type RevealRowProps = {
|
|
|
62
90
|
handleAriaLabel?: string;
|
|
63
91
|
/** Fires when the settled position changes. */
|
|
64
92
|
onRevealChange?: (position: RevealPosition) => void;
|
|
65
|
-
onScroll?: (event: UIEvent<
|
|
93
|
+
onScroll?: (event: UIEvent<HTMLElement>) => void;
|
|
66
94
|
/** Resets to closed; default true. */
|
|
67
95
|
resetWhenDisabled?: boolean;
|
|
68
96
|
disabled?: boolean;
|
|
@@ -73,6 +101,15 @@ type RevealRowProps = {
|
|
|
73
101
|
isActive?: boolean;
|
|
74
102
|
className?: string;
|
|
75
103
|
style?: CSSProperties;
|
|
104
|
+
/**
|
|
105
|
+
* Default animation preset for close/reveal animations when action buttons are clicked.
|
|
106
|
+
* @default 'quick'
|
|
107
|
+
*/
|
|
108
|
+
animationPreset?: AnimationPreset;
|
|
109
|
+
/**
|
|
110
|
+
* Custom animation configuration overriding the preset.
|
|
111
|
+
*/
|
|
112
|
+
animationConfig?: AnimationConfig;
|
|
76
113
|
};
|
|
77
114
|
|
|
78
115
|
/**
|
|
@@ -86,4 +123,4 @@ declare function getScrollClosed(wL: number, _wR: number, _maxScroll: number, mo
|
|
|
86
123
|
|
|
87
124
|
declare const RevealRow: react.ForwardRefExoticComponent<RevealRowProps & react.RefAttributes<RevealRowHandle>>;
|
|
88
125
|
|
|
89
|
-
export { REVEAL_HANDLE_POSITION, REVEAL_MODE, REVEAL_POSITION, type RevealHandlePosition, type RevealMode, type RevealPosition, RevealRow, type RevealRowClassNames, type RevealRowHandle, type RevealRowProps, getRevealFromScroll, getScrollClosed };
|
|
126
|
+
export { ANIMATION_PRESET, ANIMATION_PRESETS, type AnimationConfig, type AnimationPreset, REVEAL_HANDLE_POSITION, REVEAL_MODE, REVEAL_POSITION, REVEAL_ROW_ELEMENTS, type RevealHandlePosition, type RevealMode, type RevealPosition, RevealRow, type RevealRowClassNames, type RevealRowElement, type RevealRowHandle, type RevealRowProps, getRevealFromScroll, getScrollClosed };
|
package/dist/index.js
CHANGED
|
@@ -20,9 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ANIMATION_PRESET: () => ANIMATION_PRESET,
|
|
24
|
+
ANIMATION_PRESETS: () => ANIMATION_PRESETS,
|
|
23
25
|
REVEAL_HANDLE_POSITION: () => REVEAL_HANDLE_POSITION,
|
|
24
26
|
REVEAL_MODE: () => REVEAL_MODE,
|
|
25
27
|
REVEAL_POSITION: () => REVEAL_POSITION,
|
|
28
|
+
REVEAL_ROW_ELEMENTS: () => REVEAL_ROW_ELEMENTS,
|
|
26
29
|
RevealRow: () => RevealRow,
|
|
27
30
|
getRevealFromScroll: () => getRevealFromScroll,
|
|
28
31
|
getScrollClosed: () => getScrollClosed
|
|
@@ -44,6 +47,27 @@ var REVEAL_HANDLE_POSITION = {
|
|
|
44
47
|
start: "start",
|
|
45
48
|
end: "end"
|
|
46
49
|
};
|
|
50
|
+
var REVEAL_ROW_ELEMENTS = {
|
|
51
|
+
div: "div",
|
|
52
|
+
section: "section",
|
|
53
|
+
article: "article",
|
|
54
|
+
main: "main",
|
|
55
|
+
aside: "aside",
|
|
56
|
+
header: "header",
|
|
57
|
+
footer: "footer",
|
|
58
|
+
nav: "nav",
|
|
59
|
+
li: "li"
|
|
60
|
+
};
|
|
61
|
+
var ANIMATION_PRESET = {
|
|
62
|
+
none: "none",
|
|
63
|
+
quick: "quick",
|
|
64
|
+
smooth: "smooth"
|
|
65
|
+
};
|
|
66
|
+
var ANIMATION_PRESETS = {
|
|
67
|
+
[ANIMATION_PRESET.none]: { duration: 0, easing: "linear" },
|
|
68
|
+
[ANIMATION_PRESET.quick]: { duration: 200, easing: "ease-out" },
|
|
69
|
+
[ANIMATION_PRESET.smooth]: { duration: 400, easing: "ease-in-out" }
|
|
70
|
+
};
|
|
47
71
|
|
|
48
72
|
// src/getRevealFromScroll.ts
|
|
49
73
|
function getRevealFromScroll(scrollLeft, maxScroll, wL, wR, mode) {
|
|
@@ -106,6 +130,25 @@ function resolveMode(left, right, mode) {
|
|
|
106
130
|
if (left != null) return REVEAL_MODE.left;
|
|
107
131
|
return REVEAL_MODE.right;
|
|
108
132
|
}
|
|
133
|
+
function resolveAnimationConfig(animated, defaultPreset, customConfig) {
|
|
134
|
+
let config;
|
|
135
|
+
if (animated === false) {
|
|
136
|
+
config = ANIMATION_PRESETS[ANIMATION_PRESET.none];
|
|
137
|
+
} else if (animated === true || animated === void 0) {
|
|
138
|
+
config = customConfig || ANIMATION_PRESETS[defaultPreset];
|
|
139
|
+
} else if (typeof animated === "string") {
|
|
140
|
+
config = ANIMATION_PRESETS[animated];
|
|
141
|
+
} else {
|
|
142
|
+
config = animated;
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
...config,
|
|
146
|
+
duration: Math.max(
|
|
147
|
+
0,
|
|
148
|
+
Number.isFinite(config.duration) ? config.duration : 0
|
|
149
|
+
)
|
|
150
|
+
};
|
|
151
|
+
}
|
|
109
152
|
var SCROLL_REVEAL_DEBOUNCE_MS = 64;
|
|
110
153
|
var restEpsilon = 2;
|
|
111
154
|
var rootScrollStyle = {
|
|
@@ -117,12 +160,18 @@ var rootScrollStyle = {
|
|
|
117
160
|
overscrollBehaviorX: "contain",
|
|
118
161
|
touchAction: "pan-x pan-y"
|
|
119
162
|
};
|
|
163
|
+
var rootScrollStyleDisabled = {
|
|
164
|
+
...rootScrollStyle,
|
|
165
|
+
overflowX: "hidden",
|
|
166
|
+
touchAction: "pan-y"
|
|
167
|
+
};
|
|
120
168
|
var snapStart = { scrollSnapAlign: "start" };
|
|
121
169
|
var snapEnd = { scrollSnapAlign: "end" };
|
|
122
170
|
function RevealRowInner({
|
|
123
171
|
children,
|
|
124
172
|
left,
|
|
125
173
|
right,
|
|
174
|
+
as: Element = "div",
|
|
126
175
|
mode: modeProp,
|
|
127
176
|
actionWidthLeft: wLIn,
|
|
128
177
|
actionWidthRight: wRIn,
|
|
@@ -139,6 +188,8 @@ function RevealRowInner({
|
|
|
139
188
|
isActive = false,
|
|
140
189
|
className,
|
|
141
190
|
style,
|
|
191
|
+
animationPreset = ANIMATION_PRESET.quick,
|
|
192
|
+
animationConfig,
|
|
142
193
|
forwardedRef
|
|
143
194
|
}) {
|
|
144
195
|
const mode = resolveMode(left, right, modeProp);
|
|
@@ -154,6 +205,9 @@ function RevealRowInner({
|
|
|
154
205
|
const swipedRef = (0, import_react.useRef)(false);
|
|
155
206
|
const debounceTimer = (0, import_react.useRef)(null);
|
|
156
207
|
const hasAppliedInitialScroll = (0, import_react.useRef)(false);
|
|
208
|
+
const isAnimatingRef = (0, import_react.useRef)(false);
|
|
209
|
+
const rafIdRef = (0, import_react.useRef)(null);
|
|
210
|
+
const settleTimerRef = (0, import_react.useRef)(null);
|
|
157
211
|
const readPosition = (0, import_react.useCallback)(() => {
|
|
158
212
|
const el = containerRef.current;
|
|
159
213
|
if (!el) return REVEAL_POSITION.center;
|
|
@@ -174,36 +228,129 @@ function RevealRowInner({
|
|
|
174
228
|
const closed = getScrollClosed(wL, wR, m, mode);
|
|
175
229
|
el.scrollLeft = closed;
|
|
176
230
|
}, [wL, wR, mode]);
|
|
231
|
+
const scrollToPosition = (0, import_react.useCallback)(
|
|
232
|
+
(targetScrollLeft, animationOptions) => {
|
|
233
|
+
const el = containerRef.current;
|
|
234
|
+
if (!el) return;
|
|
235
|
+
const { duration, easing } = animationOptions;
|
|
236
|
+
if (duration === 0) {
|
|
237
|
+
el.scrollLeft = targetScrollLeft;
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (rafIdRef.current !== null) {
|
|
241
|
+
cancelAnimationFrame(rafIdRef.current);
|
|
242
|
+
rafIdRef.current = null;
|
|
243
|
+
}
|
|
244
|
+
if (settleTimerRef.current !== null) {
|
|
245
|
+
clearTimeout(settleTimerRef.current);
|
|
246
|
+
settleTimerRef.current = null;
|
|
247
|
+
}
|
|
248
|
+
isAnimatingRef.current = true;
|
|
249
|
+
const originalScrollSnapType = el.style.scrollSnapType;
|
|
250
|
+
el.style.scrollSnapType = "none";
|
|
251
|
+
const startScrollLeft = el.scrollLeft;
|
|
252
|
+
const distance = targetScrollLeft - startScrollLeft;
|
|
253
|
+
const startTime = performance.now();
|
|
254
|
+
const animate = (currentTime) => {
|
|
255
|
+
const elapsed = currentTime - startTime;
|
|
256
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
257
|
+
let easedProgress = progress;
|
|
258
|
+
if (easing === "ease-out") {
|
|
259
|
+
easedProgress = 1 - (1 - progress) ** 2;
|
|
260
|
+
} else if (easing === "ease-in-out") {
|
|
261
|
+
easedProgress = progress < 0.5 ? 2 * progress * progress : 1 - (-2 * progress + 2) ** 2 / 2;
|
|
262
|
+
} else if (easing.startsWith("cubic-bezier")) {
|
|
263
|
+
easedProgress = progress * progress * (3 - 2 * progress);
|
|
264
|
+
if (easing.includes("-0.55")) {
|
|
265
|
+
easedProgress = progress < 0.5 ? 4 * progress * progress * progress : 1 - (-2 * progress + 2) ** 3 / 2;
|
|
266
|
+
if (progress > 0.7 && progress < 1) {
|
|
267
|
+
easedProgress += Math.sin((progress - 0.7) * Math.PI * 10) * 0.1 * (1 - progress);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
el.scrollLeft = startScrollLeft + distance * easedProgress;
|
|
272
|
+
if (progress < 1) {
|
|
273
|
+
rafIdRef.current = requestAnimationFrame(animate);
|
|
274
|
+
} else {
|
|
275
|
+
el.scrollLeft = targetScrollLeft;
|
|
276
|
+
el.style.scrollSnapType = originalScrollSnapType || "x mandatory";
|
|
277
|
+
isAnimatingRef.current = false;
|
|
278
|
+
rafIdRef.current = null;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
rafIdRef.current = requestAnimationFrame(animate);
|
|
282
|
+
},
|
|
283
|
+
[]
|
|
284
|
+
);
|
|
177
285
|
(0, import_react.useImperativeHandle)(
|
|
178
286
|
forwardedRef,
|
|
179
287
|
() => ({
|
|
180
|
-
close: () => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
288
|
+
close: (animated) => {
|
|
289
|
+
const el = containerRef.current;
|
|
290
|
+
if (!el) return;
|
|
291
|
+
const m = getMaxScroll(el);
|
|
292
|
+
const closed = getScrollClosed(wL, wR, m, mode);
|
|
293
|
+
const animConfig = resolveAnimationConfig(
|
|
294
|
+
animated,
|
|
295
|
+
animationPreset,
|
|
296
|
+
animationConfig
|
|
297
|
+
);
|
|
298
|
+
scrollToPosition(closed, animConfig);
|
|
299
|
+
const delay = animConfig.duration > 0 ? animConfig.duration : 0;
|
|
300
|
+
if (settleTimerRef.current !== null) {
|
|
301
|
+
clearTimeout(settleTimerRef.current);
|
|
186
302
|
}
|
|
303
|
+
settleTimerRef.current = setTimeout(() => {
|
|
304
|
+
const p = readPosition();
|
|
305
|
+
if (lastEmitted.current !== p) {
|
|
306
|
+
lastEmitted.current = p;
|
|
307
|
+
onRevealChange?.(p);
|
|
308
|
+
}
|
|
309
|
+
settleTimerRef.current = null;
|
|
310
|
+
}, delay);
|
|
187
311
|
},
|
|
188
|
-
reveal: (position) => {
|
|
312
|
+
reveal: (position, animated) => {
|
|
189
313
|
const el = containerRef.current;
|
|
190
314
|
if (!el) return;
|
|
191
315
|
const max = getMaxScroll(el);
|
|
316
|
+
let targetScroll;
|
|
192
317
|
if (position === REVEAL_POSITION.center) {
|
|
193
|
-
|
|
318
|
+
targetScroll = getScrollClosed(wL, wR, max, mode);
|
|
194
319
|
} else if (position === REVEAL_POSITION.left && (mode === REVEAL_MODE.left || mode === REVEAL_MODE.both)) {
|
|
195
|
-
|
|
320
|
+
targetScroll = 0;
|
|
196
321
|
} else if (position === REVEAL_POSITION.right && (mode === REVEAL_MODE.right || mode === REVEAL_MODE.both)) {
|
|
197
|
-
|
|
322
|
+
targetScroll = max;
|
|
198
323
|
} else {
|
|
199
324
|
return;
|
|
200
325
|
}
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
326
|
+
const animConfig = resolveAnimationConfig(
|
|
327
|
+
animated,
|
|
328
|
+
animationPreset,
|
|
329
|
+
animationConfig
|
|
330
|
+
);
|
|
331
|
+
scrollToPosition(targetScroll, animConfig);
|
|
332
|
+
const delay = animConfig.duration > 0 ? animConfig.duration : 0;
|
|
333
|
+
if (settleTimerRef.current !== null) {
|
|
334
|
+
clearTimeout(settleTimerRef.current);
|
|
335
|
+
}
|
|
336
|
+
settleTimerRef.current = setTimeout(() => {
|
|
337
|
+
const p = getRevealFromScroll(targetScroll, max, wL, wR, mode);
|
|
338
|
+
lastEmitted.current = p;
|
|
339
|
+
onRevealChange?.(p);
|
|
340
|
+
settleTimerRef.current = null;
|
|
341
|
+
}, delay);
|
|
204
342
|
}
|
|
205
343
|
}),
|
|
206
|
-
[
|
|
344
|
+
[
|
|
345
|
+
mode,
|
|
346
|
+
onRevealChange,
|
|
347
|
+
readPosition,
|
|
348
|
+
scrollToPosition,
|
|
349
|
+
wL,
|
|
350
|
+
wR,
|
|
351
|
+
animationPreset,
|
|
352
|
+
animationConfig
|
|
353
|
+
]
|
|
207
354
|
);
|
|
208
355
|
(0, import_react.useLayoutEffect)(() => {
|
|
209
356
|
if (mode === REVEAL_MODE.right) {
|
|
@@ -235,6 +382,12 @@ function RevealRowInner({
|
|
|
235
382
|
if (debounceTimer.current) {
|
|
236
383
|
clearTimeout(debounceTimer.current);
|
|
237
384
|
}
|
|
385
|
+
if (rafIdRef.current !== null) {
|
|
386
|
+
cancelAnimationFrame(rafIdRef.current);
|
|
387
|
+
}
|
|
388
|
+
if (settleTimerRef.current !== null) {
|
|
389
|
+
clearTimeout(settleTimerRef.current);
|
|
390
|
+
}
|
|
238
391
|
},
|
|
239
392
|
[]
|
|
240
393
|
);
|
|
@@ -341,7 +494,7 @@ function RevealRowInner({
|
|
|
341
494
|
}
|
|
342
495
|
);
|
|
343
496
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
344
|
-
|
|
497
|
+
Element,
|
|
345
498
|
{
|
|
346
499
|
ref: containerRef,
|
|
347
500
|
"data-reveal-mode": mode,
|
|
@@ -349,7 +502,7 @@ function RevealRowInner({
|
|
|
349
502
|
onScroll: handleScroll,
|
|
350
503
|
onClickCapture,
|
|
351
504
|
style: {
|
|
352
|
-
...rootScrollStyle,
|
|
505
|
+
...disabled ? rootScrollStyleDisabled : rootScrollStyle,
|
|
353
506
|
...style,
|
|
354
507
|
gridTemplateColumns
|
|
355
508
|
},
|
|
@@ -386,9 +539,12 @@ var RevealRow = (0, import_react.forwardRef)(
|
|
|
386
539
|
);
|
|
387
540
|
// Annotate the CommonJS export names for ESM import in node:
|
|
388
541
|
0 && (module.exports = {
|
|
542
|
+
ANIMATION_PRESET,
|
|
543
|
+
ANIMATION_PRESETS,
|
|
389
544
|
REVEAL_HANDLE_POSITION,
|
|
390
545
|
REVEAL_MODE,
|
|
391
546
|
REVEAL_POSITION,
|
|
547
|
+
REVEAL_ROW_ELEMENTS,
|
|
392
548
|
RevealRow,
|
|
393
549
|
getRevealFromScroll,
|
|
394
550
|
getScrollClosed
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/getRevealFromScroll.ts","../src/RevealRow.tsx","../src/DefaultHandleIcon.tsx"],"sourcesContent":["export { getRevealFromScroll, getScrollClosed } from './getRevealFromScroll'\nexport { RevealRow } from './RevealRow'\nexport type {\n RevealHandlePosition,\n RevealMode,\n RevealPosition,\n RevealRowClassNames,\n RevealRowHandle,\n RevealRowProps,\n} from './types'\nexport {\n REVEAL_HANDLE_POSITION,\n REVEAL_MODE,\n REVEAL_POSITION,\n} from './types'\n","import type { CSSProperties, ReactNode, UIEvent } from 'react'\n\nexport const REVEAL_MODE = {\n left: 'left',\n right: 'right',\n both: 'both',\n} as const\n\nexport type RevealMode = (typeof REVEAL_MODE)[keyof typeof REVEAL_MODE]\n\nexport const REVEAL_POSITION = {\n left: 'left',\n center: 'center',\n right: 'right',\n} as const\n\nexport type RevealPosition =\n (typeof REVEAL_POSITION)[keyof typeof REVEAL_POSITION]\n\nexport const REVEAL_HANDLE_POSITION = {\n start: 'start',\n end: 'end',\n} as const\n\nexport type RevealHandlePosition =\n (typeof REVEAL_HANDLE_POSITION)[keyof typeof REVEAL_HANDLE_POSITION]\n\nexport type RevealRowClassNames = {\n root?: string\n main?: string\n mainInner?: string\n left?: string\n right?: string\n handleContainer?: string\n handleIcon?: string\n}\n\nexport type RevealRowHandle = {\n close: () => void\n reveal: (position: RevealPosition) => void\n}\n\nexport type RevealRowProps = {\n /** Primary row content (e.g. title, subtitle). */\n children: ReactNode\n /** Optional leading action column (e.g. delete). Omitted in `right` mode. */\n left?: ReactNode\n /**\n * Trailing action column (e.g. add). Omitted in `left` mode.\n */\n right?: ReactNode\n /**\n * If both `left` and `right` are set, defaults to `both`. If only one side,\n * mode is derived unless overridden.\n */\n mode?: RevealMode\n actionWidthLeft?: number\n actionWidthRight?: number\n classNames?: RevealRowClassNames\n /** @default true */\n showHandle?: boolean\n /** Replaces the built-in drag affordance. */\n handle?: ReactNode\n /**\n * Where the handle sits in the main row. Default: `start` in `left` mode,\n * `end` otherwise.\n */\n handlePosition?: RevealHandlePosition\n handleTitle?: string\n /** Shown in screen-reader text when using the default drag handle. */\n handleAriaLabel?: string\n /** Fires when the settled position changes. */\n onRevealChange?: (position: RevealPosition) => void\n onScroll?: (event: UIEvent<HTMLDivElement>) => void\n /** Resets to closed; default true. */\n resetWhenDisabled?: boolean\n disabled?: boolean\n /**\n * When true, snaps back to the closed position (e.g. row became active/selected\n * elsewhere in the list).\n */\n isActive?: boolean\n className?: string\n style?: CSSProperties\n}\n","import {\n REVEAL_MODE,\n REVEAL_POSITION,\n type RevealMode,\n type RevealPosition,\n} from './types'\n\n/**\n * Map horizontal scroll position to a logical \"revealed\" state.\n * `wL` / `wR` are the fixed action column widths; `maxScroll` is\n * `Math.max(0, scrollWidth - clientWidth)`.\n */\nexport function getRevealFromScroll(\n scrollLeft: number,\n maxScroll: number,\n wL: number,\n wR: number,\n mode: RevealMode,\n): RevealPosition {\n if (mode === REVEAL_MODE.right) {\n if (maxScroll <= 0) return REVEAL_POSITION.center\n return scrollLeft < wR / 2 ? REVEAL_POSITION.center : REVEAL_POSITION.right\n }\n if (mode === REVEAL_MODE.left) {\n if (maxScroll <= 0) return REVEAL_POSITION.center\n return scrollLeft < wL / 2 ? REVEAL_POSITION.left : REVEAL_POSITION.center\n }\n if (maxScroll <= 0) return REVEAL_POSITION.center\n if (scrollLeft < wL / 2) return REVEAL_POSITION.left\n if (scrollLeft > maxScroll - wR / 2) return REVEAL_POSITION.right\n return REVEAL_POSITION.center\n}\n\n/** \"Closed\" / resting scrollLeft for a mode (main panel only). */\nexport function getScrollClosed(\n wL: number,\n _wR: number,\n _maxScroll: number,\n mode: RevealMode,\n): number {\n if (mode === REVEAL_MODE.right) return 0\n return wL\n}\n","'use client'\n\nimport type { CSSProperties, ForwardedRef, MouseEvent, UIEvent } from 'react'\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n} from 'react'\n\nimport { DefaultHandleIcon } from './DefaultHandleIcon'\nimport { getRevealFromScroll, getScrollClosed } from './getRevealFromScroll'\nimport {\n REVEAL_HANDLE_POSITION,\n REVEAL_MODE,\n REVEAL_POSITION,\n type RevealHandlePosition,\n type RevealMode,\n type RevealPosition,\n type RevealRowClassNames,\n type RevealRowHandle,\n type RevealRowProps,\n} from './types'\n\nfunction cx(...parts: (string | undefined)[]) {\n return parts.filter(Boolean).join(' ')\n}\n\nfunction getMaxScroll(el: HTMLDivElement) {\n return Math.max(0, el.scrollWidth - el.clientWidth)\n}\n\nfunction resolveMode(\n left: RevealRowProps['left'],\n right: RevealRowProps['right'],\n mode: RevealMode | undefined,\n): RevealMode {\n if (mode) return mode\n if (left != null && right != null) return REVEAL_MODE.both\n if (left != null) return REVEAL_MODE.left\n return REVEAL_MODE.right\n}\n\nconst SCROLL_REVEAL_DEBOUNCE_MS = 64\nconst restEpsilon = 2\n\nconst rootScrollStyle: CSSProperties = {\n display: 'grid',\n overflowX: 'auto',\n scrollSnapType: 'x mandatory',\n scrollbarWidth: 'none',\n WebkitOverflowScrolling: 'touch',\n overscrollBehaviorX: 'contain',\n touchAction: 'pan-x pan-y',\n}\n\nconst snapStart: CSSProperties = { scrollSnapAlign: 'start' }\nconst snapEnd: CSSProperties = { scrollSnapAlign: 'end' }\n\ntype InnerProps = RevealRowProps & {\n forwardedRef: ForwardedRef<RevealRowHandle>\n}\n\nfunction RevealRowInner({\n children,\n left,\n right,\n mode: modeProp,\n actionWidthLeft: wLIn,\n actionWidthRight: wRIn,\n classNames = {} as RevealRowClassNames,\n showHandle = true,\n handle: handleOverride,\n handlePosition: handlePositionProp,\n handleTitle = 'Drag horizontally to show actions',\n handleAriaLabel = 'Drag horizontally to show actions',\n onRevealChange,\n onScroll: onScrollProp,\n resetWhenDisabled = true,\n disabled = false,\n isActive = false,\n className,\n style,\n forwardedRef,\n}: InnerProps) {\n const mode = resolveMode(left, right, modeProp)\n const hasL = mode === REVEAL_MODE.left || mode === REVEAL_MODE.both\n const hasR = mode === REVEAL_MODE.right || mode === REVEAL_MODE.both\n const wL = hasL ? (wLIn ?? 88) : 0\n const wR = hasR ? (wRIn ?? 88) : 0\n\n const handlePosition: RevealHandlePosition =\n handlePositionProp ??\n (mode === REVEAL_MODE.left\n ? REVEAL_HANDLE_POSITION.start\n : REVEAL_HANDLE_POSITION.end)\n\n const containerRef = useRef<HTMLDivElement>(null)\n const leftRef = useRef<HTMLDivElement>(null)\n const rightRef = useRef<HTMLDivElement>(null)\n const lastEmitted = useRef<RevealPosition | null>(null)\n const swipedRef = useRef(false)\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const hasAppliedInitialScroll = useRef(false)\n\n const readPosition = useCallback((): RevealPosition => {\n const el = containerRef.current\n if (!el) return REVEAL_POSITION.center\n return getRevealFromScroll(el.scrollLeft, getMaxScroll(el), wL, wR, mode)\n }, [wL, wR, mode])\n\n const emitReveal = useCallback(\n (position: RevealPosition) => {\n if (lastEmitted.current === position) return\n lastEmitted.current = position\n onRevealChange?.(position)\n },\n [onRevealChange],\n )\n\n const scrollToClosed = useCallback(() => {\n const el = containerRef.current\n if (!el) return\n const m = getMaxScroll(el)\n const closed = getScrollClosed(wL, wR, m, mode)\n el.scrollLeft = closed\n }, [wL, wR, mode])\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n close: () => {\n scrollToClosed()\n const p = readPosition()\n if (lastEmitted.current !== p) {\n lastEmitted.current = p\n onRevealChange?.(p)\n }\n },\n reveal: (position: RevealPosition) => {\n const el = containerRef.current\n if (!el) return\n const max = getMaxScroll(el)\n if (position === REVEAL_POSITION.center) {\n el.scrollLeft = getScrollClosed(wL, wR, max, mode)\n } else if (\n position === REVEAL_POSITION.left &&\n (mode === REVEAL_MODE.left || mode === REVEAL_MODE.both)\n ) {\n el.scrollLeft = 0\n } else if (\n position === REVEAL_POSITION.right &&\n (mode === REVEAL_MODE.right || mode === REVEAL_MODE.both)\n ) {\n el.scrollLeft = max\n } else {\n return\n }\n const p = getRevealFromScroll(el.scrollLeft, max, wL, wR, mode)\n lastEmitted.current = p\n onRevealChange?.(p)\n },\n }),\n [mode, onRevealChange, readPosition, scrollToClosed, wL, wR],\n )\n\n useLayoutEffect(() => {\n if (mode === REVEAL_MODE.right) {\n return\n }\n const el = containerRef.current\n if (!el) return\n if (!hasAppliedInitialScroll.current) {\n el.scrollLeft = wL\n hasAppliedInitialScroll.current = true\n }\n }, [mode, wL])\n\n useEffect(() => {\n if (disabled && resetWhenDisabled) {\n hasAppliedInitialScroll.current = true\n scrollToClosed()\n emitReveal(readPosition())\n }\n }, [disabled, emitReveal, readPosition, resetWhenDisabled, scrollToClosed])\n\n useEffect(() => {\n if (isActive) {\n hasAppliedInitialScroll.current = true\n scrollToClosed()\n emitReveal(readPosition())\n }\n }, [emitReveal, isActive, readPosition, scrollToClosed])\n\n useEffect(\n () => () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current)\n }\n },\n [],\n )\n\n const handleScroll = useCallback(\n (e: UIEvent<HTMLDivElement>) => {\n onScrollProp?.(e)\n const el = containerRef.current\n if (!el) return\n const m = getMaxScroll(el)\n const pos = getRevealFromScroll(el.scrollLeft, m, wL, wR, mode)\n const closed = getScrollClosed(wL, wR, m, mode)\n if (Math.abs(el.scrollLeft - closed) > restEpsilon) {\n swipedRef.current = true\n }\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current)\n }\n debounceTimer.current = setTimeout(() => {\n debounceTimer.current = null\n emitReveal(pos)\n }, SCROLL_REVEAL_DEBOUNCE_MS)\n },\n [emitReveal, mode, onScrollProp, wL, wR],\n )\n\n const onClickCapture = useCallback((e: MouseEvent) => {\n const t = e.target as Node | null\n if (t) {\n if (leftRef.current?.contains(t) || rightRef.current?.contains(t)) {\n return\n }\n }\n if (swipedRef.current) {\n e.preventDefault()\n e.stopPropagation()\n swipedRef.current = false\n }\n }, [])\n\n // `100%` for the main track (not `1fr`) so total row width > viewport: otherwise both\n // columns can shrink to fit with no overflow and the action stays visible.\n const gridTemplateColumns =\n mode === REVEAL_MODE.right\n ? `100% ${wR}px`\n : mode === REVEAL_MODE.left\n ? `${wL}px 100%`\n : `${wL}px 100% ${wR}px`\n\n const handleContent = showHandle ? (\n handleOverride !== undefined ? (\n handleOverride\n ) : (\n <>\n <span\n className=\"sr-only\"\n style={{\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0,0,0,0)',\n border: 0,\n }}\n >\n {handleAriaLabel}\n </span>\n <span className={classNames.handleIcon} aria-hidden>\n <DefaultHandleIcon />\n </span>\n </>\n )\n ) : null\n\n const handleStrip = showHandle ? (\n <div\n role=\"presentation\"\n className={classNames.handleContainer}\n data-reveal-row-handle\n style={{\n flexShrink: 0,\n alignSelf: 'stretch',\n display: 'flex',\n alignItems: 'center',\n }}\n title={handleOverride === undefined ? handleTitle : undefined}\n >\n {handleContent}\n </div>\n ) : null\n\n const mainColumn = (\n <div\n className={classNames.main}\n data-reveal-row-main\n style={{\n ...snapStart,\n minWidth: 0,\n width: '100%',\n maxWidth: '100%',\n boxSizing: 'border-box',\n }}\n >\n <div\n className={classNames.mainInner}\n style={{\n display: 'flex',\n minWidth: 0,\n width: '100%',\n alignItems: 'flex-start',\n }}\n >\n {handlePosition === REVEAL_HANDLE_POSITION.start && handleStrip}\n <div style={{ minWidth: 0, flex: 1, flexBasis: 0 }}>{children}</div>\n {handlePosition === REVEAL_HANDLE_POSITION.end && handleStrip}\n </div>\n </div>\n )\n\n return (\n <div\n ref={containerRef}\n data-reveal-mode={mode}\n className={cx(classNames.root, className)}\n onScroll={handleScroll}\n onClickCapture={onClickCapture}\n style={{\n ...rootScrollStyle,\n ...style,\n gridTemplateColumns,\n }}\n >\n {hasL ? (\n <div\n ref={leftRef}\n className={classNames.left}\n data-reveal-row-left\n style={{ ...snapStart, minWidth: 0, width: wL }}\n >\n {left}\n </div>\n ) : null}\n {mainColumn}\n {hasR ? (\n <div\n ref={rightRef}\n className={classNames.right}\n data-reveal-row-right\n style={{ ...snapEnd, minWidth: 0, width: wR }}\n >\n {right}\n </div>\n ) : null}\n </div>\n )\n}\n\nexport const RevealRow = forwardRef<RevealRowHandle, RevealRowProps>(\n function RevealRow(props, ref) {\n return <RevealRowInner {...props} forwardedRef={ref} />\n },\n)\n","/** Minimal 6-dot grip, no icon library dependency. */\nexport function DefaultHandleIcon() {\n return (\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n aria-hidden\n >\n <title>Drag handle</title>\n <circle cx=\"6\" cy=\"4\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"4\" r=\"1.2\" />\n <circle cx=\"6\" cy=\"8\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"8\" r=\"1.2\" />\n <circle cx=\"6\" cy=\"12\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"12\" r=\"1.2\" />\n </svg>\n )\n}\n"],"mappings":"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","names":["import_jsx_runtime","RevealRow"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/getRevealFromScroll.ts","../src/RevealRow.tsx","../src/DefaultHandleIcon.tsx"],"sourcesContent":["export { getRevealFromScroll, getScrollClosed } from './getRevealFromScroll'\nexport { RevealRow } from './RevealRow'\nexport type {\n AnimationConfig,\n AnimationPreset,\n RevealHandlePosition,\n RevealMode,\n RevealPosition,\n RevealRowClassNames,\n RevealRowElement,\n RevealRowHandle,\n RevealRowProps,\n} from './types'\nexport {\n ANIMATION_PRESET,\n ANIMATION_PRESETS,\n REVEAL_HANDLE_POSITION,\n REVEAL_MODE,\n REVEAL_POSITION,\n REVEAL_ROW_ELEMENTS,\n} from './types'\n","import type { CSSProperties, ReactNode, UIEvent } from 'react'\n\nexport const REVEAL_MODE = {\n left: 'left',\n right: 'right',\n both: 'both',\n} as const\n\nexport type RevealMode = (typeof REVEAL_MODE)[keyof typeof REVEAL_MODE]\n\nexport const REVEAL_POSITION = {\n left: 'left',\n center: 'center',\n right: 'right',\n} as const\n\nexport type RevealPosition =\n (typeof REVEAL_POSITION)[keyof typeof REVEAL_POSITION]\n\nexport const REVEAL_HANDLE_POSITION = {\n start: 'start',\n end: 'end',\n} as const\n\nexport type RevealHandlePosition =\n (typeof REVEAL_HANDLE_POSITION)[keyof typeof REVEAL_HANDLE_POSITION]\n\nexport const REVEAL_ROW_ELEMENTS = {\n div: 'div',\n section: 'section',\n article: 'article',\n main: 'main',\n aside: 'aside',\n header: 'header',\n footer: 'footer',\n nav: 'nav',\n li: 'li',\n} as const\n\nexport type RevealRowElement =\n (typeof REVEAL_ROW_ELEMENTS)[keyof typeof REVEAL_ROW_ELEMENTS]\n\nexport const ANIMATION_PRESET = {\n none: 'none',\n quick: 'quick',\n smooth: 'smooth',\n} as const\n\nexport type AnimationPreset =\n (typeof ANIMATION_PRESET)[keyof typeof ANIMATION_PRESET]\n\nexport type AnimationConfig = {\n duration: number\n easing: string\n}\n\nexport const ANIMATION_PRESETS: Record<AnimationPreset, AnimationConfig> = {\n [ANIMATION_PRESET.none]: { duration: 0, easing: 'linear' },\n [ANIMATION_PRESET.quick]: { duration: 200, easing: 'ease-out' },\n [ANIMATION_PRESET.smooth]: { duration: 400, easing: 'ease-in-out' },\n}\n\nexport type RevealRowClassNames = {\n root?: string\n main?: string\n mainInner?: string\n left?: string\n right?: string\n handleContainer?: string\n handleIcon?: string\n}\n\nexport type RevealRowHandle = {\n close: (animated?: boolean | AnimationPreset | AnimationConfig) => void\n reveal: (\n position: RevealPosition,\n animated?: boolean | AnimationPreset | AnimationConfig,\n ) => void\n}\n\nexport type RevealRowProps = {\n /** Primary row content (e.g. title, subtitle). */\n children: ReactNode\n /** Optional leading action column (e.g. delete). Omitted in `right` mode. */\n left?: ReactNode\n /**\n * Trailing action column (e.g. add). Omitted in `left` mode.\n */\n right?: ReactNode\n /**\n * The HTML element to use for the root container.\n * @default 'div'\n */\n as?: RevealRowElement\n /**\n * If both `left` and `right` are set, defaults to `both`. If only one side,\n * mode is derived unless overridden.\n */\n mode?: RevealMode\n actionWidthLeft?: number\n actionWidthRight?: number\n classNames?: RevealRowClassNames\n /** @default true */\n showHandle?: boolean\n /** Replaces the built-in drag affordance. */\n handle?: ReactNode\n /**\n * Where the handle sits in the main row. Default: `start` in `left` mode,\n * `end` otherwise.\n */\n handlePosition?: RevealHandlePosition\n handleTitle?: string\n /** Shown in screen-reader text when using the default drag handle. */\n handleAriaLabel?: string\n /** Fires when the settled position changes. */\n onRevealChange?: (position: RevealPosition) => void\n onScroll?: (event: UIEvent<HTMLElement>) => void\n /** Resets to closed; default true. */\n resetWhenDisabled?: boolean\n disabled?: boolean\n /**\n * When true, snaps back to the closed position (e.g. row became active/selected\n * elsewhere in the list).\n */\n isActive?: boolean\n className?: string\n style?: CSSProperties\n /**\n * Default animation preset for close/reveal animations when action buttons are clicked.\n * @default 'quick'\n */\n animationPreset?: AnimationPreset\n /**\n * Custom animation configuration overriding the preset.\n */\n animationConfig?: AnimationConfig\n}\n","import {\n REVEAL_MODE,\n REVEAL_POSITION,\n type RevealMode,\n type RevealPosition,\n} from './types'\n\n/**\n * Map horizontal scroll position to a logical \"revealed\" state.\n * `wL` / `wR` are the fixed action column widths; `maxScroll` is\n * `Math.max(0, scrollWidth - clientWidth)`.\n */\nexport function getRevealFromScroll(\n scrollLeft: number,\n maxScroll: number,\n wL: number,\n wR: number,\n mode: RevealMode,\n): RevealPosition {\n if (mode === REVEAL_MODE.right) {\n if (maxScroll <= 0) return REVEAL_POSITION.center\n return scrollLeft < wR / 2 ? REVEAL_POSITION.center : REVEAL_POSITION.right\n }\n if (mode === REVEAL_MODE.left) {\n if (maxScroll <= 0) return REVEAL_POSITION.center\n return scrollLeft < wL / 2 ? REVEAL_POSITION.left : REVEAL_POSITION.center\n }\n if (maxScroll <= 0) return REVEAL_POSITION.center\n if (scrollLeft < wL / 2) return REVEAL_POSITION.left\n if (scrollLeft > maxScroll - wR / 2) return REVEAL_POSITION.right\n return REVEAL_POSITION.center\n}\n\n/** \"Closed\" / resting scrollLeft for a mode (main panel only). */\nexport function getScrollClosed(\n wL: number,\n _wR: number,\n _maxScroll: number,\n mode: RevealMode,\n): number {\n if (mode === REVEAL_MODE.right) return 0\n return wL\n}\n","'use client'\n\nimport type { CSSProperties, ForwardedRef, MouseEvent, UIEvent } from 'react'\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n} from 'react'\n\nimport { DefaultHandleIcon } from './DefaultHandleIcon'\nimport { getRevealFromScroll, getScrollClosed } from './getRevealFromScroll'\nimport {\n ANIMATION_PRESET,\n ANIMATION_PRESETS,\n type AnimationConfig,\n type AnimationPreset,\n REVEAL_HANDLE_POSITION,\n REVEAL_MODE,\n REVEAL_POSITION,\n type RevealHandlePosition,\n type RevealMode,\n type RevealPosition,\n type RevealRowClassNames,\n type RevealRowHandle,\n type RevealRowProps,\n} from './types'\n\nfunction cx(...parts: (string | undefined)[]) {\n return parts.filter(Boolean).join(' ')\n}\n\nfunction getMaxScroll(el: HTMLElement) {\n return Math.max(0, el.scrollWidth - el.clientWidth)\n}\n\nfunction resolveMode(\n left: RevealRowProps['left'],\n right: RevealRowProps['right'],\n mode: RevealMode | undefined,\n): RevealMode {\n if (mode) return mode\n if (left != null && right != null) return REVEAL_MODE.both\n if (left != null) return REVEAL_MODE.left\n return REVEAL_MODE.right\n}\n\nfunction resolveAnimationConfig(\n animated: boolean | AnimationPreset | AnimationConfig | undefined,\n defaultPreset: AnimationPreset,\n customConfig?: AnimationConfig,\n): AnimationConfig {\n let config: AnimationConfig\n\n if (animated === false) {\n config = ANIMATION_PRESETS[ANIMATION_PRESET.none]\n } else if (animated === true || animated === undefined) {\n config = customConfig || ANIMATION_PRESETS[defaultPreset]\n } else if (typeof animated === 'string') {\n config = ANIMATION_PRESETS[animated]\n } else {\n config = animated\n }\n\n // Validate and clamp duration to be >= 0\n return {\n ...config,\n duration: Math.max(\n 0,\n Number.isFinite(config.duration) ? config.duration : 0,\n ),\n }\n}\n\nconst SCROLL_REVEAL_DEBOUNCE_MS = 64\nconst restEpsilon = 2\n\nconst rootScrollStyle: CSSProperties = {\n display: 'grid',\n overflowX: 'auto',\n scrollSnapType: 'x mandatory',\n scrollbarWidth: 'none',\n WebkitOverflowScrolling: 'touch',\n overscrollBehaviorX: 'contain',\n touchAction: 'pan-x pan-y',\n}\n\nconst rootScrollStyleDisabled: CSSProperties = {\n ...rootScrollStyle,\n overflowX: 'hidden',\n touchAction: 'pan-y',\n}\n\nconst snapStart: CSSProperties = { scrollSnapAlign: 'start' }\nconst snapEnd: CSSProperties = { scrollSnapAlign: 'end' }\n\ntype InnerProps = RevealRowProps & {\n forwardedRef: ForwardedRef<RevealRowHandle>\n}\n\nfunction RevealRowInner({\n children,\n left,\n right,\n as: Element = 'div',\n mode: modeProp,\n actionWidthLeft: wLIn,\n actionWidthRight: wRIn,\n classNames = {} as RevealRowClassNames,\n showHandle = true,\n handle: handleOverride,\n handlePosition: handlePositionProp,\n handleTitle = 'Drag horizontally to show actions',\n handleAriaLabel = 'Drag horizontally to show actions',\n onRevealChange,\n onScroll: onScrollProp,\n resetWhenDisabled = true,\n disabled = false,\n isActive = false,\n className,\n style,\n animationPreset = ANIMATION_PRESET.quick,\n animationConfig,\n forwardedRef,\n}: InnerProps) {\n const mode = resolveMode(left, right, modeProp)\n const hasL = mode === REVEAL_MODE.left || mode === REVEAL_MODE.both\n const hasR = mode === REVEAL_MODE.right || mode === REVEAL_MODE.both\n const wL = hasL ? (wLIn ?? 88) : 0\n const wR = hasR ? (wRIn ?? 88) : 0\n\n const handlePosition: RevealHandlePosition =\n handlePositionProp ??\n (mode === REVEAL_MODE.left\n ? REVEAL_HANDLE_POSITION.start\n : REVEAL_HANDLE_POSITION.end)\n\n const containerRef = useRef<HTMLElement>(null)\n const leftRef = useRef<HTMLDivElement>(null)\n const rightRef = useRef<HTMLDivElement>(null)\n const lastEmitted = useRef<RevealPosition | null>(null)\n const swipedRef = useRef(false)\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const hasAppliedInitialScroll = useRef(false)\n const isAnimatingRef = useRef(false)\n const rafIdRef = useRef<number | null>(null)\n const settleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const readPosition = useCallback((): RevealPosition => {\n const el = containerRef.current\n if (!el) return REVEAL_POSITION.center\n return getRevealFromScroll(el.scrollLeft, getMaxScroll(el), wL, wR, mode)\n }, [wL, wR, mode])\n\n const emitReveal = useCallback(\n (position: RevealPosition) => {\n if (lastEmitted.current === position) return\n lastEmitted.current = position\n onRevealChange?.(position)\n },\n [onRevealChange],\n )\n\n const scrollToClosed = useCallback(() => {\n const el = containerRef.current\n if (!el) return\n const m = getMaxScroll(el)\n const closed = getScrollClosed(wL, wR, m, mode)\n\n // For immediate scroll, we can use the default behavior\n // CSS scroll snap will handle the final positioning\n el.scrollLeft = closed\n }, [wL, wR, mode])\n\n const scrollToPosition = useCallback(\n (targetScrollLeft: number, animationOptions: AnimationConfig) => {\n const el = containerRef.current\n if (!el) return\n\n const { duration, easing } = animationOptions\n\n if (duration === 0) {\n el.scrollLeft = targetScrollLeft\n return\n }\n\n // Cancel any existing animation\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current)\n rafIdRef.current = null\n }\n if (settleTimerRef.current !== null) {\n clearTimeout(settleTimerRef.current)\n settleTimerRef.current = null\n }\n\n // Disable scroll snap during animation\n isAnimatingRef.current = true\n const originalScrollSnapType = el.style.scrollSnapType\n el.style.scrollSnapType = 'none'\n\n const startScrollLeft = el.scrollLeft\n const distance = targetScrollLeft - startScrollLeft\n const startTime = performance.now()\n\n const animate = (currentTime: number) => {\n const elapsed = currentTime - startTime\n const progress = Math.min(elapsed / duration, 1)\n\n let easedProgress = progress\n if (easing === 'ease-out') {\n easedProgress = 1 - (1 - progress) ** 2\n } else if (easing === 'ease-in-out') {\n easedProgress =\n progress < 0.5\n ? 2 * progress * progress\n : 1 - (-2 * progress + 2) ** 2 / 2\n } else if (easing.startsWith('cubic-bezier')) {\n // For the bounce effect, we'll use a simplified approximation\n easedProgress = progress * progress * (3 - 2 * progress)\n if (easing.includes('-0.55')) {\n // Bounce effect approximation\n easedProgress =\n progress < 0.5\n ? 4 * progress * progress * progress\n : 1 - (-2 * progress + 2) ** 3 / 2\n // Add overshoot for bounce\n if (progress > 0.7 && progress < 1) {\n easedProgress +=\n Math.sin((progress - 0.7) * Math.PI * 10) * 0.1 * (1 - progress)\n }\n }\n }\n\n el.scrollLeft = startScrollLeft + distance * easedProgress\n\n if (progress < 1) {\n rafIdRef.current = requestAnimationFrame(animate)\n } else {\n el.scrollLeft = targetScrollLeft\n // Re-enable scroll snap after animation completes\n el.style.scrollSnapType = originalScrollSnapType || 'x mandatory'\n isAnimatingRef.current = false\n rafIdRef.current = null\n }\n }\n\n rafIdRef.current = requestAnimationFrame(animate)\n },\n [],\n )\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n close: (animated?: boolean | AnimationPreset | AnimationConfig) => {\n const el = containerRef.current\n if (!el) return\n\n const m = getMaxScroll(el)\n const closed = getScrollClosed(wL, wR, m, mode)\n const animConfig = resolveAnimationConfig(\n animated,\n animationPreset,\n animationConfig,\n )\n\n scrollToPosition(closed, animConfig)\n\n // Update position after animation or immediately if no animation\n const delay = animConfig.duration > 0 ? animConfig.duration : 0\n if (settleTimerRef.current !== null) {\n clearTimeout(settleTimerRef.current)\n }\n settleTimerRef.current = setTimeout(() => {\n const p = readPosition()\n if (lastEmitted.current !== p) {\n lastEmitted.current = p\n onRevealChange?.(p)\n }\n settleTimerRef.current = null\n }, delay)\n },\n reveal: (\n position: RevealPosition,\n animated?: boolean | AnimationPreset | AnimationConfig,\n ) => {\n const el = containerRef.current\n if (!el) return\n const max = getMaxScroll(el)\n\n let targetScroll: number\n if (position === REVEAL_POSITION.center) {\n targetScroll = getScrollClosed(wL, wR, max, mode)\n } else if (\n position === REVEAL_POSITION.left &&\n (mode === REVEAL_MODE.left || mode === REVEAL_MODE.both)\n ) {\n targetScroll = 0\n } else if (\n position === REVEAL_POSITION.right &&\n (mode === REVEAL_MODE.right || mode === REVEAL_MODE.both)\n ) {\n targetScroll = max\n } else {\n return\n }\n\n const animConfig = resolveAnimationConfig(\n animated,\n animationPreset,\n animationConfig,\n )\n scrollToPosition(targetScroll, animConfig)\n\n // Update position after animation or immediately if no animation\n const delay = animConfig.duration > 0 ? animConfig.duration : 0\n if (settleTimerRef.current !== null) {\n clearTimeout(settleTimerRef.current)\n }\n settleTimerRef.current = setTimeout(() => {\n const p = getRevealFromScroll(targetScroll, max, wL, wR, mode)\n lastEmitted.current = p\n onRevealChange?.(p)\n settleTimerRef.current = null\n }, delay)\n },\n }),\n [\n mode,\n onRevealChange,\n readPosition,\n scrollToPosition,\n wL,\n wR,\n animationPreset,\n animationConfig,\n ],\n )\n\n useLayoutEffect(() => {\n if (mode === REVEAL_MODE.right) {\n return\n }\n const el = containerRef.current\n if (!el) return\n if (!hasAppliedInitialScroll.current) {\n el.scrollLeft = wL\n hasAppliedInitialScroll.current = true\n }\n }, [mode, wL])\n\n useEffect(() => {\n if (disabled && resetWhenDisabled) {\n hasAppliedInitialScroll.current = true\n scrollToClosed()\n emitReveal(readPosition())\n }\n }, [disabled, emitReveal, readPosition, resetWhenDisabled, scrollToClosed])\n\n useEffect(() => {\n if (isActive) {\n hasAppliedInitialScroll.current = true\n scrollToClosed()\n emitReveal(readPosition())\n }\n }, [emitReveal, isActive, readPosition, scrollToClosed])\n\n useEffect(\n () => () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current)\n }\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current)\n }\n if (settleTimerRef.current !== null) {\n clearTimeout(settleTimerRef.current)\n }\n },\n [],\n )\n\n const handleScroll = useCallback(\n (e: UIEvent<HTMLElement>) => {\n onScrollProp?.(e)\n const el = containerRef.current\n if (!el) return\n const m = getMaxScroll(el)\n const pos = getRevealFromScroll(el.scrollLeft, m, wL, wR, mode)\n const closed = getScrollClosed(wL, wR, m, mode)\n if (Math.abs(el.scrollLeft - closed) > restEpsilon) {\n swipedRef.current = true\n }\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current)\n }\n debounceTimer.current = setTimeout(() => {\n debounceTimer.current = null\n emitReveal(pos)\n }, SCROLL_REVEAL_DEBOUNCE_MS)\n },\n [emitReveal, mode, onScrollProp, wL, wR],\n )\n\n const onClickCapture = useCallback((e: MouseEvent) => {\n const t = e.target as Node | null\n if (t) {\n if (leftRef.current?.contains(t) || rightRef.current?.contains(t)) {\n return\n }\n }\n if (swipedRef.current) {\n e.preventDefault()\n e.stopPropagation()\n swipedRef.current = false\n }\n }, [])\n\n // `100%` for the main track (not `1fr`) so total row width > viewport: otherwise both\n // columns can shrink to fit with no overflow and the action stays visible.\n const gridTemplateColumns =\n mode === REVEAL_MODE.right\n ? `100% ${wR}px`\n : mode === REVEAL_MODE.left\n ? `${wL}px 100%`\n : `${wL}px 100% ${wR}px`\n\n const handleContent = showHandle ? (\n handleOverride !== undefined ? (\n handleOverride\n ) : (\n <>\n <span\n className=\"sr-only\"\n style={{\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0,0,0,0)',\n border: 0,\n }}\n >\n {handleAriaLabel}\n </span>\n <span className={classNames.handleIcon} aria-hidden>\n <DefaultHandleIcon />\n </span>\n </>\n )\n ) : null\n\n const handleStrip = showHandle ? (\n <div\n role=\"presentation\"\n className={classNames.handleContainer}\n data-reveal-row-handle\n style={{\n flexShrink: 0,\n alignSelf: 'stretch',\n display: 'flex',\n alignItems: 'center',\n }}\n title={handleOverride === undefined ? handleTitle : undefined}\n >\n {handleContent}\n </div>\n ) : null\n\n const mainColumn = (\n <div\n className={classNames.main}\n data-reveal-row-main\n style={{\n ...snapStart,\n minWidth: 0,\n width: '100%',\n maxWidth: '100%',\n boxSizing: 'border-box',\n }}\n >\n <div\n className={classNames.mainInner}\n style={{\n display: 'flex',\n minWidth: 0,\n width: '100%',\n alignItems: 'flex-start',\n }}\n >\n {handlePosition === REVEAL_HANDLE_POSITION.start && handleStrip}\n <div style={{ minWidth: 0, flex: 1, flexBasis: 0 }}>{children}</div>\n {handlePosition === REVEAL_HANDLE_POSITION.end && handleStrip}\n </div>\n </div>\n )\n\n return (\n <Element\n // biome-ignore lint/suspicious/noExplicitAny: Required for polymorphic ref compatibility\n ref={containerRef as any}\n data-reveal-mode={mode}\n className={cx(classNames.root, className)}\n onScroll={handleScroll}\n onClickCapture={onClickCapture}\n style={{\n ...(disabled ? rootScrollStyleDisabled : rootScrollStyle),\n ...style,\n gridTemplateColumns,\n }}\n >\n {hasL ? (\n <div\n ref={leftRef}\n className={classNames.left}\n data-reveal-row-left\n style={{ ...snapStart, minWidth: 0, width: wL }}\n >\n {left}\n </div>\n ) : null}\n {mainColumn}\n {hasR ? (\n <div\n ref={rightRef}\n className={classNames.right}\n data-reveal-row-right\n style={{ ...snapEnd, minWidth: 0, width: wR }}\n >\n {right}\n </div>\n ) : null}\n </Element>\n )\n}\n\nexport const RevealRow = forwardRef<RevealRowHandle, RevealRowProps>(\n function RevealRow(props, ref) {\n return <RevealRowInner {...props} forwardedRef={ref} />\n },\n)\n","/** Minimal 6-dot grip, no icon library dependency. */\nexport function DefaultHandleIcon() {\n return (\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n aria-hidden\n >\n <title>Drag handle</title>\n <circle cx=\"6\" cy=\"4\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"4\" r=\"1.2\" />\n <circle cx=\"6\" cy=\"8\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"8\" r=\"1.2\" />\n <circle cx=\"6\" cy=\"12\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"12\" r=\"1.2\" />\n </svg>\n )\n}\n"],"mappings":"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","names":["import_jsx_runtime","RevealRow"]}
|
package/dist/index.mjs
CHANGED
|
@@ -13,6 +13,27 @@ var REVEAL_HANDLE_POSITION = {
|
|
|
13
13
|
start: "start",
|
|
14
14
|
end: "end"
|
|
15
15
|
};
|
|
16
|
+
var REVEAL_ROW_ELEMENTS = {
|
|
17
|
+
div: "div",
|
|
18
|
+
section: "section",
|
|
19
|
+
article: "article",
|
|
20
|
+
main: "main",
|
|
21
|
+
aside: "aside",
|
|
22
|
+
header: "header",
|
|
23
|
+
footer: "footer",
|
|
24
|
+
nav: "nav",
|
|
25
|
+
li: "li"
|
|
26
|
+
};
|
|
27
|
+
var ANIMATION_PRESET = {
|
|
28
|
+
none: "none",
|
|
29
|
+
quick: "quick",
|
|
30
|
+
smooth: "smooth"
|
|
31
|
+
};
|
|
32
|
+
var ANIMATION_PRESETS = {
|
|
33
|
+
[ANIMATION_PRESET.none]: { duration: 0, easing: "linear" },
|
|
34
|
+
[ANIMATION_PRESET.quick]: { duration: 200, easing: "ease-out" },
|
|
35
|
+
[ANIMATION_PRESET.smooth]: { duration: 400, easing: "ease-in-out" }
|
|
36
|
+
};
|
|
16
37
|
|
|
17
38
|
// src/getRevealFromScroll.ts
|
|
18
39
|
function getRevealFromScroll(scrollLeft, maxScroll, wL, wR, mode) {
|
|
@@ -82,6 +103,25 @@ function resolveMode(left, right, mode) {
|
|
|
82
103
|
if (left != null) return REVEAL_MODE.left;
|
|
83
104
|
return REVEAL_MODE.right;
|
|
84
105
|
}
|
|
106
|
+
function resolveAnimationConfig(animated, defaultPreset, customConfig) {
|
|
107
|
+
let config;
|
|
108
|
+
if (animated === false) {
|
|
109
|
+
config = ANIMATION_PRESETS[ANIMATION_PRESET.none];
|
|
110
|
+
} else if (animated === true || animated === void 0) {
|
|
111
|
+
config = customConfig || ANIMATION_PRESETS[defaultPreset];
|
|
112
|
+
} else if (typeof animated === "string") {
|
|
113
|
+
config = ANIMATION_PRESETS[animated];
|
|
114
|
+
} else {
|
|
115
|
+
config = animated;
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
...config,
|
|
119
|
+
duration: Math.max(
|
|
120
|
+
0,
|
|
121
|
+
Number.isFinite(config.duration) ? config.duration : 0
|
|
122
|
+
)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
85
125
|
var SCROLL_REVEAL_DEBOUNCE_MS = 64;
|
|
86
126
|
var restEpsilon = 2;
|
|
87
127
|
var rootScrollStyle = {
|
|
@@ -93,12 +133,18 @@ var rootScrollStyle = {
|
|
|
93
133
|
overscrollBehaviorX: "contain",
|
|
94
134
|
touchAction: "pan-x pan-y"
|
|
95
135
|
};
|
|
136
|
+
var rootScrollStyleDisabled = {
|
|
137
|
+
...rootScrollStyle,
|
|
138
|
+
overflowX: "hidden",
|
|
139
|
+
touchAction: "pan-y"
|
|
140
|
+
};
|
|
96
141
|
var snapStart = { scrollSnapAlign: "start" };
|
|
97
142
|
var snapEnd = { scrollSnapAlign: "end" };
|
|
98
143
|
function RevealRowInner({
|
|
99
144
|
children,
|
|
100
145
|
left,
|
|
101
146
|
right,
|
|
147
|
+
as: Element = "div",
|
|
102
148
|
mode: modeProp,
|
|
103
149
|
actionWidthLeft: wLIn,
|
|
104
150
|
actionWidthRight: wRIn,
|
|
@@ -115,6 +161,8 @@ function RevealRowInner({
|
|
|
115
161
|
isActive = false,
|
|
116
162
|
className,
|
|
117
163
|
style,
|
|
164
|
+
animationPreset = ANIMATION_PRESET.quick,
|
|
165
|
+
animationConfig,
|
|
118
166
|
forwardedRef
|
|
119
167
|
}) {
|
|
120
168
|
const mode = resolveMode(left, right, modeProp);
|
|
@@ -130,6 +178,9 @@ function RevealRowInner({
|
|
|
130
178
|
const swipedRef = useRef(false);
|
|
131
179
|
const debounceTimer = useRef(null);
|
|
132
180
|
const hasAppliedInitialScroll = useRef(false);
|
|
181
|
+
const isAnimatingRef = useRef(false);
|
|
182
|
+
const rafIdRef = useRef(null);
|
|
183
|
+
const settleTimerRef = useRef(null);
|
|
133
184
|
const readPosition = useCallback(() => {
|
|
134
185
|
const el = containerRef.current;
|
|
135
186
|
if (!el) return REVEAL_POSITION.center;
|
|
@@ -150,36 +201,129 @@ function RevealRowInner({
|
|
|
150
201
|
const closed = getScrollClosed(wL, wR, m, mode);
|
|
151
202
|
el.scrollLeft = closed;
|
|
152
203
|
}, [wL, wR, mode]);
|
|
204
|
+
const scrollToPosition = useCallback(
|
|
205
|
+
(targetScrollLeft, animationOptions) => {
|
|
206
|
+
const el = containerRef.current;
|
|
207
|
+
if (!el) return;
|
|
208
|
+
const { duration, easing } = animationOptions;
|
|
209
|
+
if (duration === 0) {
|
|
210
|
+
el.scrollLeft = targetScrollLeft;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (rafIdRef.current !== null) {
|
|
214
|
+
cancelAnimationFrame(rafIdRef.current);
|
|
215
|
+
rafIdRef.current = null;
|
|
216
|
+
}
|
|
217
|
+
if (settleTimerRef.current !== null) {
|
|
218
|
+
clearTimeout(settleTimerRef.current);
|
|
219
|
+
settleTimerRef.current = null;
|
|
220
|
+
}
|
|
221
|
+
isAnimatingRef.current = true;
|
|
222
|
+
const originalScrollSnapType = el.style.scrollSnapType;
|
|
223
|
+
el.style.scrollSnapType = "none";
|
|
224
|
+
const startScrollLeft = el.scrollLeft;
|
|
225
|
+
const distance = targetScrollLeft - startScrollLeft;
|
|
226
|
+
const startTime = performance.now();
|
|
227
|
+
const animate = (currentTime) => {
|
|
228
|
+
const elapsed = currentTime - startTime;
|
|
229
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
230
|
+
let easedProgress = progress;
|
|
231
|
+
if (easing === "ease-out") {
|
|
232
|
+
easedProgress = 1 - (1 - progress) ** 2;
|
|
233
|
+
} else if (easing === "ease-in-out") {
|
|
234
|
+
easedProgress = progress < 0.5 ? 2 * progress * progress : 1 - (-2 * progress + 2) ** 2 / 2;
|
|
235
|
+
} else if (easing.startsWith("cubic-bezier")) {
|
|
236
|
+
easedProgress = progress * progress * (3 - 2 * progress);
|
|
237
|
+
if (easing.includes("-0.55")) {
|
|
238
|
+
easedProgress = progress < 0.5 ? 4 * progress * progress * progress : 1 - (-2 * progress + 2) ** 3 / 2;
|
|
239
|
+
if (progress > 0.7 && progress < 1) {
|
|
240
|
+
easedProgress += Math.sin((progress - 0.7) * Math.PI * 10) * 0.1 * (1 - progress);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
el.scrollLeft = startScrollLeft + distance * easedProgress;
|
|
245
|
+
if (progress < 1) {
|
|
246
|
+
rafIdRef.current = requestAnimationFrame(animate);
|
|
247
|
+
} else {
|
|
248
|
+
el.scrollLeft = targetScrollLeft;
|
|
249
|
+
el.style.scrollSnapType = originalScrollSnapType || "x mandatory";
|
|
250
|
+
isAnimatingRef.current = false;
|
|
251
|
+
rafIdRef.current = null;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
rafIdRef.current = requestAnimationFrame(animate);
|
|
255
|
+
},
|
|
256
|
+
[]
|
|
257
|
+
);
|
|
153
258
|
useImperativeHandle(
|
|
154
259
|
forwardedRef,
|
|
155
260
|
() => ({
|
|
156
|
-
close: () => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
261
|
+
close: (animated) => {
|
|
262
|
+
const el = containerRef.current;
|
|
263
|
+
if (!el) return;
|
|
264
|
+
const m = getMaxScroll(el);
|
|
265
|
+
const closed = getScrollClosed(wL, wR, m, mode);
|
|
266
|
+
const animConfig = resolveAnimationConfig(
|
|
267
|
+
animated,
|
|
268
|
+
animationPreset,
|
|
269
|
+
animationConfig
|
|
270
|
+
);
|
|
271
|
+
scrollToPosition(closed, animConfig);
|
|
272
|
+
const delay = animConfig.duration > 0 ? animConfig.duration : 0;
|
|
273
|
+
if (settleTimerRef.current !== null) {
|
|
274
|
+
clearTimeout(settleTimerRef.current);
|
|
162
275
|
}
|
|
276
|
+
settleTimerRef.current = setTimeout(() => {
|
|
277
|
+
const p = readPosition();
|
|
278
|
+
if (lastEmitted.current !== p) {
|
|
279
|
+
lastEmitted.current = p;
|
|
280
|
+
onRevealChange?.(p);
|
|
281
|
+
}
|
|
282
|
+
settleTimerRef.current = null;
|
|
283
|
+
}, delay);
|
|
163
284
|
},
|
|
164
|
-
reveal: (position) => {
|
|
285
|
+
reveal: (position, animated) => {
|
|
165
286
|
const el = containerRef.current;
|
|
166
287
|
if (!el) return;
|
|
167
288
|
const max = getMaxScroll(el);
|
|
289
|
+
let targetScroll;
|
|
168
290
|
if (position === REVEAL_POSITION.center) {
|
|
169
|
-
|
|
291
|
+
targetScroll = getScrollClosed(wL, wR, max, mode);
|
|
170
292
|
} else if (position === REVEAL_POSITION.left && (mode === REVEAL_MODE.left || mode === REVEAL_MODE.both)) {
|
|
171
|
-
|
|
293
|
+
targetScroll = 0;
|
|
172
294
|
} else if (position === REVEAL_POSITION.right && (mode === REVEAL_MODE.right || mode === REVEAL_MODE.both)) {
|
|
173
|
-
|
|
295
|
+
targetScroll = max;
|
|
174
296
|
} else {
|
|
175
297
|
return;
|
|
176
298
|
}
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
299
|
+
const animConfig = resolveAnimationConfig(
|
|
300
|
+
animated,
|
|
301
|
+
animationPreset,
|
|
302
|
+
animationConfig
|
|
303
|
+
);
|
|
304
|
+
scrollToPosition(targetScroll, animConfig);
|
|
305
|
+
const delay = animConfig.duration > 0 ? animConfig.duration : 0;
|
|
306
|
+
if (settleTimerRef.current !== null) {
|
|
307
|
+
clearTimeout(settleTimerRef.current);
|
|
308
|
+
}
|
|
309
|
+
settleTimerRef.current = setTimeout(() => {
|
|
310
|
+
const p = getRevealFromScroll(targetScroll, max, wL, wR, mode);
|
|
311
|
+
lastEmitted.current = p;
|
|
312
|
+
onRevealChange?.(p);
|
|
313
|
+
settleTimerRef.current = null;
|
|
314
|
+
}, delay);
|
|
180
315
|
}
|
|
181
316
|
}),
|
|
182
|
-
[
|
|
317
|
+
[
|
|
318
|
+
mode,
|
|
319
|
+
onRevealChange,
|
|
320
|
+
readPosition,
|
|
321
|
+
scrollToPosition,
|
|
322
|
+
wL,
|
|
323
|
+
wR,
|
|
324
|
+
animationPreset,
|
|
325
|
+
animationConfig
|
|
326
|
+
]
|
|
183
327
|
);
|
|
184
328
|
useLayoutEffect(() => {
|
|
185
329
|
if (mode === REVEAL_MODE.right) {
|
|
@@ -211,6 +355,12 @@ function RevealRowInner({
|
|
|
211
355
|
if (debounceTimer.current) {
|
|
212
356
|
clearTimeout(debounceTimer.current);
|
|
213
357
|
}
|
|
358
|
+
if (rafIdRef.current !== null) {
|
|
359
|
+
cancelAnimationFrame(rafIdRef.current);
|
|
360
|
+
}
|
|
361
|
+
if (settleTimerRef.current !== null) {
|
|
362
|
+
clearTimeout(settleTimerRef.current);
|
|
363
|
+
}
|
|
214
364
|
},
|
|
215
365
|
[]
|
|
216
366
|
);
|
|
@@ -317,7 +467,7 @@ function RevealRowInner({
|
|
|
317
467
|
}
|
|
318
468
|
);
|
|
319
469
|
return /* @__PURE__ */ jsxs2(
|
|
320
|
-
|
|
470
|
+
Element,
|
|
321
471
|
{
|
|
322
472
|
ref: containerRef,
|
|
323
473
|
"data-reveal-mode": mode,
|
|
@@ -325,7 +475,7 @@ function RevealRowInner({
|
|
|
325
475
|
onScroll: handleScroll,
|
|
326
476
|
onClickCapture,
|
|
327
477
|
style: {
|
|
328
|
-
...rootScrollStyle,
|
|
478
|
+
...disabled ? rootScrollStyleDisabled : rootScrollStyle,
|
|
329
479
|
...style,
|
|
330
480
|
gridTemplateColumns
|
|
331
481
|
},
|
|
@@ -361,9 +511,12 @@ var RevealRow = forwardRef(
|
|
|
361
511
|
}
|
|
362
512
|
);
|
|
363
513
|
export {
|
|
514
|
+
ANIMATION_PRESET,
|
|
515
|
+
ANIMATION_PRESETS,
|
|
364
516
|
REVEAL_HANDLE_POSITION,
|
|
365
517
|
REVEAL_MODE,
|
|
366
518
|
REVEAL_POSITION,
|
|
519
|
+
REVEAL_ROW_ELEMENTS,
|
|
367
520
|
RevealRow,
|
|
368
521
|
getRevealFromScroll,
|
|
369
522
|
getScrollClosed
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/getRevealFromScroll.ts","../src/RevealRow.tsx","../src/DefaultHandleIcon.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode, UIEvent } from 'react'\n\nexport const REVEAL_MODE = {\n left: 'left',\n right: 'right',\n both: 'both',\n} as const\n\nexport type RevealMode = (typeof REVEAL_MODE)[keyof typeof REVEAL_MODE]\n\nexport const REVEAL_POSITION = {\n left: 'left',\n center: 'center',\n right: 'right',\n} as const\n\nexport type RevealPosition =\n (typeof REVEAL_POSITION)[keyof typeof REVEAL_POSITION]\n\nexport const REVEAL_HANDLE_POSITION = {\n start: 'start',\n end: 'end',\n} as const\n\nexport type RevealHandlePosition =\n (typeof REVEAL_HANDLE_POSITION)[keyof typeof REVEAL_HANDLE_POSITION]\n\nexport type RevealRowClassNames = {\n root?: string\n main?: string\n mainInner?: string\n left?: string\n right?: string\n handleContainer?: string\n handleIcon?: string\n}\n\nexport type RevealRowHandle = {\n close: () => void\n reveal: (position: RevealPosition) => void\n}\n\nexport type RevealRowProps = {\n /** Primary row content (e.g. title, subtitle). */\n children: ReactNode\n /** Optional leading action column (e.g. delete). Omitted in `right` mode. */\n left?: ReactNode\n /**\n * Trailing action column (e.g. add). Omitted in `left` mode.\n */\n right?: ReactNode\n /**\n * If both `left` and `right` are set, defaults to `both`. If only one side,\n * mode is derived unless overridden.\n */\n mode?: RevealMode\n actionWidthLeft?: number\n actionWidthRight?: number\n classNames?: RevealRowClassNames\n /** @default true */\n showHandle?: boolean\n /** Replaces the built-in drag affordance. */\n handle?: ReactNode\n /**\n * Where the handle sits in the main row. Default: `start` in `left` mode,\n * `end` otherwise.\n */\n handlePosition?: RevealHandlePosition\n handleTitle?: string\n /** Shown in screen-reader text when using the default drag handle. */\n handleAriaLabel?: string\n /** Fires when the settled position changes. */\n onRevealChange?: (position: RevealPosition) => void\n onScroll?: (event: UIEvent<HTMLDivElement>) => void\n /** Resets to closed; default true. */\n resetWhenDisabled?: boolean\n disabled?: boolean\n /**\n * When true, snaps back to the closed position (e.g. row became active/selected\n * elsewhere in the list).\n */\n isActive?: boolean\n className?: string\n style?: CSSProperties\n}\n","import {\n REVEAL_MODE,\n REVEAL_POSITION,\n type RevealMode,\n type RevealPosition,\n} from './types'\n\n/**\n * Map horizontal scroll position to a logical \"revealed\" state.\n * `wL` / `wR` are the fixed action column widths; `maxScroll` is\n * `Math.max(0, scrollWidth - clientWidth)`.\n */\nexport function getRevealFromScroll(\n scrollLeft: number,\n maxScroll: number,\n wL: number,\n wR: number,\n mode: RevealMode,\n): RevealPosition {\n if (mode === REVEAL_MODE.right) {\n if (maxScroll <= 0) return REVEAL_POSITION.center\n return scrollLeft < wR / 2 ? REVEAL_POSITION.center : REVEAL_POSITION.right\n }\n if (mode === REVEAL_MODE.left) {\n if (maxScroll <= 0) return REVEAL_POSITION.center\n return scrollLeft < wL / 2 ? REVEAL_POSITION.left : REVEAL_POSITION.center\n }\n if (maxScroll <= 0) return REVEAL_POSITION.center\n if (scrollLeft < wL / 2) return REVEAL_POSITION.left\n if (scrollLeft > maxScroll - wR / 2) return REVEAL_POSITION.right\n return REVEAL_POSITION.center\n}\n\n/** \"Closed\" / resting scrollLeft for a mode (main panel only). */\nexport function getScrollClosed(\n wL: number,\n _wR: number,\n _maxScroll: number,\n mode: RevealMode,\n): number {\n if (mode === REVEAL_MODE.right) return 0\n return wL\n}\n","'use client'\n\nimport type { CSSProperties, ForwardedRef, MouseEvent, UIEvent } from 'react'\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n} from 'react'\n\nimport { DefaultHandleIcon } from './DefaultHandleIcon'\nimport { getRevealFromScroll, getScrollClosed } from './getRevealFromScroll'\nimport {\n REVEAL_HANDLE_POSITION,\n REVEAL_MODE,\n REVEAL_POSITION,\n type RevealHandlePosition,\n type RevealMode,\n type RevealPosition,\n type RevealRowClassNames,\n type RevealRowHandle,\n type RevealRowProps,\n} from './types'\n\nfunction cx(...parts: (string | undefined)[]) {\n return parts.filter(Boolean).join(' ')\n}\n\nfunction getMaxScroll(el: HTMLDivElement) {\n return Math.max(0, el.scrollWidth - el.clientWidth)\n}\n\nfunction resolveMode(\n left: RevealRowProps['left'],\n right: RevealRowProps['right'],\n mode: RevealMode | undefined,\n): RevealMode {\n if (mode) return mode\n if (left != null && right != null) return REVEAL_MODE.both\n if (left != null) return REVEAL_MODE.left\n return REVEAL_MODE.right\n}\n\nconst SCROLL_REVEAL_DEBOUNCE_MS = 64\nconst restEpsilon = 2\n\nconst rootScrollStyle: CSSProperties = {\n display: 'grid',\n overflowX: 'auto',\n scrollSnapType: 'x mandatory',\n scrollbarWidth: 'none',\n WebkitOverflowScrolling: 'touch',\n overscrollBehaviorX: 'contain',\n touchAction: 'pan-x pan-y',\n}\n\nconst snapStart: CSSProperties = { scrollSnapAlign: 'start' }\nconst snapEnd: CSSProperties = { scrollSnapAlign: 'end' }\n\ntype InnerProps = RevealRowProps & {\n forwardedRef: ForwardedRef<RevealRowHandle>\n}\n\nfunction RevealRowInner({\n children,\n left,\n right,\n mode: modeProp,\n actionWidthLeft: wLIn,\n actionWidthRight: wRIn,\n classNames = {} as RevealRowClassNames,\n showHandle = true,\n handle: handleOverride,\n handlePosition: handlePositionProp,\n handleTitle = 'Drag horizontally to show actions',\n handleAriaLabel = 'Drag horizontally to show actions',\n onRevealChange,\n onScroll: onScrollProp,\n resetWhenDisabled = true,\n disabled = false,\n isActive = false,\n className,\n style,\n forwardedRef,\n}: InnerProps) {\n const mode = resolveMode(left, right, modeProp)\n const hasL = mode === REVEAL_MODE.left || mode === REVEAL_MODE.both\n const hasR = mode === REVEAL_MODE.right || mode === REVEAL_MODE.both\n const wL = hasL ? (wLIn ?? 88) : 0\n const wR = hasR ? (wRIn ?? 88) : 0\n\n const handlePosition: RevealHandlePosition =\n handlePositionProp ??\n (mode === REVEAL_MODE.left\n ? REVEAL_HANDLE_POSITION.start\n : REVEAL_HANDLE_POSITION.end)\n\n const containerRef = useRef<HTMLDivElement>(null)\n const leftRef = useRef<HTMLDivElement>(null)\n const rightRef = useRef<HTMLDivElement>(null)\n const lastEmitted = useRef<RevealPosition | null>(null)\n const swipedRef = useRef(false)\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const hasAppliedInitialScroll = useRef(false)\n\n const readPosition = useCallback((): RevealPosition => {\n const el = containerRef.current\n if (!el) return REVEAL_POSITION.center\n return getRevealFromScroll(el.scrollLeft, getMaxScroll(el), wL, wR, mode)\n }, [wL, wR, mode])\n\n const emitReveal = useCallback(\n (position: RevealPosition) => {\n if (lastEmitted.current === position) return\n lastEmitted.current = position\n onRevealChange?.(position)\n },\n [onRevealChange],\n )\n\n const scrollToClosed = useCallback(() => {\n const el = containerRef.current\n if (!el) return\n const m = getMaxScroll(el)\n const closed = getScrollClosed(wL, wR, m, mode)\n el.scrollLeft = closed\n }, [wL, wR, mode])\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n close: () => {\n scrollToClosed()\n const p = readPosition()\n if (lastEmitted.current !== p) {\n lastEmitted.current = p\n onRevealChange?.(p)\n }\n },\n reveal: (position: RevealPosition) => {\n const el = containerRef.current\n if (!el) return\n const max = getMaxScroll(el)\n if (position === REVEAL_POSITION.center) {\n el.scrollLeft = getScrollClosed(wL, wR, max, mode)\n } else if (\n position === REVEAL_POSITION.left &&\n (mode === REVEAL_MODE.left || mode === REVEAL_MODE.both)\n ) {\n el.scrollLeft = 0\n } else if (\n position === REVEAL_POSITION.right &&\n (mode === REVEAL_MODE.right || mode === REVEAL_MODE.both)\n ) {\n el.scrollLeft = max\n } else {\n return\n }\n const p = getRevealFromScroll(el.scrollLeft, max, wL, wR, mode)\n lastEmitted.current = p\n onRevealChange?.(p)\n },\n }),\n [mode, onRevealChange, readPosition, scrollToClosed, wL, wR],\n )\n\n useLayoutEffect(() => {\n if (mode === REVEAL_MODE.right) {\n return\n }\n const el = containerRef.current\n if (!el) return\n if (!hasAppliedInitialScroll.current) {\n el.scrollLeft = wL\n hasAppliedInitialScroll.current = true\n }\n }, [mode, wL])\n\n useEffect(() => {\n if (disabled && resetWhenDisabled) {\n hasAppliedInitialScroll.current = true\n scrollToClosed()\n emitReveal(readPosition())\n }\n }, [disabled, emitReveal, readPosition, resetWhenDisabled, scrollToClosed])\n\n useEffect(() => {\n if (isActive) {\n hasAppliedInitialScroll.current = true\n scrollToClosed()\n emitReveal(readPosition())\n }\n }, [emitReveal, isActive, readPosition, scrollToClosed])\n\n useEffect(\n () => () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current)\n }\n },\n [],\n )\n\n const handleScroll = useCallback(\n (e: UIEvent<HTMLDivElement>) => {\n onScrollProp?.(e)\n const el = containerRef.current\n if (!el) return\n const m = getMaxScroll(el)\n const pos = getRevealFromScroll(el.scrollLeft, m, wL, wR, mode)\n const closed = getScrollClosed(wL, wR, m, mode)\n if (Math.abs(el.scrollLeft - closed) > restEpsilon) {\n swipedRef.current = true\n }\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current)\n }\n debounceTimer.current = setTimeout(() => {\n debounceTimer.current = null\n emitReveal(pos)\n }, SCROLL_REVEAL_DEBOUNCE_MS)\n },\n [emitReveal, mode, onScrollProp, wL, wR],\n )\n\n const onClickCapture = useCallback((e: MouseEvent) => {\n const t = e.target as Node | null\n if (t) {\n if (leftRef.current?.contains(t) || rightRef.current?.contains(t)) {\n return\n }\n }\n if (swipedRef.current) {\n e.preventDefault()\n e.stopPropagation()\n swipedRef.current = false\n }\n }, [])\n\n // `100%` for the main track (not `1fr`) so total row width > viewport: otherwise both\n // columns can shrink to fit with no overflow and the action stays visible.\n const gridTemplateColumns =\n mode === REVEAL_MODE.right\n ? `100% ${wR}px`\n : mode === REVEAL_MODE.left\n ? `${wL}px 100%`\n : `${wL}px 100% ${wR}px`\n\n const handleContent = showHandle ? (\n handleOverride !== undefined ? (\n handleOverride\n ) : (\n <>\n <span\n className=\"sr-only\"\n style={{\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0,0,0,0)',\n border: 0,\n }}\n >\n {handleAriaLabel}\n </span>\n <span className={classNames.handleIcon} aria-hidden>\n <DefaultHandleIcon />\n </span>\n </>\n )\n ) : null\n\n const handleStrip = showHandle ? (\n <div\n role=\"presentation\"\n className={classNames.handleContainer}\n data-reveal-row-handle\n style={{\n flexShrink: 0,\n alignSelf: 'stretch',\n display: 'flex',\n alignItems: 'center',\n }}\n title={handleOverride === undefined ? handleTitle : undefined}\n >\n {handleContent}\n </div>\n ) : null\n\n const mainColumn = (\n <div\n className={classNames.main}\n data-reveal-row-main\n style={{\n ...snapStart,\n minWidth: 0,\n width: '100%',\n maxWidth: '100%',\n boxSizing: 'border-box',\n }}\n >\n <div\n className={classNames.mainInner}\n style={{\n display: 'flex',\n minWidth: 0,\n width: '100%',\n alignItems: 'flex-start',\n }}\n >\n {handlePosition === REVEAL_HANDLE_POSITION.start && handleStrip}\n <div style={{ minWidth: 0, flex: 1, flexBasis: 0 }}>{children}</div>\n {handlePosition === REVEAL_HANDLE_POSITION.end && handleStrip}\n </div>\n </div>\n )\n\n return (\n <div\n ref={containerRef}\n data-reveal-mode={mode}\n className={cx(classNames.root, className)}\n onScroll={handleScroll}\n onClickCapture={onClickCapture}\n style={{\n ...rootScrollStyle,\n ...style,\n gridTemplateColumns,\n }}\n >\n {hasL ? (\n <div\n ref={leftRef}\n className={classNames.left}\n data-reveal-row-left\n style={{ ...snapStart, minWidth: 0, width: wL }}\n >\n {left}\n </div>\n ) : null}\n {mainColumn}\n {hasR ? (\n <div\n ref={rightRef}\n className={classNames.right}\n data-reveal-row-right\n style={{ ...snapEnd, minWidth: 0, width: wR }}\n >\n {right}\n </div>\n ) : null}\n </div>\n )\n}\n\nexport const RevealRow = forwardRef<RevealRowHandle, RevealRowProps>(\n function RevealRow(props, ref) {\n return <RevealRowInner {...props} forwardedRef={ref} />\n },\n)\n","/** Minimal 6-dot grip, no icon library dependency. */\nexport function DefaultHandleIcon() {\n return (\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n aria-hidden\n >\n <title>Drag handle</title>\n <circle cx=\"6\" cy=\"4\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"4\" r=\"1.2\" />\n <circle cx=\"6\" cy=\"8\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"8\" r=\"1.2\" />\n <circle cx=\"6\" cy=\"12\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"12\" r=\"1.2\" />\n </svg>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs","RevealRow"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/getRevealFromScroll.ts","../src/RevealRow.tsx","../src/DefaultHandleIcon.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode, UIEvent } from 'react'\n\nexport const REVEAL_MODE = {\n left: 'left',\n right: 'right',\n both: 'both',\n} as const\n\nexport type RevealMode = (typeof REVEAL_MODE)[keyof typeof REVEAL_MODE]\n\nexport const REVEAL_POSITION = {\n left: 'left',\n center: 'center',\n right: 'right',\n} as const\n\nexport type RevealPosition =\n (typeof REVEAL_POSITION)[keyof typeof REVEAL_POSITION]\n\nexport const REVEAL_HANDLE_POSITION = {\n start: 'start',\n end: 'end',\n} as const\n\nexport type RevealHandlePosition =\n (typeof REVEAL_HANDLE_POSITION)[keyof typeof REVEAL_HANDLE_POSITION]\n\nexport const REVEAL_ROW_ELEMENTS = {\n div: 'div',\n section: 'section',\n article: 'article',\n main: 'main',\n aside: 'aside',\n header: 'header',\n footer: 'footer',\n nav: 'nav',\n li: 'li',\n} as const\n\nexport type RevealRowElement =\n (typeof REVEAL_ROW_ELEMENTS)[keyof typeof REVEAL_ROW_ELEMENTS]\n\nexport const ANIMATION_PRESET = {\n none: 'none',\n quick: 'quick',\n smooth: 'smooth',\n} as const\n\nexport type AnimationPreset =\n (typeof ANIMATION_PRESET)[keyof typeof ANIMATION_PRESET]\n\nexport type AnimationConfig = {\n duration: number\n easing: string\n}\n\nexport const ANIMATION_PRESETS: Record<AnimationPreset, AnimationConfig> = {\n [ANIMATION_PRESET.none]: { duration: 0, easing: 'linear' },\n [ANIMATION_PRESET.quick]: { duration: 200, easing: 'ease-out' },\n [ANIMATION_PRESET.smooth]: { duration: 400, easing: 'ease-in-out' },\n}\n\nexport type RevealRowClassNames = {\n root?: string\n main?: string\n mainInner?: string\n left?: string\n right?: string\n handleContainer?: string\n handleIcon?: string\n}\n\nexport type RevealRowHandle = {\n close: (animated?: boolean | AnimationPreset | AnimationConfig) => void\n reveal: (\n position: RevealPosition,\n animated?: boolean | AnimationPreset | AnimationConfig,\n ) => void\n}\n\nexport type RevealRowProps = {\n /** Primary row content (e.g. title, subtitle). */\n children: ReactNode\n /** Optional leading action column (e.g. delete). Omitted in `right` mode. */\n left?: ReactNode\n /**\n * Trailing action column (e.g. add). Omitted in `left` mode.\n */\n right?: ReactNode\n /**\n * The HTML element to use for the root container.\n * @default 'div'\n */\n as?: RevealRowElement\n /**\n * If both `left` and `right` are set, defaults to `both`. If only one side,\n * mode is derived unless overridden.\n */\n mode?: RevealMode\n actionWidthLeft?: number\n actionWidthRight?: number\n classNames?: RevealRowClassNames\n /** @default true */\n showHandle?: boolean\n /** Replaces the built-in drag affordance. */\n handle?: ReactNode\n /**\n * Where the handle sits in the main row. Default: `start` in `left` mode,\n * `end` otherwise.\n */\n handlePosition?: RevealHandlePosition\n handleTitle?: string\n /** Shown in screen-reader text when using the default drag handle. */\n handleAriaLabel?: string\n /** Fires when the settled position changes. */\n onRevealChange?: (position: RevealPosition) => void\n onScroll?: (event: UIEvent<HTMLElement>) => void\n /** Resets to closed; default true. */\n resetWhenDisabled?: boolean\n disabled?: boolean\n /**\n * When true, snaps back to the closed position (e.g. row became active/selected\n * elsewhere in the list).\n */\n isActive?: boolean\n className?: string\n style?: CSSProperties\n /**\n * Default animation preset for close/reveal animations when action buttons are clicked.\n * @default 'quick'\n */\n animationPreset?: AnimationPreset\n /**\n * Custom animation configuration overriding the preset.\n */\n animationConfig?: AnimationConfig\n}\n","import {\n REVEAL_MODE,\n REVEAL_POSITION,\n type RevealMode,\n type RevealPosition,\n} from './types'\n\n/**\n * Map horizontal scroll position to a logical \"revealed\" state.\n * `wL` / `wR` are the fixed action column widths; `maxScroll` is\n * `Math.max(0, scrollWidth - clientWidth)`.\n */\nexport function getRevealFromScroll(\n scrollLeft: number,\n maxScroll: number,\n wL: number,\n wR: number,\n mode: RevealMode,\n): RevealPosition {\n if (mode === REVEAL_MODE.right) {\n if (maxScroll <= 0) return REVEAL_POSITION.center\n return scrollLeft < wR / 2 ? REVEAL_POSITION.center : REVEAL_POSITION.right\n }\n if (mode === REVEAL_MODE.left) {\n if (maxScroll <= 0) return REVEAL_POSITION.center\n return scrollLeft < wL / 2 ? REVEAL_POSITION.left : REVEAL_POSITION.center\n }\n if (maxScroll <= 0) return REVEAL_POSITION.center\n if (scrollLeft < wL / 2) return REVEAL_POSITION.left\n if (scrollLeft > maxScroll - wR / 2) return REVEAL_POSITION.right\n return REVEAL_POSITION.center\n}\n\n/** \"Closed\" / resting scrollLeft for a mode (main panel only). */\nexport function getScrollClosed(\n wL: number,\n _wR: number,\n _maxScroll: number,\n mode: RevealMode,\n): number {\n if (mode === REVEAL_MODE.right) return 0\n return wL\n}\n","'use client'\n\nimport type { CSSProperties, ForwardedRef, MouseEvent, UIEvent } from 'react'\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n} from 'react'\n\nimport { DefaultHandleIcon } from './DefaultHandleIcon'\nimport { getRevealFromScroll, getScrollClosed } from './getRevealFromScroll'\nimport {\n ANIMATION_PRESET,\n ANIMATION_PRESETS,\n type AnimationConfig,\n type AnimationPreset,\n REVEAL_HANDLE_POSITION,\n REVEAL_MODE,\n REVEAL_POSITION,\n type RevealHandlePosition,\n type RevealMode,\n type RevealPosition,\n type RevealRowClassNames,\n type RevealRowHandle,\n type RevealRowProps,\n} from './types'\n\nfunction cx(...parts: (string | undefined)[]) {\n return parts.filter(Boolean).join(' ')\n}\n\nfunction getMaxScroll(el: HTMLElement) {\n return Math.max(0, el.scrollWidth - el.clientWidth)\n}\n\nfunction resolveMode(\n left: RevealRowProps['left'],\n right: RevealRowProps['right'],\n mode: RevealMode | undefined,\n): RevealMode {\n if (mode) return mode\n if (left != null && right != null) return REVEAL_MODE.both\n if (left != null) return REVEAL_MODE.left\n return REVEAL_MODE.right\n}\n\nfunction resolveAnimationConfig(\n animated: boolean | AnimationPreset | AnimationConfig | undefined,\n defaultPreset: AnimationPreset,\n customConfig?: AnimationConfig,\n): AnimationConfig {\n let config: AnimationConfig\n\n if (animated === false) {\n config = ANIMATION_PRESETS[ANIMATION_PRESET.none]\n } else if (animated === true || animated === undefined) {\n config = customConfig || ANIMATION_PRESETS[defaultPreset]\n } else if (typeof animated === 'string') {\n config = ANIMATION_PRESETS[animated]\n } else {\n config = animated\n }\n\n // Validate and clamp duration to be >= 0\n return {\n ...config,\n duration: Math.max(\n 0,\n Number.isFinite(config.duration) ? config.duration : 0,\n ),\n }\n}\n\nconst SCROLL_REVEAL_DEBOUNCE_MS = 64\nconst restEpsilon = 2\n\nconst rootScrollStyle: CSSProperties = {\n display: 'grid',\n overflowX: 'auto',\n scrollSnapType: 'x mandatory',\n scrollbarWidth: 'none',\n WebkitOverflowScrolling: 'touch',\n overscrollBehaviorX: 'contain',\n touchAction: 'pan-x pan-y',\n}\n\nconst rootScrollStyleDisabled: CSSProperties = {\n ...rootScrollStyle,\n overflowX: 'hidden',\n touchAction: 'pan-y',\n}\n\nconst snapStart: CSSProperties = { scrollSnapAlign: 'start' }\nconst snapEnd: CSSProperties = { scrollSnapAlign: 'end' }\n\ntype InnerProps = RevealRowProps & {\n forwardedRef: ForwardedRef<RevealRowHandle>\n}\n\nfunction RevealRowInner({\n children,\n left,\n right,\n as: Element = 'div',\n mode: modeProp,\n actionWidthLeft: wLIn,\n actionWidthRight: wRIn,\n classNames = {} as RevealRowClassNames,\n showHandle = true,\n handle: handleOverride,\n handlePosition: handlePositionProp,\n handleTitle = 'Drag horizontally to show actions',\n handleAriaLabel = 'Drag horizontally to show actions',\n onRevealChange,\n onScroll: onScrollProp,\n resetWhenDisabled = true,\n disabled = false,\n isActive = false,\n className,\n style,\n animationPreset = ANIMATION_PRESET.quick,\n animationConfig,\n forwardedRef,\n}: InnerProps) {\n const mode = resolveMode(left, right, modeProp)\n const hasL = mode === REVEAL_MODE.left || mode === REVEAL_MODE.both\n const hasR = mode === REVEAL_MODE.right || mode === REVEAL_MODE.both\n const wL = hasL ? (wLIn ?? 88) : 0\n const wR = hasR ? (wRIn ?? 88) : 0\n\n const handlePosition: RevealHandlePosition =\n handlePositionProp ??\n (mode === REVEAL_MODE.left\n ? REVEAL_HANDLE_POSITION.start\n : REVEAL_HANDLE_POSITION.end)\n\n const containerRef = useRef<HTMLElement>(null)\n const leftRef = useRef<HTMLDivElement>(null)\n const rightRef = useRef<HTMLDivElement>(null)\n const lastEmitted = useRef<RevealPosition | null>(null)\n const swipedRef = useRef(false)\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const hasAppliedInitialScroll = useRef(false)\n const isAnimatingRef = useRef(false)\n const rafIdRef = useRef<number | null>(null)\n const settleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const readPosition = useCallback((): RevealPosition => {\n const el = containerRef.current\n if (!el) return REVEAL_POSITION.center\n return getRevealFromScroll(el.scrollLeft, getMaxScroll(el), wL, wR, mode)\n }, [wL, wR, mode])\n\n const emitReveal = useCallback(\n (position: RevealPosition) => {\n if (lastEmitted.current === position) return\n lastEmitted.current = position\n onRevealChange?.(position)\n },\n [onRevealChange],\n )\n\n const scrollToClosed = useCallback(() => {\n const el = containerRef.current\n if (!el) return\n const m = getMaxScroll(el)\n const closed = getScrollClosed(wL, wR, m, mode)\n\n // For immediate scroll, we can use the default behavior\n // CSS scroll snap will handle the final positioning\n el.scrollLeft = closed\n }, [wL, wR, mode])\n\n const scrollToPosition = useCallback(\n (targetScrollLeft: number, animationOptions: AnimationConfig) => {\n const el = containerRef.current\n if (!el) return\n\n const { duration, easing } = animationOptions\n\n if (duration === 0) {\n el.scrollLeft = targetScrollLeft\n return\n }\n\n // Cancel any existing animation\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current)\n rafIdRef.current = null\n }\n if (settleTimerRef.current !== null) {\n clearTimeout(settleTimerRef.current)\n settleTimerRef.current = null\n }\n\n // Disable scroll snap during animation\n isAnimatingRef.current = true\n const originalScrollSnapType = el.style.scrollSnapType\n el.style.scrollSnapType = 'none'\n\n const startScrollLeft = el.scrollLeft\n const distance = targetScrollLeft - startScrollLeft\n const startTime = performance.now()\n\n const animate = (currentTime: number) => {\n const elapsed = currentTime - startTime\n const progress = Math.min(elapsed / duration, 1)\n\n let easedProgress = progress\n if (easing === 'ease-out') {\n easedProgress = 1 - (1 - progress) ** 2\n } else if (easing === 'ease-in-out') {\n easedProgress =\n progress < 0.5\n ? 2 * progress * progress\n : 1 - (-2 * progress + 2) ** 2 / 2\n } else if (easing.startsWith('cubic-bezier')) {\n // For the bounce effect, we'll use a simplified approximation\n easedProgress = progress * progress * (3 - 2 * progress)\n if (easing.includes('-0.55')) {\n // Bounce effect approximation\n easedProgress =\n progress < 0.5\n ? 4 * progress * progress * progress\n : 1 - (-2 * progress + 2) ** 3 / 2\n // Add overshoot for bounce\n if (progress > 0.7 && progress < 1) {\n easedProgress +=\n Math.sin((progress - 0.7) * Math.PI * 10) * 0.1 * (1 - progress)\n }\n }\n }\n\n el.scrollLeft = startScrollLeft + distance * easedProgress\n\n if (progress < 1) {\n rafIdRef.current = requestAnimationFrame(animate)\n } else {\n el.scrollLeft = targetScrollLeft\n // Re-enable scroll snap after animation completes\n el.style.scrollSnapType = originalScrollSnapType || 'x mandatory'\n isAnimatingRef.current = false\n rafIdRef.current = null\n }\n }\n\n rafIdRef.current = requestAnimationFrame(animate)\n },\n [],\n )\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n close: (animated?: boolean | AnimationPreset | AnimationConfig) => {\n const el = containerRef.current\n if (!el) return\n\n const m = getMaxScroll(el)\n const closed = getScrollClosed(wL, wR, m, mode)\n const animConfig = resolveAnimationConfig(\n animated,\n animationPreset,\n animationConfig,\n )\n\n scrollToPosition(closed, animConfig)\n\n // Update position after animation or immediately if no animation\n const delay = animConfig.duration > 0 ? animConfig.duration : 0\n if (settleTimerRef.current !== null) {\n clearTimeout(settleTimerRef.current)\n }\n settleTimerRef.current = setTimeout(() => {\n const p = readPosition()\n if (lastEmitted.current !== p) {\n lastEmitted.current = p\n onRevealChange?.(p)\n }\n settleTimerRef.current = null\n }, delay)\n },\n reveal: (\n position: RevealPosition,\n animated?: boolean | AnimationPreset | AnimationConfig,\n ) => {\n const el = containerRef.current\n if (!el) return\n const max = getMaxScroll(el)\n\n let targetScroll: number\n if (position === REVEAL_POSITION.center) {\n targetScroll = getScrollClosed(wL, wR, max, mode)\n } else if (\n position === REVEAL_POSITION.left &&\n (mode === REVEAL_MODE.left || mode === REVEAL_MODE.both)\n ) {\n targetScroll = 0\n } else if (\n position === REVEAL_POSITION.right &&\n (mode === REVEAL_MODE.right || mode === REVEAL_MODE.both)\n ) {\n targetScroll = max\n } else {\n return\n }\n\n const animConfig = resolveAnimationConfig(\n animated,\n animationPreset,\n animationConfig,\n )\n scrollToPosition(targetScroll, animConfig)\n\n // Update position after animation or immediately if no animation\n const delay = animConfig.duration > 0 ? animConfig.duration : 0\n if (settleTimerRef.current !== null) {\n clearTimeout(settleTimerRef.current)\n }\n settleTimerRef.current = setTimeout(() => {\n const p = getRevealFromScroll(targetScroll, max, wL, wR, mode)\n lastEmitted.current = p\n onRevealChange?.(p)\n settleTimerRef.current = null\n }, delay)\n },\n }),\n [\n mode,\n onRevealChange,\n readPosition,\n scrollToPosition,\n wL,\n wR,\n animationPreset,\n animationConfig,\n ],\n )\n\n useLayoutEffect(() => {\n if (mode === REVEAL_MODE.right) {\n return\n }\n const el = containerRef.current\n if (!el) return\n if (!hasAppliedInitialScroll.current) {\n el.scrollLeft = wL\n hasAppliedInitialScroll.current = true\n }\n }, [mode, wL])\n\n useEffect(() => {\n if (disabled && resetWhenDisabled) {\n hasAppliedInitialScroll.current = true\n scrollToClosed()\n emitReveal(readPosition())\n }\n }, [disabled, emitReveal, readPosition, resetWhenDisabled, scrollToClosed])\n\n useEffect(() => {\n if (isActive) {\n hasAppliedInitialScroll.current = true\n scrollToClosed()\n emitReveal(readPosition())\n }\n }, [emitReveal, isActive, readPosition, scrollToClosed])\n\n useEffect(\n () => () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current)\n }\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current)\n }\n if (settleTimerRef.current !== null) {\n clearTimeout(settleTimerRef.current)\n }\n },\n [],\n )\n\n const handleScroll = useCallback(\n (e: UIEvent<HTMLElement>) => {\n onScrollProp?.(e)\n const el = containerRef.current\n if (!el) return\n const m = getMaxScroll(el)\n const pos = getRevealFromScroll(el.scrollLeft, m, wL, wR, mode)\n const closed = getScrollClosed(wL, wR, m, mode)\n if (Math.abs(el.scrollLeft - closed) > restEpsilon) {\n swipedRef.current = true\n }\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current)\n }\n debounceTimer.current = setTimeout(() => {\n debounceTimer.current = null\n emitReveal(pos)\n }, SCROLL_REVEAL_DEBOUNCE_MS)\n },\n [emitReveal, mode, onScrollProp, wL, wR],\n )\n\n const onClickCapture = useCallback((e: MouseEvent) => {\n const t = e.target as Node | null\n if (t) {\n if (leftRef.current?.contains(t) || rightRef.current?.contains(t)) {\n return\n }\n }\n if (swipedRef.current) {\n e.preventDefault()\n e.stopPropagation()\n swipedRef.current = false\n }\n }, [])\n\n // `100%` for the main track (not `1fr`) so total row width > viewport: otherwise both\n // columns can shrink to fit with no overflow and the action stays visible.\n const gridTemplateColumns =\n mode === REVEAL_MODE.right\n ? `100% ${wR}px`\n : mode === REVEAL_MODE.left\n ? `${wL}px 100%`\n : `${wL}px 100% ${wR}px`\n\n const handleContent = showHandle ? (\n handleOverride !== undefined ? (\n handleOverride\n ) : (\n <>\n <span\n className=\"sr-only\"\n style={{\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0,0,0,0)',\n border: 0,\n }}\n >\n {handleAriaLabel}\n </span>\n <span className={classNames.handleIcon} aria-hidden>\n <DefaultHandleIcon />\n </span>\n </>\n )\n ) : null\n\n const handleStrip = showHandle ? (\n <div\n role=\"presentation\"\n className={classNames.handleContainer}\n data-reveal-row-handle\n style={{\n flexShrink: 0,\n alignSelf: 'stretch',\n display: 'flex',\n alignItems: 'center',\n }}\n title={handleOverride === undefined ? handleTitle : undefined}\n >\n {handleContent}\n </div>\n ) : null\n\n const mainColumn = (\n <div\n className={classNames.main}\n data-reveal-row-main\n style={{\n ...snapStart,\n minWidth: 0,\n width: '100%',\n maxWidth: '100%',\n boxSizing: 'border-box',\n }}\n >\n <div\n className={classNames.mainInner}\n style={{\n display: 'flex',\n minWidth: 0,\n width: '100%',\n alignItems: 'flex-start',\n }}\n >\n {handlePosition === REVEAL_HANDLE_POSITION.start && handleStrip}\n <div style={{ minWidth: 0, flex: 1, flexBasis: 0 }}>{children}</div>\n {handlePosition === REVEAL_HANDLE_POSITION.end && handleStrip}\n </div>\n </div>\n )\n\n return (\n <Element\n // biome-ignore lint/suspicious/noExplicitAny: Required for polymorphic ref compatibility\n ref={containerRef as any}\n data-reveal-mode={mode}\n className={cx(classNames.root, className)}\n onScroll={handleScroll}\n onClickCapture={onClickCapture}\n style={{\n ...(disabled ? rootScrollStyleDisabled : rootScrollStyle),\n ...style,\n gridTemplateColumns,\n }}\n >\n {hasL ? (\n <div\n ref={leftRef}\n className={classNames.left}\n data-reveal-row-left\n style={{ ...snapStart, minWidth: 0, width: wL }}\n >\n {left}\n </div>\n ) : null}\n {mainColumn}\n {hasR ? (\n <div\n ref={rightRef}\n className={classNames.right}\n data-reveal-row-right\n style={{ ...snapEnd, minWidth: 0, width: wR }}\n >\n {right}\n </div>\n ) : null}\n </Element>\n )\n}\n\nexport const RevealRow = forwardRef<RevealRowHandle, RevealRowProps>(\n function RevealRow(props, ref) {\n return <RevealRowInner {...props} forwardedRef={ref} />\n },\n)\n","/** Minimal 6-dot grip, no icon library dependency. */\nexport function DefaultHandleIcon() {\n return (\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n aria-hidden\n >\n <title>Drag handle</title>\n <circle cx=\"6\" cy=\"4\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"4\" r=\"1.2\" />\n <circle cx=\"6\" cy=\"8\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"8\" r=\"1.2\" />\n <circle cx=\"6\" cy=\"12\" r=\"1.2\" />\n <circle cx=\"10\" cy=\"12\" r=\"1.2\" />\n </svg>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs","RevealRow"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@present-day/reveal-row",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Horizontal scroll-to-reveal row for actions on the left, right, or both sides",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -58,10 +58,14 @@
|
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@biomejs/biome": "^2.4.13",
|
|
61
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
62
|
+
"@testing-library/react": "^16.3.2",
|
|
63
|
+
"@testing-library/user-event": "^14.6.1",
|
|
61
64
|
"@types/react": "^19.2.14",
|
|
62
65
|
"@types/react-dom": "^19.2.3",
|
|
63
66
|
"@vitejs/plugin-react": "^6.0.1",
|
|
64
67
|
"@vitest/coverage-istanbul": "^4.1.5",
|
|
68
|
+
"jsdom": "^29.0.2",
|
|
65
69
|
"react": "^19.2.5",
|
|
66
70
|
"react-dom": "^19.2.5",
|
|
67
71
|
"tsup": "^8.5.1",
|