@present-day/reveal-row 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +115 -0
- package/dist/index.d.mts +89 -0
- package/dist/index.d.ts +89 -0
- package/dist/index.js +390 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +365 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Present Day
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# `@present-day/reveal-row`
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @present-day/reveal-row
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Peer dependencies: `react`, `react-dom` (v18 or v19).
|
|
12
|
+
|
|
13
|
+
## Basic usage
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { RevealRow } from '@present-day/reveal-row'
|
|
17
|
+
|
|
18
|
+
// Right mode — swipe left to reveal
|
|
19
|
+
<RevealRow right={<button onClick={handleDelete}>Delete</button>}>
|
|
20
|
+
<MyRowContent />
|
|
21
|
+
</RevealRow>
|
|
22
|
+
|
|
23
|
+
// Left mode — swipe right to reveal
|
|
24
|
+
<RevealRow left={<button onClick={handlePin}>Pin</button>}>
|
|
25
|
+
<MyRowContent />
|
|
26
|
+
</RevealRow>
|
|
27
|
+
|
|
28
|
+
// Both modes — swipe either direction
|
|
29
|
+
<RevealRow
|
|
30
|
+
left={<button onClick={handlePin}>Pin</button>}
|
|
31
|
+
right={<button onClick={handleDelete}>Delete</button>}
|
|
32
|
+
>
|
|
33
|
+
<MyRowContent />
|
|
34
|
+
</RevealRow>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Modes
|
|
38
|
+
|
|
39
|
+
| `mode` | Slots used | Resting ("closed") scroll |
|
|
40
|
+
| ------- | -------------------- | ------------------------------------------- |
|
|
41
|
+
| `right` | `right` only | `scrollLeft = 0` (left edge) |
|
|
42
|
+
| `left` | `left` only | `scrollLeft = wL` (after leading column) |
|
|
43
|
+
| `both` | `left` and `right` | `scrollLeft = wL` (main fills viewport) |
|
|
44
|
+
|
|
45
|
+
Omit `mode` and it's inferred: both slots → `both`, only `left` → `left`, otherwise `right`.
|
|
46
|
+
|
|
47
|
+
## Props
|
|
48
|
+
|
|
49
|
+
| Prop | Type | Default | Description |
|
|
50
|
+
| ---- | ---- | ------- | ----------- |
|
|
51
|
+
| `children` | `ReactNode` | — | Primary row content |
|
|
52
|
+
| `left` | `ReactNode` | — | Leading action column |
|
|
53
|
+
| `right` | `ReactNode` | — | Trailing action column |
|
|
54
|
+
| `mode` | `'left' \| 'right' \| 'both'` | inferred | Override mode detection |
|
|
55
|
+
| `actionWidthLeft` | `number` | `88` | Width (px) of the left column |
|
|
56
|
+
| `actionWidthRight` | `number` | `88` | Width (px) of the right column |
|
|
57
|
+
| `classNames` | `RevealRowClassNames` | `{}` | Class names for each sub-element |
|
|
58
|
+
| `showHandle` | `boolean` | `true` | Render the default 6-dot drag affordance |
|
|
59
|
+
| `handle` | `ReactNode` | — | Replace the default handle with custom content |
|
|
60
|
+
| `handlePosition` | `'start' \| 'end'` | `'start'` in left mode, `'end'` otherwise | Where the handle strip sits in the row |
|
|
61
|
+
| `handleTitle` | `string` | `'Drag horizontally…'` | Tooltip on the default handle |
|
|
62
|
+
| `handleAriaLabel` | `string` | `'Drag horizontally…'` | Screen-reader text on the default handle |
|
|
63
|
+
| `onRevealChange` | `(pos: RevealPosition) => void` | — | Fires when the settled position changes (debounced) |
|
|
64
|
+
| `onScroll` | `UIEventHandler` | — | Raw scroll events |
|
|
65
|
+
| `disabled` | `boolean` | `false` | Disables swiping |
|
|
66
|
+
| `resetWhenDisabled` | `boolean` | `true` | Snap closed when `disabled` becomes true |
|
|
67
|
+
| `isActive` | `boolean` | `false` | Snap closed (e.g. another row was selected) |
|
|
68
|
+
| `className` | `string` | — | Added to the root scroll element |
|
|
69
|
+
| `style` | `CSSProperties` | — | Added to the root scroll element |
|
|
70
|
+
|
|
71
|
+
## Ref API
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
const ref = useRef<RevealRowHandle>(null)
|
|
75
|
+
|
|
76
|
+
<RevealRow ref={ref} right={<DeleteButton />}>
|
|
77
|
+
<MyRowContent />
|
|
78
|
+
</RevealRow>
|
|
79
|
+
|
|
80
|
+
// Programmatic control
|
|
81
|
+
ref.current?.close() // snap to center
|
|
82
|
+
ref.current?.reveal('left') // snap to left action
|
|
83
|
+
ref.current?.reveal('right') // snap to right action
|
|
84
|
+
ref.current?.reveal('center') // alias for close
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## classNames
|
|
88
|
+
|
|
89
|
+
All sub-elements accept class names for styling:
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
<RevealRow
|
|
93
|
+
classNames={{
|
|
94
|
+
root: 'my-row', // scroll container
|
|
95
|
+
main: 'my-row__main', // main content track
|
|
96
|
+
mainInner: '', // flex wrapper inside main
|
|
97
|
+
left: 'my-row__left', // left action column
|
|
98
|
+
right: 'my-row__right', // right action column
|
|
99
|
+
handleContainer: '', // outer handle strip
|
|
100
|
+
handleIcon: '', // icon wrapper inside handle
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Integration notes
|
|
106
|
+
|
|
107
|
+
**Nested vertical scroll** — the root uses `touch-action: pan-x pan-y` so a parent list can still scroll vertically.
|
|
108
|
+
|
|
109
|
+
**Overscroll / browser back gestures** — if horizontal swipes compete with iOS back or macOS trackpad history navigation, set `overscroll-behavior-x: none` on a suitable ancestor (e.g. a full-screen container).
|
|
110
|
+
|
|
111
|
+
**Preventing row activation on swipe** — the component guards against triggering a click after a horizontal drag. If you wrap the row in a command palette item or similar, keep the built-in `onClickCapture` behaviour intact, or replicate it.
|
|
112
|
+
|
|
113
|
+
## Publishing
|
|
114
|
+
|
|
115
|
+
Run `bun run build` to produce `dist/`. The `exports` field in `package.json` points to `dist/index.{js,mjs,d.ts}`. Push a tag to trigger the GitHub Actions publish workflow (OIDC trusted publishing — no npm token needed in secrets).
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, UIEvent, CSSProperties } from 'react';
|
|
3
|
+
|
|
4
|
+
declare const REVEAL_MODE: {
|
|
5
|
+
readonly left: "left";
|
|
6
|
+
readonly right: "right";
|
|
7
|
+
readonly both: "both";
|
|
8
|
+
};
|
|
9
|
+
type RevealMode = (typeof REVEAL_MODE)[keyof typeof REVEAL_MODE];
|
|
10
|
+
declare const REVEAL_POSITION: {
|
|
11
|
+
readonly left: "left";
|
|
12
|
+
readonly center: "center";
|
|
13
|
+
readonly right: "right";
|
|
14
|
+
};
|
|
15
|
+
type RevealPosition = (typeof REVEAL_POSITION)[keyof typeof REVEAL_POSITION];
|
|
16
|
+
declare const REVEAL_HANDLE_POSITION: {
|
|
17
|
+
readonly start: "start";
|
|
18
|
+
readonly end: "end";
|
|
19
|
+
};
|
|
20
|
+
type RevealHandlePosition = (typeof REVEAL_HANDLE_POSITION)[keyof typeof REVEAL_HANDLE_POSITION];
|
|
21
|
+
type RevealRowClassNames = {
|
|
22
|
+
root?: string;
|
|
23
|
+
main?: string;
|
|
24
|
+
mainInner?: string;
|
|
25
|
+
left?: string;
|
|
26
|
+
right?: string;
|
|
27
|
+
handleContainer?: string;
|
|
28
|
+
handleIcon?: string;
|
|
29
|
+
};
|
|
30
|
+
type RevealRowHandle = {
|
|
31
|
+
close: () => void;
|
|
32
|
+
reveal: (position: RevealPosition) => void;
|
|
33
|
+
};
|
|
34
|
+
type RevealRowProps = {
|
|
35
|
+
/** Primary row content (e.g. title, subtitle). */
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
/** Optional leading action column (e.g. delete). Omitted in `right` mode. */
|
|
38
|
+
left?: ReactNode;
|
|
39
|
+
/**
|
|
40
|
+
* Trailing action column (e.g. add). Omitted in `left` mode.
|
|
41
|
+
*/
|
|
42
|
+
right?: ReactNode;
|
|
43
|
+
/**
|
|
44
|
+
* If both `left` and `right` are set, defaults to `both`. If only one side,
|
|
45
|
+
* mode is derived unless overridden.
|
|
46
|
+
*/
|
|
47
|
+
mode?: RevealMode;
|
|
48
|
+
actionWidthLeft?: number;
|
|
49
|
+
actionWidthRight?: number;
|
|
50
|
+
classNames?: RevealRowClassNames;
|
|
51
|
+
/** @default true */
|
|
52
|
+
showHandle?: boolean;
|
|
53
|
+
/** Replaces the built-in drag affordance. */
|
|
54
|
+
handle?: ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* Where the handle sits in the main row. Default: `start` in `left` mode,
|
|
57
|
+
* `end` otherwise.
|
|
58
|
+
*/
|
|
59
|
+
handlePosition?: RevealHandlePosition;
|
|
60
|
+
handleTitle?: string;
|
|
61
|
+
/** Shown in screen-reader text when using the default drag handle. */
|
|
62
|
+
handleAriaLabel?: string;
|
|
63
|
+
/** Fires when the settled position changes. */
|
|
64
|
+
onRevealChange?: (position: RevealPosition) => void;
|
|
65
|
+
onScroll?: (event: UIEvent<HTMLDivElement>) => void;
|
|
66
|
+
/** Resets to closed; default true. */
|
|
67
|
+
resetWhenDisabled?: boolean;
|
|
68
|
+
disabled?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* When true, snaps back to the closed position (e.g. row became active/selected
|
|
71
|
+
* elsewhere in the list).
|
|
72
|
+
*/
|
|
73
|
+
isActive?: boolean;
|
|
74
|
+
className?: string;
|
|
75
|
+
style?: CSSProperties;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Map horizontal scroll position to a logical "revealed" state.
|
|
80
|
+
* `wL` / `wR` are the fixed action column widths; `maxScroll` is
|
|
81
|
+
* `Math.max(0, scrollWidth - clientWidth)`.
|
|
82
|
+
*/
|
|
83
|
+
declare function getRevealFromScroll(scrollLeft: number, maxScroll: number, wL: number, wR: number, mode: RevealMode): RevealPosition;
|
|
84
|
+
/** "Closed" / resting scrollLeft for a mode (main panel only). */
|
|
85
|
+
declare function getScrollClosed(wL: number, _wR: number, _maxScroll: number, mode: RevealMode): number;
|
|
86
|
+
|
|
87
|
+
declare const RevealRow: react.ForwardRefExoticComponent<RevealRowProps & react.RefAttributes<RevealRowHandle>>;
|
|
88
|
+
|
|
89
|
+
export { REVEAL_HANDLE_POSITION, REVEAL_MODE, REVEAL_POSITION, type RevealHandlePosition, type RevealMode, type RevealPosition, RevealRow, type RevealRowClassNames, type RevealRowHandle, type RevealRowProps, getRevealFromScroll, getScrollClosed };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, UIEvent, CSSProperties } from 'react';
|
|
3
|
+
|
|
4
|
+
declare const REVEAL_MODE: {
|
|
5
|
+
readonly left: "left";
|
|
6
|
+
readonly right: "right";
|
|
7
|
+
readonly both: "both";
|
|
8
|
+
};
|
|
9
|
+
type RevealMode = (typeof REVEAL_MODE)[keyof typeof REVEAL_MODE];
|
|
10
|
+
declare const REVEAL_POSITION: {
|
|
11
|
+
readonly left: "left";
|
|
12
|
+
readonly center: "center";
|
|
13
|
+
readonly right: "right";
|
|
14
|
+
};
|
|
15
|
+
type RevealPosition = (typeof REVEAL_POSITION)[keyof typeof REVEAL_POSITION];
|
|
16
|
+
declare const REVEAL_HANDLE_POSITION: {
|
|
17
|
+
readonly start: "start";
|
|
18
|
+
readonly end: "end";
|
|
19
|
+
};
|
|
20
|
+
type RevealHandlePosition = (typeof REVEAL_HANDLE_POSITION)[keyof typeof REVEAL_HANDLE_POSITION];
|
|
21
|
+
type RevealRowClassNames = {
|
|
22
|
+
root?: string;
|
|
23
|
+
main?: string;
|
|
24
|
+
mainInner?: string;
|
|
25
|
+
left?: string;
|
|
26
|
+
right?: string;
|
|
27
|
+
handleContainer?: string;
|
|
28
|
+
handleIcon?: string;
|
|
29
|
+
};
|
|
30
|
+
type RevealRowHandle = {
|
|
31
|
+
close: () => void;
|
|
32
|
+
reveal: (position: RevealPosition) => void;
|
|
33
|
+
};
|
|
34
|
+
type RevealRowProps = {
|
|
35
|
+
/** Primary row content (e.g. title, subtitle). */
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
/** Optional leading action column (e.g. delete). Omitted in `right` mode. */
|
|
38
|
+
left?: ReactNode;
|
|
39
|
+
/**
|
|
40
|
+
* Trailing action column (e.g. add). Omitted in `left` mode.
|
|
41
|
+
*/
|
|
42
|
+
right?: ReactNode;
|
|
43
|
+
/**
|
|
44
|
+
* If both `left` and `right` are set, defaults to `both`. If only one side,
|
|
45
|
+
* mode is derived unless overridden.
|
|
46
|
+
*/
|
|
47
|
+
mode?: RevealMode;
|
|
48
|
+
actionWidthLeft?: number;
|
|
49
|
+
actionWidthRight?: number;
|
|
50
|
+
classNames?: RevealRowClassNames;
|
|
51
|
+
/** @default true */
|
|
52
|
+
showHandle?: boolean;
|
|
53
|
+
/** Replaces the built-in drag affordance. */
|
|
54
|
+
handle?: ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* Where the handle sits in the main row. Default: `start` in `left` mode,
|
|
57
|
+
* `end` otherwise.
|
|
58
|
+
*/
|
|
59
|
+
handlePosition?: RevealHandlePosition;
|
|
60
|
+
handleTitle?: string;
|
|
61
|
+
/** Shown in screen-reader text when using the default drag handle. */
|
|
62
|
+
handleAriaLabel?: string;
|
|
63
|
+
/** Fires when the settled position changes. */
|
|
64
|
+
onRevealChange?: (position: RevealPosition) => void;
|
|
65
|
+
onScroll?: (event: UIEvent<HTMLDivElement>) => void;
|
|
66
|
+
/** Resets to closed; default true. */
|
|
67
|
+
resetWhenDisabled?: boolean;
|
|
68
|
+
disabled?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* When true, snaps back to the closed position (e.g. row became active/selected
|
|
71
|
+
* elsewhere in the list).
|
|
72
|
+
*/
|
|
73
|
+
isActive?: boolean;
|
|
74
|
+
className?: string;
|
|
75
|
+
style?: CSSProperties;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Map horizontal scroll position to a logical "revealed" state.
|
|
80
|
+
* `wL` / `wR` are the fixed action column widths; `maxScroll` is
|
|
81
|
+
* `Math.max(0, scrollWidth - clientWidth)`.
|
|
82
|
+
*/
|
|
83
|
+
declare function getRevealFromScroll(scrollLeft: number, maxScroll: number, wL: number, wR: number, mode: RevealMode): RevealPosition;
|
|
84
|
+
/** "Closed" / resting scrollLeft for a mode (main panel only). */
|
|
85
|
+
declare function getScrollClosed(wL: number, _wR: number, _maxScroll: number, mode: RevealMode): number;
|
|
86
|
+
|
|
87
|
+
declare const RevealRow: react.ForwardRefExoticComponent<RevealRowProps & react.RefAttributes<RevealRowHandle>>;
|
|
88
|
+
|
|
89
|
+
export { REVEAL_HANDLE_POSITION, REVEAL_MODE, REVEAL_POSITION, type RevealHandlePosition, type RevealMode, type RevealPosition, RevealRow, type RevealRowClassNames, type RevealRowHandle, type RevealRowProps, getRevealFromScroll, getScrollClosed };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
REVEAL_HANDLE_POSITION: () => REVEAL_HANDLE_POSITION,
|
|
24
|
+
REVEAL_MODE: () => REVEAL_MODE,
|
|
25
|
+
REVEAL_POSITION: () => REVEAL_POSITION,
|
|
26
|
+
RevealRow: () => RevealRow,
|
|
27
|
+
getRevealFromScroll: () => getRevealFromScroll,
|
|
28
|
+
getScrollClosed: () => getScrollClosed
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
|
|
32
|
+
// src/types.ts
|
|
33
|
+
var REVEAL_MODE = {
|
|
34
|
+
left: "left",
|
|
35
|
+
right: "right",
|
|
36
|
+
both: "both"
|
|
37
|
+
};
|
|
38
|
+
var REVEAL_POSITION = {
|
|
39
|
+
left: "left",
|
|
40
|
+
center: "center",
|
|
41
|
+
right: "right"
|
|
42
|
+
};
|
|
43
|
+
var REVEAL_HANDLE_POSITION = {
|
|
44
|
+
start: "start",
|
|
45
|
+
end: "end"
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// src/getRevealFromScroll.ts
|
|
49
|
+
function getRevealFromScroll(scrollLeft, maxScroll, wL, wR, mode) {
|
|
50
|
+
if (mode === REVEAL_MODE.right) {
|
|
51
|
+
if (maxScroll <= 0) return REVEAL_POSITION.center;
|
|
52
|
+
return scrollLeft < wR / 2 ? REVEAL_POSITION.center : REVEAL_POSITION.right;
|
|
53
|
+
}
|
|
54
|
+
if (mode === REVEAL_MODE.left) {
|
|
55
|
+
if (maxScroll <= 0) return REVEAL_POSITION.center;
|
|
56
|
+
return scrollLeft < wL / 2 ? REVEAL_POSITION.left : REVEAL_POSITION.center;
|
|
57
|
+
}
|
|
58
|
+
if (maxScroll <= 0) return REVEAL_POSITION.center;
|
|
59
|
+
if (scrollLeft < wL / 2) return REVEAL_POSITION.left;
|
|
60
|
+
if (scrollLeft > maxScroll - wR / 2) return REVEAL_POSITION.right;
|
|
61
|
+
return REVEAL_POSITION.center;
|
|
62
|
+
}
|
|
63
|
+
function getScrollClosed(wL, _wR, _maxScroll, mode) {
|
|
64
|
+
if (mode === REVEAL_MODE.right) return 0;
|
|
65
|
+
return wL;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/RevealRow.tsx
|
|
69
|
+
var import_react = require("react");
|
|
70
|
+
|
|
71
|
+
// src/DefaultHandleIcon.tsx
|
|
72
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
73
|
+
function DefaultHandleIcon() {
|
|
74
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
75
|
+
"svg",
|
|
76
|
+
{
|
|
77
|
+
width: 16,
|
|
78
|
+
height: 16,
|
|
79
|
+
viewBox: "0 0 16 16",
|
|
80
|
+
fill: "currentColor",
|
|
81
|
+
"aria-hidden": true,
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6", cy: "4", r: "1.2" }),
|
|
84
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "10", cy: "4", r: "1.2" }),
|
|
85
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6", cy: "8", r: "1.2" }),
|
|
86
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "10", cy: "8", r: "1.2" }),
|
|
87
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6", cy: "12", r: "1.2" }),
|
|
88
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "10", cy: "12", r: "1.2" })
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/RevealRow.tsx
|
|
95
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
96
|
+
function cx(...parts) {
|
|
97
|
+
return parts.filter(Boolean).join(" ");
|
|
98
|
+
}
|
|
99
|
+
function getMaxScroll(el) {
|
|
100
|
+
return Math.max(0, el.scrollWidth - el.clientWidth);
|
|
101
|
+
}
|
|
102
|
+
function resolveMode(left, right, mode) {
|
|
103
|
+
if (mode) return mode;
|
|
104
|
+
if (left != null && right != null) return REVEAL_MODE.both;
|
|
105
|
+
if (left != null) return REVEAL_MODE.left;
|
|
106
|
+
return REVEAL_MODE.right;
|
|
107
|
+
}
|
|
108
|
+
var SCROLL_REVEAL_DEBOUNCE_MS = 64;
|
|
109
|
+
var restEpsilon = 2;
|
|
110
|
+
var rootScrollStyle = {
|
|
111
|
+
display: "grid",
|
|
112
|
+
overflowX: "auto",
|
|
113
|
+
scrollSnapType: "x mandatory",
|
|
114
|
+
scrollbarWidth: "none",
|
|
115
|
+
WebkitOverflowScrolling: "touch",
|
|
116
|
+
overscrollBehaviorX: "contain",
|
|
117
|
+
touchAction: "pan-x pan-y"
|
|
118
|
+
};
|
|
119
|
+
var snapStart = { scrollSnapAlign: "start" };
|
|
120
|
+
var snapEnd = { scrollSnapAlign: "end" };
|
|
121
|
+
function RevealRowInner({
|
|
122
|
+
children,
|
|
123
|
+
left,
|
|
124
|
+
right,
|
|
125
|
+
mode: modeProp,
|
|
126
|
+
actionWidthLeft: wLIn,
|
|
127
|
+
actionWidthRight: wRIn,
|
|
128
|
+
classNames = {},
|
|
129
|
+
showHandle = true,
|
|
130
|
+
handle: handleOverride,
|
|
131
|
+
handlePosition: handlePositionProp,
|
|
132
|
+
handleTitle = "Drag horizontally to show actions",
|
|
133
|
+
handleAriaLabel = "Drag horizontally to show actions",
|
|
134
|
+
onRevealChange,
|
|
135
|
+
onScroll: onScrollProp,
|
|
136
|
+
resetWhenDisabled = true,
|
|
137
|
+
disabled = false,
|
|
138
|
+
isActive = false,
|
|
139
|
+
className,
|
|
140
|
+
style,
|
|
141
|
+
forwardedRef
|
|
142
|
+
}) {
|
|
143
|
+
const mode = resolveMode(left, right, modeProp);
|
|
144
|
+
const hasL = mode === REVEAL_MODE.left || mode === REVEAL_MODE.both;
|
|
145
|
+
const hasR = mode === REVEAL_MODE.right || mode === REVEAL_MODE.both;
|
|
146
|
+
const wL = hasL ? wLIn ?? 88 : 0;
|
|
147
|
+
const wR = hasR ? wRIn ?? 88 : 0;
|
|
148
|
+
const handlePosition = handlePositionProp ?? (mode === REVEAL_MODE.left ? REVEAL_HANDLE_POSITION.start : REVEAL_HANDLE_POSITION.end);
|
|
149
|
+
const containerRef = (0, import_react.useRef)(null);
|
|
150
|
+
const leftRef = (0, import_react.useRef)(null);
|
|
151
|
+
const rightRef = (0, import_react.useRef)(null);
|
|
152
|
+
const lastEmitted = (0, import_react.useRef)(null);
|
|
153
|
+
const swipedRef = (0, import_react.useRef)(false);
|
|
154
|
+
const debounceTimer = (0, import_react.useRef)(null);
|
|
155
|
+
const hasAppliedInitialScroll = (0, import_react.useRef)(false);
|
|
156
|
+
const readPosition = (0, import_react.useCallback)(() => {
|
|
157
|
+
const el = containerRef.current;
|
|
158
|
+
if (!el) return REVEAL_POSITION.center;
|
|
159
|
+
return getRevealFromScroll(el.scrollLeft, getMaxScroll(el), wL, wR, mode);
|
|
160
|
+
}, [wL, wR, mode]);
|
|
161
|
+
const emitReveal = (0, import_react.useCallback)(
|
|
162
|
+
(position) => {
|
|
163
|
+
if (lastEmitted.current === position) return;
|
|
164
|
+
lastEmitted.current = position;
|
|
165
|
+
onRevealChange?.(position);
|
|
166
|
+
},
|
|
167
|
+
[onRevealChange]
|
|
168
|
+
);
|
|
169
|
+
const scrollToClosed = (0, import_react.useCallback)(() => {
|
|
170
|
+
const el = containerRef.current;
|
|
171
|
+
if (!el) return;
|
|
172
|
+
const m = getMaxScroll(el);
|
|
173
|
+
const closed = getScrollClosed(wL, wR, m, mode);
|
|
174
|
+
el.scrollLeft = closed;
|
|
175
|
+
}, [wL, wR, mode]);
|
|
176
|
+
(0, import_react.useImperativeHandle)(
|
|
177
|
+
forwardedRef,
|
|
178
|
+
() => ({
|
|
179
|
+
close: () => {
|
|
180
|
+
scrollToClosed();
|
|
181
|
+
const p = readPosition();
|
|
182
|
+
if (lastEmitted.current !== p) {
|
|
183
|
+
lastEmitted.current = p;
|
|
184
|
+
onRevealChange?.(p);
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
reveal: (position) => {
|
|
188
|
+
const el = containerRef.current;
|
|
189
|
+
if (!el) return;
|
|
190
|
+
const max = getMaxScroll(el);
|
|
191
|
+
if (position === REVEAL_POSITION.center) {
|
|
192
|
+
el.scrollLeft = getScrollClosed(wL, wR, max, mode);
|
|
193
|
+
} else if (position === REVEAL_POSITION.left && (mode === REVEAL_MODE.left || mode === REVEAL_MODE.both)) {
|
|
194
|
+
el.scrollLeft = 0;
|
|
195
|
+
} else if (position === REVEAL_POSITION.right && (mode === REVEAL_MODE.right || mode === REVEAL_MODE.both)) {
|
|
196
|
+
el.scrollLeft = max;
|
|
197
|
+
} else {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const p = getRevealFromScroll(el.scrollLeft, max, wL, wR, mode);
|
|
201
|
+
lastEmitted.current = p;
|
|
202
|
+
onRevealChange?.(p);
|
|
203
|
+
}
|
|
204
|
+
}),
|
|
205
|
+
[mode, onRevealChange, readPosition, scrollToClosed, wL, wR]
|
|
206
|
+
);
|
|
207
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
208
|
+
if (mode === REVEAL_MODE.right) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const el = containerRef.current;
|
|
212
|
+
if (!el) return;
|
|
213
|
+
if (!hasAppliedInitialScroll.current) {
|
|
214
|
+
el.scrollLeft = wL;
|
|
215
|
+
hasAppliedInitialScroll.current = true;
|
|
216
|
+
}
|
|
217
|
+
}, [mode, wL]);
|
|
218
|
+
(0, import_react.useEffect)(() => {
|
|
219
|
+
if (disabled && resetWhenDisabled) {
|
|
220
|
+
hasAppliedInitialScroll.current = true;
|
|
221
|
+
scrollToClosed();
|
|
222
|
+
emitReveal(readPosition());
|
|
223
|
+
}
|
|
224
|
+
}, [disabled, emitReveal, readPosition, resetWhenDisabled, scrollToClosed]);
|
|
225
|
+
(0, import_react.useEffect)(() => {
|
|
226
|
+
if (isActive) {
|
|
227
|
+
hasAppliedInitialScroll.current = true;
|
|
228
|
+
scrollToClosed();
|
|
229
|
+
emitReveal(readPosition());
|
|
230
|
+
}
|
|
231
|
+
}, [emitReveal, isActive, readPosition, scrollToClosed]);
|
|
232
|
+
(0, import_react.useEffect)(
|
|
233
|
+
() => () => {
|
|
234
|
+
if (debounceTimer.current) {
|
|
235
|
+
clearTimeout(debounceTimer.current);
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
[]
|
|
239
|
+
);
|
|
240
|
+
const handleScroll = (0, import_react.useCallback)(
|
|
241
|
+
(e) => {
|
|
242
|
+
onScrollProp?.(e);
|
|
243
|
+
const el = containerRef.current;
|
|
244
|
+
if (!el) return;
|
|
245
|
+
const m = getMaxScroll(el);
|
|
246
|
+
const pos = getRevealFromScroll(el.scrollLeft, m, wL, wR, mode);
|
|
247
|
+
const closed = getScrollClosed(wL, wR, m, mode);
|
|
248
|
+
if (Math.abs(el.scrollLeft - closed) > restEpsilon) {
|
|
249
|
+
swipedRef.current = true;
|
|
250
|
+
}
|
|
251
|
+
if (debounceTimer.current) {
|
|
252
|
+
clearTimeout(debounceTimer.current);
|
|
253
|
+
}
|
|
254
|
+
debounceTimer.current = setTimeout(() => {
|
|
255
|
+
debounceTimer.current = null;
|
|
256
|
+
emitReveal(pos);
|
|
257
|
+
}, SCROLL_REVEAL_DEBOUNCE_MS);
|
|
258
|
+
},
|
|
259
|
+
[emitReveal, mode, onScrollProp, wL, wR]
|
|
260
|
+
);
|
|
261
|
+
const onClickCapture = (0, import_react.useCallback)((e) => {
|
|
262
|
+
const t = e.target;
|
|
263
|
+
if (t) {
|
|
264
|
+
if (leftRef.current?.contains(t) || rightRef.current?.contains(t)) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (swipedRef.current) {
|
|
269
|
+
e.preventDefault();
|
|
270
|
+
e.stopPropagation();
|
|
271
|
+
swipedRef.current = false;
|
|
272
|
+
}
|
|
273
|
+
}, []);
|
|
274
|
+
const gridTemplateColumns = mode === REVEAL_MODE.right ? `100% ${wR}px` : mode === REVEAL_MODE.left ? `${wL}px 100%` : `${wL}px 100% ${wR}px`;
|
|
275
|
+
const handleContent = showHandle ? handleOverride !== void 0 ? handleOverride : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
276
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
277
|
+
"span",
|
|
278
|
+
{
|
|
279
|
+
className: "sr-only",
|
|
280
|
+
style: {
|
|
281
|
+
position: "absolute",
|
|
282
|
+
width: 1,
|
|
283
|
+
height: 1,
|
|
284
|
+
padding: 0,
|
|
285
|
+
margin: -1,
|
|
286
|
+
overflow: "hidden",
|
|
287
|
+
clip: "rect(0,0,0,0)",
|
|
288
|
+
border: 0
|
|
289
|
+
},
|
|
290
|
+
children: handleAriaLabel
|
|
291
|
+
}
|
|
292
|
+
),
|
|
293
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: classNames.handleIcon, "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DefaultHandleIcon, {}) })
|
|
294
|
+
] }) : null;
|
|
295
|
+
const handleStrip = showHandle ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
296
|
+
"div",
|
|
297
|
+
{
|
|
298
|
+
role: "presentation",
|
|
299
|
+
className: classNames.handleContainer,
|
|
300
|
+
"data-reveal-row-handle": true,
|
|
301
|
+
style: { flexShrink: 0, alignSelf: "stretch", display: "flex", alignItems: "center" },
|
|
302
|
+
title: handleOverride === void 0 ? handleTitle : void 0,
|
|
303
|
+
children: handleContent
|
|
304
|
+
}
|
|
305
|
+
) : null;
|
|
306
|
+
const mainColumn = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
307
|
+
"div",
|
|
308
|
+
{
|
|
309
|
+
className: classNames.main,
|
|
310
|
+
"data-reveal-row-main": true,
|
|
311
|
+
style: {
|
|
312
|
+
...snapStart,
|
|
313
|
+
minWidth: 0,
|
|
314
|
+
width: "100%",
|
|
315
|
+
maxWidth: "100%",
|
|
316
|
+
boxSizing: "border-box"
|
|
317
|
+
},
|
|
318
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
319
|
+
"div",
|
|
320
|
+
{
|
|
321
|
+
className: classNames.mainInner,
|
|
322
|
+
style: {
|
|
323
|
+
display: "flex",
|
|
324
|
+
minWidth: 0,
|
|
325
|
+
width: "100%",
|
|
326
|
+
alignItems: "flex-start"
|
|
327
|
+
},
|
|
328
|
+
children: [
|
|
329
|
+
handlePosition === REVEAL_HANDLE_POSITION.start && handleStrip,
|
|
330
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { minWidth: 0, flex: 1, flexBasis: 0 }, children }),
|
|
331
|
+
handlePosition === REVEAL_HANDLE_POSITION.end && handleStrip
|
|
332
|
+
]
|
|
333
|
+
}
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
338
|
+
"div",
|
|
339
|
+
{
|
|
340
|
+
ref: containerRef,
|
|
341
|
+
"data-reveal-mode": mode,
|
|
342
|
+
className: cx(classNames.root, className),
|
|
343
|
+
onScroll: handleScroll,
|
|
344
|
+
onClickCapture,
|
|
345
|
+
style: {
|
|
346
|
+
...rootScrollStyle,
|
|
347
|
+
...style,
|
|
348
|
+
gridTemplateColumns
|
|
349
|
+
},
|
|
350
|
+
children: [
|
|
351
|
+
hasL ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
352
|
+
"div",
|
|
353
|
+
{
|
|
354
|
+
ref: leftRef,
|
|
355
|
+
className: classNames.left,
|
|
356
|
+
"data-reveal-row-left": true,
|
|
357
|
+
style: { ...snapStart, minWidth: 0, width: wL },
|
|
358
|
+
children: left
|
|
359
|
+
}
|
|
360
|
+
) : null,
|
|
361
|
+
mainColumn,
|
|
362
|
+
hasR ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
363
|
+
"div",
|
|
364
|
+
{
|
|
365
|
+
ref: rightRef,
|
|
366
|
+
className: classNames.right,
|
|
367
|
+
"data-reveal-row-right": true,
|
|
368
|
+
style: { ...snapEnd, minWidth: 0, width: wR },
|
|
369
|
+
children: right
|
|
370
|
+
}
|
|
371
|
+
) : null
|
|
372
|
+
]
|
|
373
|
+
}
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
var RevealRow = (0, import_react.forwardRef)(
|
|
377
|
+
function RevealRow2(props, ref) {
|
|
378
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RevealRowInner, { ...props, forwardedRef: ref });
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
382
|
+
0 && (module.exports = {
|
|
383
|
+
REVEAL_HANDLE_POSITION,
|
|
384
|
+
REVEAL_MODE,
|
|
385
|
+
REVEAL_POSITION,
|
|
386
|
+
RevealRow,
|
|
387
|
+
getRevealFromScroll,
|
|
388
|
+
getScrollClosed
|
|
389
|
+
});
|
|
390
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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={{ flexShrink: 0, alignSelf: 'stretch', display: 'flex', alignItems: 'center' }}\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 <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
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var REVEAL_MODE = {
|
|
3
|
+
left: "left",
|
|
4
|
+
right: "right",
|
|
5
|
+
both: "both"
|
|
6
|
+
};
|
|
7
|
+
var REVEAL_POSITION = {
|
|
8
|
+
left: "left",
|
|
9
|
+
center: "center",
|
|
10
|
+
right: "right"
|
|
11
|
+
};
|
|
12
|
+
var REVEAL_HANDLE_POSITION = {
|
|
13
|
+
start: "start",
|
|
14
|
+
end: "end"
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/getRevealFromScroll.ts
|
|
18
|
+
function getRevealFromScroll(scrollLeft, maxScroll, wL, wR, mode) {
|
|
19
|
+
if (mode === REVEAL_MODE.right) {
|
|
20
|
+
if (maxScroll <= 0) return REVEAL_POSITION.center;
|
|
21
|
+
return scrollLeft < wR / 2 ? REVEAL_POSITION.center : REVEAL_POSITION.right;
|
|
22
|
+
}
|
|
23
|
+
if (mode === REVEAL_MODE.left) {
|
|
24
|
+
if (maxScroll <= 0) return REVEAL_POSITION.center;
|
|
25
|
+
return scrollLeft < wL / 2 ? REVEAL_POSITION.left : REVEAL_POSITION.center;
|
|
26
|
+
}
|
|
27
|
+
if (maxScroll <= 0) return REVEAL_POSITION.center;
|
|
28
|
+
if (scrollLeft < wL / 2) return REVEAL_POSITION.left;
|
|
29
|
+
if (scrollLeft > maxScroll - wR / 2) return REVEAL_POSITION.right;
|
|
30
|
+
return REVEAL_POSITION.center;
|
|
31
|
+
}
|
|
32
|
+
function getScrollClosed(wL, _wR, _maxScroll, mode) {
|
|
33
|
+
if (mode === REVEAL_MODE.right) return 0;
|
|
34
|
+
return wL;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/RevealRow.tsx
|
|
38
|
+
import {
|
|
39
|
+
forwardRef,
|
|
40
|
+
useCallback,
|
|
41
|
+
useEffect,
|
|
42
|
+
useImperativeHandle,
|
|
43
|
+
useLayoutEffect,
|
|
44
|
+
useRef
|
|
45
|
+
} from "react";
|
|
46
|
+
|
|
47
|
+
// src/DefaultHandleIcon.tsx
|
|
48
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
49
|
+
function DefaultHandleIcon() {
|
|
50
|
+
return /* @__PURE__ */ jsxs(
|
|
51
|
+
"svg",
|
|
52
|
+
{
|
|
53
|
+
width: 16,
|
|
54
|
+
height: 16,
|
|
55
|
+
viewBox: "0 0 16 16",
|
|
56
|
+
fill: "currentColor",
|
|
57
|
+
"aria-hidden": true,
|
|
58
|
+
children: [
|
|
59
|
+
/* @__PURE__ */ jsx("circle", { cx: "6", cy: "4", r: "1.2" }),
|
|
60
|
+
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "4", r: "1.2" }),
|
|
61
|
+
/* @__PURE__ */ jsx("circle", { cx: "6", cy: "8", r: "1.2" }),
|
|
62
|
+
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "8", r: "1.2" }),
|
|
63
|
+
/* @__PURE__ */ jsx("circle", { cx: "6", cy: "12", r: "1.2" }),
|
|
64
|
+
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "12", r: "1.2" })
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/RevealRow.tsx
|
|
71
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
72
|
+
function cx(...parts) {
|
|
73
|
+
return parts.filter(Boolean).join(" ");
|
|
74
|
+
}
|
|
75
|
+
function getMaxScroll(el) {
|
|
76
|
+
return Math.max(0, el.scrollWidth - el.clientWidth);
|
|
77
|
+
}
|
|
78
|
+
function resolveMode(left, right, mode) {
|
|
79
|
+
if (mode) return mode;
|
|
80
|
+
if (left != null && right != null) return REVEAL_MODE.both;
|
|
81
|
+
if (left != null) return REVEAL_MODE.left;
|
|
82
|
+
return REVEAL_MODE.right;
|
|
83
|
+
}
|
|
84
|
+
var SCROLL_REVEAL_DEBOUNCE_MS = 64;
|
|
85
|
+
var restEpsilon = 2;
|
|
86
|
+
var rootScrollStyle = {
|
|
87
|
+
display: "grid",
|
|
88
|
+
overflowX: "auto",
|
|
89
|
+
scrollSnapType: "x mandatory",
|
|
90
|
+
scrollbarWidth: "none",
|
|
91
|
+
WebkitOverflowScrolling: "touch",
|
|
92
|
+
overscrollBehaviorX: "contain",
|
|
93
|
+
touchAction: "pan-x pan-y"
|
|
94
|
+
};
|
|
95
|
+
var snapStart = { scrollSnapAlign: "start" };
|
|
96
|
+
var snapEnd = { scrollSnapAlign: "end" };
|
|
97
|
+
function RevealRowInner({
|
|
98
|
+
children,
|
|
99
|
+
left,
|
|
100
|
+
right,
|
|
101
|
+
mode: modeProp,
|
|
102
|
+
actionWidthLeft: wLIn,
|
|
103
|
+
actionWidthRight: wRIn,
|
|
104
|
+
classNames = {},
|
|
105
|
+
showHandle = true,
|
|
106
|
+
handle: handleOverride,
|
|
107
|
+
handlePosition: handlePositionProp,
|
|
108
|
+
handleTitle = "Drag horizontally to show actions",
|
|
109
|
+
handleAriaLabel = "Drag horizontally to show actions",
|
|
110
|
+
onRevealChange,
|
|
111
|
+
onScroll: onScrollProp,
|
|
112
|
+
resetWhenDisabled = true,
|
|
113
|
+
disabled = false,
|
|
114
|
+
isActive = false,
|
|
115
|
+
className,
|
|
116
|
+
style,
|
|
117
|
+
forwardedRef
|
|
118
|
+
}) {
|
|
119
|
+
const mode = resolveMode(left, right, modeProp);
|
|
120
|
+
const hasL = mode === REVEAL_MODE.left || mode === REVEAL_MODE.both;
|
|
121
|
+
const hasR = mode === REVEAL_MODE.right || mode === REVEAL_MODE.both;
|
|
122
|
+
const wL = hasL ? wLIn ?? 88 : 0;
|
|
123
|
+
const wR = hasR ? wRIn ?? 88 : 0;
|
|
124
|
+
const handlePosition = handlePositionProp ?? (mode === REVEAL_MODE.left ? REVEAL_HANDLE_POSITION.start : REVEAL_HANDLE_POSITION.end);
|
|
125
|
+
const containerRef = useRef(null);
|
|
126
|
+
const leftRef = useRef(null);
|
|
127
|
+
const rightRef = useRef(null);
|
|
128
|
+
const lastEmitted = useRef(null);
|
|
129
|
+
const swipedRef = useRef(false);
|
|
130
|
+
const debounceTimer = useRef(null);
|
|
131
|
+
const hasAppliedInitialScroll = useRef(false);
|
|
132
|
+
const readPosition = useCallback(() => {
|
|
133
|
+
const el = containerRef.current;
|
|
134
|
+
if (!el) return REVEAL_POSITION.center;
|
|
135
|
+
return getRevealFromScroll(el.scrollLeft, getMaxScroll(el), wL, wR, mode);
|
|
136
|
+
}, [wL, wR, mode]);
|
|
137
|
+
const emitReveal = useCallback(
|
|
138
|
+
(position) => {
|
|
139
|
+
if (lastEmitted.current === position) return;
|
|
140
|
+
lastEmitted.current = position;
|
|
141
|
+
onRevealChange?.(position);
|
|
142
|
+
},
|
|
143
|
+
[onRevealChange]
|
|
144
|
+
);
|
|
145
|
+
const scrollToClosed = useCallback(() => {
|
|
146
|
+
const el = containerRef.current;
|
|
147
|
+
if (!el) return;
|
|
148
|
+
const m = getMaxScroll(el);
|
|
149
|
+
const closed = getScrollClosed(wL, wR, m, mode);
|
|
150
|
+
el.scrollLeft = closed;
|
|
151
|
+
}, [wL, wR, mode]);
|
|
152
|
+
useImperativeHandle(
|
|
153
|
+
forwardedRef,
|
|
154
|
+
() => ({
|
|
155
|
+
close: () => {
|
|
156
|
+
scrollToClosed();
|
|
157
|
+
const p = readPosition();
|
|
158
|
+
if (lastEmitted.current !== p) {
|
|
159
|
+
lastEmitted.current = p;
|
|
160
|
+
onRevealChange?.(p);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
reveal: (position) => {
|
|
164
|
+
const el = containerRef.current;
|
|
165
|
+
if (!el) return;
|
|
166
|
+
const max = getMaxScroll(el);
|
|
167
|
+
if (position === REVEAL_POSITION.center) {
|
|
168
|
+
el.scrollLeft = getScrollClosed(wL, wR, max, mode);
|
|
169
|
+
} else if (position === REVEAL_POSITION.left && (mode === REVEAL_MODE.left || mode === REVEAL_MODE.both)) {
|
|
170
|
+
el.scrollLeft = 0;
|
|
171
|
+
} else if (position === REVEAL_POSITION.right && (mode === REVEAL_MODE.right || mode === REVEAL_MODE.both)) {
|
|
172
|
+
el.scrollLeft = max;
|
|
173
|
+
} else {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const p = getRevealFromScroll(el.scrollLeft, max, wL, wR, mode);
|
|
177
|
+
lastEmitted.current = p;
|
|
178
|
+
onRevealChange?.(p);
|
|
179
|
+
}
|
|
180
|
+
}),
|
|
181
|
+
[mode, onRevealChange, readPosition, scrollToClosed, wL, wR]
|
|
182
|
+
);
|
|
183
|
+
useLayoutEffect(() => {
|
|
184
|
+
if (mode === REVEAL_MODE.right) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const el = containerRef.current;
|
|
188
|
+
if (!el) return;
|
|
189
|
+
if (!hasAppliedInitialScroll.current) {
|
|
190
|
+
el.scrollLeft = wL;
|
|
191
|
+
hasAppliedInitialScroll.current = true;
|
|
192
|
+
}
|
|
193
|
+
}, [mode, wL]);
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
if (disabled && resetWhenDisabled) {
|
|
196
|
+
hasAppliedInitialScroll.current = true;
|
|
197
|
+
scrollToClosed();
|
|
198
|
+
emitReveal(readPosition());
|
|
199
|
+
}
|
|
200
|
+
}, [disabled, emitReveal, readPosition, resetWhenDisabled, scrollToClosed]);
|
|
201
|
+
useEffect(() => {
|
|
202
|
+
if (isActive) {
|
|
203
|
+
hasAppliedInitialScroll.current = true;
|
|
204
|
+
scrollToClosed();
|
|
205
|
+
emitReveal(readPosition());
|
|
206
|
+
}
|
|
207
|
+
}, [emitReveal, isActive, readPosition, scrollToClosed]);
|
|
208
|
+
useEffect(
|
|
209
|
+
() => () => {
|
|
210
|
+
if (debounceTimer.current) {
|
|
211
|
+
clearTimeout(debounceTimer.current);
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
[]
|
|
215
|
+
);
|
|
216
|
+
const handleScroll = useCallback(
|
|
217
|
+
(e) => {
|
|
218
|
+
onScrollProp?.(e);
|
|
219
|
+
const el = containerRef.current;
|
|
220
|
+
if (!el) return;
|
|
221
|
+
const m = getMaxScroll(el);
|
|
222
|
+
const pos = getRevealFromScroll(el.scrollLeft, m, wL, wR, mode);
|
|
223
|
+
const closed = getScrollClosed(wL, wR, m, mode);
|
|
224
|
+
if (Math.abs(el.scrollLeft - closed) > restEpsilon) {
|
|
225
|
+
swipedRef.current = true;
|
|
226
|
+
}
|
|
227
|
+
if (debounceTimer.current) {
|
|
228
|
+
clearTimeout(debounceTimer.current);
|
|
229
|
+
}
|
|
230
|
+
debounceTimer.current = setTimeout(() => {
|
|
231
|
+
debounceTimer.current = null;
|
|
232
|
+
emitReveal(pos);
|
|
233
|
+
}, SCROLL_REVEAL_DEBOUNCE_MS);
|
|
234
|
+
},
|
|
235
|
+
[emitReveal, mode, onScrollProp, wL, wR]
|
|
236
|
+
);
|
|
237
|
+
const onClickCapture = useCallback((e) => {
|
|
238
|
+
const t = e.target;
|
|
239
|
+
if (t) {
|
|
240
|
+
if (leftRef.current?.contains(t) || rightRef.current?.contains(t)) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (swipedRef.current) {
|
|
245
|
+
e.preventDefault();
|
|
246
|
+
e.stopPropagation();
|
|
247
|
+
swipedRef.current = false;
|
|
248
|
+
}
|
|
249
|
+
}, []);
|
|
250
|
+
const gridTemplateColumns = mode === REVEAL_MODE.right ? `100% ${wR}px` : mode === REVEAL_MODE.left ? `${wL}px 100%` : `${wL}px 100% ${wR}px`;
|
|
251
|
+
const handleContent = showHandle ? handleOverride !== void 0 ? handleOverride : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
252
|
+
/* @__PURE__ */ jsx2(
|
|
253
|
+
"span",
|
|
254
|
+
{
|
|
255
|
+
className: "sr-only",
|
|
256
|
+
style: {
|
|
257
|
+
position: "absolute",
|
|
258
|
+
width: 1,
|
|
259
|
+
height: 1,
|
|
260
|
+
padding: 0,
|
|
261
|
+
margin: -1,
|
|
262
|
+
overflow: "hidden",
|
|
263
|
+
clip: "rect(0,0,0,0)",
|
|
264
|
+
border: 0
|
|
265
|
+
},
|
|
266
|
+
children: handleAriaLabel
|
|
267
|
+
}
|
|
268
|
+
),
|
|
269
|
+
/* @__PURE__ */ jsx2("span", { className: classNames.handleIcon, "aria-hidden": true, children: /* @__PURE__ */ jsx2(DefaultHandleIcon, {}) })
|
|
270
|
+
] }) : null;
|
|
271
|
+
const handleStrip = showHandle ? /* @__PURE__ */ jsx2(
|
|
272
|
+
"div",
|
|
273
|
+
{
|
|
274
|
+
role: "presentation",
|
|
275
|
+
className: classNames.handleContainer,
|
|
276
|
+
"data-reveal-row-handle": true,
|
|
277
|
+
style: { flexShrink: 0, alignSelf: "stretch", display: "flex", alignItems: "center" },
|
|
278
|
+
title: handleOverride === void 0 ? handleTitle : void 0,
|
|
279
|
+
children: handleContent
|
|
280
|
+
}
|
|
281
|
+
) : null;
|
|
282
|
+
const mainColumn = /* @__PURE__ */ jsx2(
|
|
283
|
+
"div",
|
|
284
|
+
{
|
|
285
|
+
className: classNames.main,
|
|
286
|
+
"data-reveal-row-main": true,
|
|
287
|
+
style: {
|
|
288
|
+
...snapStart,
|
|
289
|
+
minWidth: 0,
|
|
290
|
+
width: "100%",
|
|
291
|
+
maxWidth: "100%",
|
|
292
|
+
boxSizing: "border-box"
|
|
293
|
+
},
|
|
294
|
+
children: /* @__PURE__ */ jsxs2(
|
|
295
|
+
"div",
|
|
296
|
+
{
|
|
297
|
+
className: classNames.mainInner,
|
|
298
|
+
style: {
|
|
299
|
+
display: "flex",
|
|
300
|
+
minWidth: 0,
|
|
301
|
+
width: "100%",
|
|
302
|
+
alignItems: "flex-start"
|
|
303
|
+
},
|
|
304
|
+
children: [
|
|
305
|
+
handlePosition === REVEAL_HANDLE_POSITION.start && handleStrip,
|
|
306
|
+
/* @__PURE__ */ jsx2("div", { style: { minWidth: 0, flex: 1, flexBasis: 0 }, children }),
|
|
307
|
+
handlePosition === REVEAL_HANDLE_POSITION.end && handleStrip
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
)
|
|
311
|
+
}
|
|
312
|
+
);
|
|
313
|
+
return /* @__PURE__ */ jsxs2(
|
|
314
|
+
"div",
|
|
315
|
+
{
|
|
316
|
+
ref: containerRef,
|
|
317
|
+
"data-reveal-mode": mode,
|
|
318
|
+
className: cx(classNames.root, className),
|
|
319
|
+
onScroll: handleScroll,
|
|
320
|
+
onClickCapture,
|
|
321
|
+
style: {
|
|
322
|
+
...rootScrollStyle,
|
|
323
|
+
...style,
|
|
324
|
+
gridTemplateColumns
|
|
325
|
+
},
|
|
326
|
+
children: [
|
|
327
|
+
hasL ? /* @__PURE__ */ jsx2(
|
|
328
|
+
"div",
|
|
329
|
+
{
|
|
330
|
+
ref: leftRef,
|
|
331
|
+
className: classNames.left,
|
|
332
|
+
"data-reveal-row-left": true,
|
|
333
|
+
style: { ...snapStart, minWidth: 0, width: wL },
|
|
334
|
+
children: left
|
|
335
|
+
}
|
|
336
|
+
) : null,
|
|
337
|
+
mainColumn,
|
|
338
|
+
hasR ? /* @__PURE__ */ jsx2(
|
|
339
|
+
"div",
|
|
340
|
+
{
|
|
341
|
+
ref: rightRef,
|
|
342
|
+
className: classNames.right,
|
|
343
|
+
"data-reveal-row-right": true,
|
|
344
|
+
style: { ...snapEnd, minWidth: 0, width: wR },
|
|
345
|
+
children: right
|
|
346
|
+
}
|
|
347
|
+
) : null
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
var RevealRow = forwardRef(
|
|
353
|
+
function RevealRow2(props, ref) {
|
|
354
|
+
return /* @__PURE__ */ jsx2(RevealRowInner, { ...props, forwardedRef: ref });
|
|
355
|
+
}
|
|
356
|
+
);
|
|
357
|
+
export {
|
|
358
|
+
REVEAL_HANDLE_POSITION,
|
|
359
|
+
REVEAL_MODE,
|
|
360
|
+
REVEAL_POSITION,
|
|
361
|
+
RevealRow,
|
|
362
|
+
getRevealFromScroll,
|
|
363
|
+
getScrollClosed
|
|
364
|
+
};
|
|
365
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +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={{ flexShrink: 0, alignSelf: 'stretch', display: 'flex', alignItems: 'center' }}\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 <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
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@present-day/reveal-row",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Horizontal scroll-to-reveal row for actions on the left, right, or both sides",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"packageManager": "bun@1.1.42",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"playground": "vite --config playground/vite.config.ts",
|
|
22
|
+
"playground:build": "vite build --config playground/vite.config.ts",
|
|
23
|
+
"playground:preview": "vite preview --config playground/vite.config.ts",
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"dev": "tsup --watch",
|
|
26
|
+
"lint": "biome check .",
|
|
27
|
+
"format": "biome check --write .",
|
|
28
|
+
"type-check": "tsc --noEmit",
|
|
29
|
+
"test": "bun --bun vitest run",
|
|
30
|
+
"test:coverage": "bun --bun vitest run --coverage",
|
|
31
|
+
"test:watch": "bun --bun vitest"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"react",
|
|
35
|
+
"reveal",
|
|
36
|
+
"swipe",
|
|
37
|
+
"scroll",
|
|
38
|
+
"list-row",
|
|
39
|
+
"actions",
|
|
40
|
+
"mobile"
|
|
41
|
+
],
|
|
42
|
+
"author": "Present Day",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/present-day/reveal-row.git"
|
|
47
|
+
},
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/present-day/reveal-row/issues"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/present-day/reveal-row#readme",
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"react": ">=18.0.0",
|
|
57
|
+
"react-dom": ">=18.0.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@biomejs/biome": "^2.4.13",
|
|
61
|
+
"@types/react": "^19.2.14",
|
|
62
|
+
"@types/react-dom": "^19.2.3",
|
|
63
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
64
|
+
"@vitest/coverage-istanbul": "^4.1.5",
|
|
65
|
+
"react": "^19.2.5",
|
|
66
|
+
"react-dom": "^19.2.5",
|
|
67
|
+
"tsup": "^8.5.1",
|
|
68
|
+
"typescript": "^6.0.3",
|
|
69
|
+
"vite": "^8.0.10",
|
|
70
|
+
"vitest": "^4.1.5"
|
|
71
|
+
}
|
|
72
|
+
}
|