@cellarnode/ui 0.19.1 → 0.19.2
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/dist/components/journey-card.d.ts +9 -1
- package/dist/components/journey-card.d.ts.map +1 -1
- package/dist/components/journey-card.js +13 -6
- package/dist/components/journey-card.js.map +1 -1
- package/dist/components/journey-card.stories.d.ts +2 -0
- package/dist/components/journey-card.stories.d.ts.map +1 -1
- package/dist/components/journey-card.stories.js +43 -0
- package/dist/components/journey-card.stories.js.map +1 -1
- package/dist/components/sortable-card-context.d.ts +18 -0
- package/dist/components/sortable-card-context.d.ts.map +1 -0
- package/dist/components/sortable-card-context.js +18 -0
- package/dist/components/sortable-card-context.js.map +1 -0
- package/dist/components/sortable-card-shell.d.ts +40 -21
- package/dist/components/sortable-card-shell.d.ts.map +1 -1
- package/dist/components/sortable-card-shell.js +46 -39
- package/dist/components/sortable-card-shell.js.map +1 -1
- package/dist/components/sortable-card-shell.stories.d.ts +1 -1
- package/dist/components/sortable-card-shell.stories.d.ts.map +1 -1
- package/dist/components/sortable-card-shell.stories.js +28 -15
- package/dist/components/sortable-card-shell.stories.js.map +1 -1
- package/dist/components/sortable-card-shell.test.js +57 -16
- package/dist/components/sortable-card-shell.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -42,8 +42,16 @@ export interface JourneyCardProps {
|
|
|
42
42
|
animate?: boolean;
|
|
43
43
|
/** Disable hover lift (used inside drag overlay) */
|
|
44
44
|
disableHover?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Force-show the drag grip in the top-left corner. Normally the card
|
|
47
|
+
* auto-detects whether it is rendered inside a `SortableCardShell` via
|
|
48
|
+
* `SortableCardContext`. Set to `false` to suppress the grip even when
|
|
49
|
+
* nested in a shell (e.g. inside a drag overlay preview). Set to `true`
|
|
50
|
+
* to show it outside of a shell (rare).
|
|
51
|
+
*/
|
|
52
|
+
showGrip?: boolean;
|
|
45
53
|
onClick?: () => void;
|
|
46
54
|
className?: string;
|
|
47
55
|
}
|
|
48
|
-
export declare function JourneyCard({ productImage, productInitials, title, subtitle, modified, activityDot, matchScore, progress, metaRight, metaRightTone, participants, titleIcon, actionsSlot, variant, animate, disableHover, onClick, className, }: JourneyCardProps): import("react/jsx-runtime").JSX.Element;
|
|
56
|
+
export declare function JourneyCard({ productImage, productInitials, title, subtitle, modified, activityDot, matchScore, progress, metaRight, metaRightTone, participants, titleIcon, actionsSlot, variant, animate, disableHover, showGrip, onClick, className, }: JourneyCardProps): import("react/jsx-runtime").JSX.Element;
|
|
49
57
|
//# sourceMappingURL=journey-card.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journey-card.d.ts","sourceRoot":"","sources":["../../src/components/journey-card.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"journey-card.d.ts","sourceRoot":"","sources":["../../src/components/journey-card.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAG9D,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAErE,MAAM,WAAW,gBAAgB;IAC/B,iGAAiG;IACjG,YAAY,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACxD,2FAA2F;IAC3F,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,gDAAgD;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,+BAA+B;IAC/B,aAAa,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IAChD,2CAA2C;IAC3C,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;IAC5B,6FAA6F;IAC7F,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,gCAAgC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,WAAW,CAAC,EAC1B,YAAY,EACZ,eAAe,EACf,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,WAAW,EACX,UAAU,EACV,QAAQ,EACR,SAAS,EACT,aAAyB,EACzB,YAAY,EACZ,SAAS,EACT,WAAW,EACX,OAAmB,EACnB,OAAe,EACf,YAAoB,EACpB,QAAQ,EACR,OAAO,EACP,SAAS,GACV,EAAE,gBAAgB,2CAyMlB"}
|
|
@@ -1,32 +1,39 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { motion } from "motion/react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Grip } from "lucide-react";
|
|
3
5
|
import { cn } from "../lib/utils";
|
|
4
6
|
import { AvatarStack } from "./avatar-stack";
|
|
7
|
+
import { SortableCardContext } from "./sortable-card-context";
|
|
5
8
|
const VARIANT_BG = {
|
|
6
9
|
default: "bg-[var(--card)]",
|
|
7
10
|
sent: "bg-[color-mix(in_oklab,white_96%,var(--primary)_4%)]",
|
|
8
11
|
won: "bg-[var(--tone-success-surface)] border-[color-mix(in_oklab,white_72%,var(--success)_28%)]",
|
|
9
12
|
lost: "bg-[color-mix(in_oklab,white_97%,var(--foreground)_3%)] opacity-90",
|
|
10
13
|
};
|
|
11
|
-
export function JourneyCard({ productImage, productInitials, title, subtitle, modified = false, activityDot, matchScore, progress, metaRight, metaRightTone = "default", participants, titleIcon, actionsSlot, variant = "default", animate = false, disableHover = false, onClick, className, }) {
|
|
14
|
+
export function JourneyCard({ productImage, productInitials, title, subtitle, modified = false, activityDot, matchScore, progress, metaRight, metaRightTone = "default", participants, titleIcon, actionsSlot, variant = "default", animate = false, disableHover = false, showGrip, onClick, className, }) {
|
|
12
15
|
const showInitials = !productImage && !!productInitials;
|
|
16
|
+
const { isDraggable } = React.use(SortableCardContext);
|
|
17
|
+
// Default: show grip whenever the card is nested in a SortableCardShell.
|
|
18
|
+
// Consumers can override either direction via `showGrip`.
|
|
19
|
+
const renderGrip = showGrip ?? isDraggable;
|
|
13
20
|
const shell = (_jsxs("div", { role: onClick ? "button" : undefined, tabIndex: onClick ? 0 : undefined, onClick: onClick, onKeyDown: (e) => {
|
|
14
21
|
if (onClick && (e.key === "Enter" || e.key === " ")) {
|
|
15
22
|
e.preventDefault();
|
|
16
23
|
onClick();
|
|
17
24
|
}
|
|
18
|
-
}, className: cn("group relative rounded-xl border border-[color-mix(in_oklab,var(--border)_60%,transparent)] p-3", "backdrop-blur-[14px] backdrop-saturate-[120%]", "shadow-[0_1px_2px_oklch(0.2_0.005_230/0.04),0_8px_24px_-18px_oklch(0.2_0.005_230/0.08),inset_0_1px_0_oklch(1_0_0/0.35)]", !disableHover &&
|
|
25
|
+
}, className: cn("group relative rounded-xl border border-[color-mix(in_oklab,var(--border)_60%,transparent)] p-3.5", "backdrop-blur-[14px] backdrop-saturate-[120%]", "shadow-[0_1px_2px_oklch(0.2_0.005_230/0.04),0_8px_24px_-18px_oklch(0.2_0.005_230/0.08),inset_0_1px_0_oklch(1_0_0/0.35)]", !disableHover &&
|
|
19
26
|
"transition-[transform,border-color,box-shadow] duration-[var(--duration-standard)] ease-[var(--ease-emphasized)] will-change-transform", !disableHover &&
|
|
20
|
-
"hover:-translate-y-1 hover:border-[color-mix(in_oklab,var(--primary)_22%,var(--border))] hover:shadow-[0_8px_20px_-12px_oklch(0.2_0.005_230/0.08),0_20px_50px_-30px_oklch(0.40_0.062_178/0.28),inset_0_1px_0_oklch(1_0_0/0.45)] hover:z-10 focus-within:z-10 has-[[data-open]]:z-50", VARIANT_BG[variant], onClick && "cursor-pointer", className), children: [_jsxs("div", { className: "flex items-start gap-[10px]", children: [productImage ? (_jsx("img", { src: productImage.url, alt: productImage.altText ?? "", width:
|
|
27
|
+
"hover:-translate-y-1 hover:border-[color-mix(in_oklab,var(--primary)_22%,var(--border))] hover:shadow-[0_8px_20px_-12px_oklch(0.2_0.005_230/0.08),0_20px_50px_-30px_oklch(0.40_0.062_178/0.28),inset_0_1px_0_oklch(1_0_0/0.45)] hover:z-10 focus-within:z-10 has-[[data-open]]:z-50", VARIANT_BG[variant], onClick && "cursor-pointer", className), children: [renderGrip && (_jsx("span", { "aria-hidden": "true", title: "Drag to reorder", className: "pointer-events-none absolute left-1.5 top-1.5 z-10 flex size-5 items-center justify-center rounded text-[var(--muted-foreground)] opacity-30 transition-opacity duration-[var(--duration-standard)] ease-[var(--ease-emphasized)] group-hover:opacity-100", children: _jsx(Grip, { className: "size-3.5" }) })), _jsxs("div", { className: cn("flex items-start gap-[10px]", renderGrip && "pl-5"), children: [productImage ? (_jsx("img", { src: productImage.url, alt: productImage.altText ?? "", width: 48, height: 48, loading: "lazy", className: "size-12 shrink-0 rounded-lg object-cover shadow-[0_2px_8px_-2px_oklch(0_0_0/0.15),inset_0_1px_0_oklch(1_0_0/0.2)]" })) : showInitials ? (_jsx("div", { className: "flex size-12 shrink-0 items-center justify-center rounded-lg text-sm font-bold tracking-tight text-white shadow-[0_2px_8px_-2px_oklch(0_0_0/0.15),inset_0_1px_0_oklch(1_0_0/0.2)]", style: {
|
|
21
28
|
background: "linear-gradient(135deg, color-mix(in oklab, var(--primary) 60%, white) 0%, color-mix(in oklab, var(--accent-secondary) 60%, white) 100%)",
|
|
22
29
|
fontFamily: "Sora, sans-serif",
|
|
23
|
-
}, "aria-hidden": "true", children: productInitials })) : (_jsx("div", { className: "flex size-
|
|
30
|
+
}, "aria-hidden": "true", children: productInitials })) : (_jsx("div", { className: "flex size-12 shrink-0 items-center justify-center rounded-lg text-lg", style: {
|
|
24
31
|
background: "color-mix(in oklab, white 94%, var(--primary) 6%)",
|
|
25
32
|
border: "1.5px dashed color-mix(in oklab, var(--primary) 30%, white)",
|
|
26
33
|
color: "color-mix(in oklab, var(--primary) 60%, var(--muted-foreground))",
|
|
27
|
-
}, "aria-hidden": "true", children: "+" })), _jsxs("div", { className: "min-w-0 flex-1 pt-0.5", children: [_jsxs("div", { className: "mb-[3px] flex items-center gap-1.5", children: [_jsx("div", { className: "min-w-0 flex-1 truncate font-display text-
|
|
34
|
+
}, "aria-hidden": "true", children: "+" })), _jsxs("div", { className: "min-w-0 flex-1 pt-0.5", children: [_jsxs("div", { className: "mb-[3px] flex items-center gap-1.5", children: [_jsx("div", { className: "min-w-0 flex-1 truncate font-display text-sm/tight font-semibold tracking-tight text-foreground", children: title }), modified && (_jsx("span", { title: "Modified for this offer", "aria-label": "Modified for this offer", className: "size-[7px] shrink-0 rounded-full bg-[var(--accent-secondary)] shadow-[0_0_0_3px_color-mix(in_oklab,var(--accent-secondary)_15%,transparent)]" })), activityDot && !modified && (_jsx("span", { title: "Recent activity", "aria-label": "Recent activity", className: "size-[7px] shrink-0 rounded-full bg-[var(--primary)] shadow-[0_0_0_3px_color-mix(in_oklab,var(--primary)_15%,transparent)]" })), titleIcon && (_jsx("span", { className: "shrink-0 text-[var(--accent-secondary)]", children: titleIcon })), typeof matchScore === "number" && (_jsxs("span", { className: cn("shrink-0 rounded-md px-1.5 py-[1px] text-[10px] font-semibold tabular-nums", matchScore >= 80
|
|
28
35
|
? "bg-[color-mix(in_oklab,var(--primary)_10%,transparent)] text-[color-mix(in_oklab,black_30%,var(--primary)_70%)]"
|
|
29
|
-
: "bg-[color-mix(in_oklab,var(--primary)_6%,transparent)] text-[var(--muted-foreground)]"), children: [matchScore, "%"] }))] }), subtitle && (_jsx("div", { className: "truncate text-
|
|
36
|
+
: "bg-[color-mix(in_oklab,var(--primary)_6%,transparent)] text-[var(--muted-foreground)]"), children: [matchScore, "%"] }))] }), subtitle && (_jsx("div", { className: "truncate text-xs/snug text-[var(--muted-foreground)]", children: subtitle }))] })] }), typeof progress === "number" && (_jsx("div", { className: "mt-[10px] h-1 overflow-hidden rounded-full bg-[color-mix(in_oklab,var(--primary)_8%,transparent)]", role: "progressbar", "aria-valuenow": Math.round(progress * 100), "aria-valuemin": 0, "aria-valuemax": 100, children: _jsx("div", { className: "h-full transition-[width] duration-[var(--duration-hero)] ease-[var(--ease-emphasized)]", style: {
|
|
30
37
|
width: `${Math.max(0, Math.min(1, progress)) * 100}%`,
|
|
31
38
|
background: "linear-gradient(90deg, var(--primary), color-mix(in oklab, var(--primary) 70%, var(--accent-secondary)))",
|
|
32
39
|
} }) })), ((participants && participants.length > 0) || metaRight || actionsSlot) && (_jsx("div", { className: "mx-0 my-[10px] h-px bg-linear-to-r from-transparent via-[color-mix(in_oklab,var(--primary)_15%,transparent)] to-transparent" })), ((participants && participants.length > 0) || metaRight || actionsSlot) && (_jsxs("div", { className: "flex items-center gap-2", children: [participants && participants.length > 0 ? (_jsx(AvatarStack, { orgs: participants, size: "sm" })) : (_jsx("span", {})), _jsx("span", { className: "flex-1" }), metaRight && (_jsx("span", { className: cn("text-right font-display text-xs tabular-nums tracking-tight", metaRightTone === "success" &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journey-card.js","sourceRoot":"","sources":["../../src/components/journey-card.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"journey-card.js","sourceRoot":"","sources":["../../src/components/journey-card.tsx"],"names":[],"mappings":"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"}
|
|
@@ -11,5 +11,7 @@ export declare const Sent: Story;
|
|
|
11
11
|
export declare const Won: Story;
|
|
12
12
|
export declare const WithAnimation: Story;
|
|
13
13
|
export declare const WithActivityDot: Story;
|
|
14
|
+
export declare const WithDragGrip: Story;
|
|
15
|
+
export declare const WithDragGripForceShown: Story;
|
|
14
16
|
export declare const WithActionsSlot: Story;
|
|
15
17
|
//# sourceMappingURL=journey-card.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journey-card.stories.d.ts","sourceRoot":"","sources":["../../src/components/journey-card.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"journey-card.stories.d.ts","sourceRoot":"","sources":["../../src/components/journey-card.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAYhC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAE9C,eAAO,MAAM,QAAQ,EAAE,KAUtB,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,KAUxC,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAWvB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAUzB,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAclB,CAAC;AAEF,eAAO,MAAM,GAAG,EAAE,KAejB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAQ3B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAU7B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KA0B1B,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,KAoBpC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KA2B7B,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Award, MoreHorizontal } from "lucide-react";
|
|
3
3
|
import { JourneyCard } from "./journey-card";
|
|
4
|
+
import { SortableCardContext } from "./sortable-card-shell";
|
|
4
5
|
const meta = {
|
|
5
6
|
title: "Components/JourneyCard",
|
|
6
7
|
component: JourneyCard,
|
|
@@ -105,6 +106,48 @@ export const WithActivityDot = {
|
|
|
105
106
|
metaRightTone: "muted",
|
|
106
107
|
},
|
|
107
108
|
};
|
|
109
|
+
export const WithDragGrip = {
|
|
110
|
+
name: "With drag grip (inside SortableCardShell)",
|
|
111
|
+
decorators: [
|
|
112
|
+
(Story) => (_jsx(SortableCardContext, { value: { isDraggable: true }, children: _jsx(Story, {}) })),
|
|
113
|
+
],
|
|
114
|
+
args: {
|
|
115
|
+
productInitials: "CR",
|
|
116
|
+
title: "Chardonnay Reserve 2021",
|
|
117
|
+
subtitle: "Nordic Wines · Organic whites",
|
|
118
|
+
participants: [{ id: "nw", name: "Nordic Wines" }],
|
|
119
|
+
metaRight: "2d ago",
|
|
120
|
+
metaRightTone: "muted",
|
|
121
|
+
onClick: () => { },
|
|
122
|
+
},
|
|
123
|
+
parameters: {
|
|
124
|
+
docs: {
|
|
125
|
+
description: {
|
|
126
|
+
story: "Cards rendered inside a `SortableCardShell` show a top-left grip affordance (6-dot grid, opacity 30% idle / 100% on hover). The grip is purely visual — `pointer-events-none` — so the whole card remains the drag activation surface. Toggle the story in isolation (not inside a shell) via the `Selected` story to verify the grip disappears outside a drag context.",
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
export const WithDragGripForceShown = {
|
|
132
|
+
name: "With drag grip (showGrip={true})",
|
|
133
|
+
args: {
|
|
134
|
+
showGrip: true,
|
|
135
|
+
productInitials: "CR",
|
|
136
|
+
title: "Chardonnay Reserve 2021",
|
|
137
|
+
subtitle: "Nordic Wines · Organic whites",
|
|
138
|
+
participants: [{ id: "nw", name: "Nordic Wines" }],
|
|
139
|
+
metaRight: "2d ago",
|
|
140
|
+
metaRightTone: "muted",
|
|
141
|
+
onClick: () => { },
|
|
142
|
+
},
|
|
143
|
+
parameters: {
|
|
144
|
+
docs: {
|
|
145
|
+
description: {
|
|
146
|
+
story: "`showGrip` overrides auto-detection. Use `true` to force the grip outside a `SortableCardShell` context, or `false` to suppress it inside one (e.g. in a drag-overlay preview).",
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
};
|
|
108
151
|
export const WithActionsSlot = {
|
|
109
152
|
args: {
|
|
110
153
|
productInitials: "CR",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journey-card.stories.js","sourceRoot":"","sources":["../../src/components/journey-card.stories.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,WAAW,EAAyB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"journey-card.stories.js","sourceRoot":"","sources":["../../src/components/journey-card.stories.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SortableCardContext — minimal leaf module.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `sortable-card-shell.tsx` so card components (e.g.
|
|
5
|
+
* `JourneyCard`) can read the context to decide whether to render a
|
|
6
|
+
* drag affordance WITHOUT transitively importing `@dnd-kit/dom` at
|
|
7
|
+
* module load. `@dnd-kit/dom` touches `ResizeObserver` when imported,
|
|
8
|
+
* which breaks jsdom-based tests that don't polyfill it.
|
|
9
|
+
*
|
|
10
|
+
* The shell itself re-exports this via `sortable-card-shell.tsx` for
|
|
11
|
+
* back-compat, so `import { SortableCardContext } from "./sortable-card-shell"`
|
|
12
|
+
* still works for existing consumers and tests.
|
|
13
|
+
*/
|
|
14
|
+
export interface SortableCardContextValue {
|
|
15
|
+
isDraggable: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare const SortableCardContext: import("react").Context<SortableCardContextValue>;
|
|
18
|
+
//# sourceMappingURL=sortable-card-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sortable-card-context.d.ts","sourceRoot":"","sources":["../../src/components/sortable-card-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,mDAE9B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SortableCardContext — minimal leaf module.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `sortable-card-shell.tsx` so card components (e.g.
|
|
5
|
+
* `JourneyCard`) can read the context to decide whether to render a
|
|
6
|
+
* drag affordance WITHOUT transitively importing `@dnd-kit/dom` at
|
|
7
|
+
* module load. `@dnd-kit/dom` touches `ResizeObserver` when imported,
|
|
8
|
+
* which breaks jsdom-based tests that don't polyfill it.
|
|
9
|
+
*
|
|
10
|
+
* The shell itself re-exports this via `sortable-card-shell.tsx` for
|
|
11
|
+
* back-compat, so `import { SortableCardContext } from "./sortable-card-shell"`
|
|
12
|
+
* still works for existing consumers and tests.
|
|
13
|
+
*/
|
|
14
|
+
import { createContext } from "react";
|
|
15
|
+
export const SortableCardContext = createContext({
|
|
16
|
+
isDraggable: false,
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=sortable-card-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sortable-card-context.js","sourceRoot":"","sources":["../../src/components/sortable-card-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAMtC,MAAM,CAAC,MAAM,mBAAmB,GAAG,aAAa,CAA2B;IACzE,WAAW,EAAE,KAAK;CACnB,CAAC,CAAC"}
|
|
@@ -1,32 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SortableCardShell —
|
|
2
|
+
* SortableCardShell — whole-card drag wrapper.
|
|
3
3
|
*
|
|
4
|
-
* Journey/kanban
|
|
5
|
-
* 1. The whole card is the drag activation surface
|
|
6
|
-
* 2.
|
|
7
|
-
*
|
|
8
|
-
* they must NOT start a drag.
|
|
9
|
-
*
|
|
10
|
-
* This shell wraps children in a div whose ref is dnd-kit's activation region.
|
|
11
|
-
* The grip icon is purely visual (`pointer-events-none` + `aria-hidden`) and
|
|
12
|
-
* is NOT used as the drag handle — it's an affordance hint only.
|
|
4
|
+
* Journey/kanban cards want two things:
|
|
5
|
+
* 1. The whole card is the drag activation surface.
|
|
6
|
+
* 2. Clicks on `<button>`/`<a>`/menus/etc. inside the card must still
|
|
7
|
+
* work — they must NOT start a drag.
|
|
13
8
|
*
|
|
14
9
|
* To keep clicks on interactive descendants from activating a drag, we
|
|
15
10
|
* configure `PointerSensor` per-draggable with a `preventActivation` hook
|
|
16
|
-
* that inspects the pointer target with `Element.closest(...)`. Any
|
|
17
|
-
* matching a known interactive selector — or carrying a
|
|
18
|
-
* attribute — cancels activation before the drag starts.
|
|
11
|
+
* that inspects the pointer target with `Element.closest(...)`. Any
|
|
12
|
+
* element matching a known interactive selector — or carrying a
|
|
13
|
+
* `data-no-drag` attribute — cancels activation before the drag starts.
|
|
14
|
+
*
|
|
15
|
+
* This shell does NOT render a grip affordance. Consumers that want one
|
|
16
|
+
* (e.g. JourneyCard) can read the exported `SortableCardContext` to
|
|
17
|
+
* detect they are inside a drag shell and render their own grip in a
|
|
18
|
+
* layout-appropriate position.
|
|
19
19
|
*
|
|
20
20
|
* Requires the optional peer dependencies `@dnd-kit/react` and `@dnd-kit/dom`.
|
|
21
21
|
* Not exported from the main barrel — import directly from
|
|
22
22
|
* `@cellarnode/ui/sortable-card-shell`.
|
|
23
23
|
*/
|
|
24
24
|
import { type ReactNode } from "react";
|
|
25
|
+
import { SortableCardContext, type SortableCardContextValue } from "./sortable-card-context";
|
|
26
|
+
export { SortableCardContext };
|
|
27
|
+
export type { SortableCardContextValue };
|
|
25
28
|
/**
|
|
26
29
|
* CSS selector for elements inside a draggable card that should NOT
|
|
27
30
|
* activate a drag when clicked. Consumers can opt any element out by
|
|
28
31
|
* adding the `data-no-drag` attribute.
|
|
29
32
|
*
|
|
33
|
+
* Notable exclusion: `[role='button']` and `[role='link']` are NOT in
|
|
34
|
+
* this list. JourneyCard (and similar card wrappers) set `role='button'`
|
|
35
|
+
* on their root div for keyboard a11y. If we matched those, `closest()`
|
|
36
|
+
* would resolve to the card wrapper itself and drag would never activate.
|
|
37
|
+
* `@dnd-kit/dom`'s own activation constraints (5px distance, 200ms delay)
|
|
38
|
+
* already prevent tap-clicks from starting accidental drags, so dropping
|
|
39
|
+
* these roles is safe.
|
|
40
|
+
*
|
|
30
41
|
* Exported so consumers can extend or reuse it in custom sensor configs.
|
|
31
42
|
*/
|
|
32
43
|
export declare const SORTABLE_CARD_NO_DRAG_SELECTOR: string;
|
|
@@ -47,14 +58,20 @@ interface SortableCardShellCommonProps {
|
|
|
47
58
|
isShaking?: boolean;
|
|
48
59
|
/** Extra classes for the wrapper element. */
|
|
49
60
|
className?: string;
|
|
50
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* @deprecated The shell no longer renders a grip. Card components
|
|
63
|
+
* render their own grip internally (see `JourneyCard`). Retained as
|
|
64
|
+
* a no-op for backwards compatibility with older consumer code.
|
|
65
|
+
*/
|
|
51
66
|
gripClassName?: string;
|
|
52
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* @deprecated The shell no longer renders a grip. Card components
|
|
69
|
+
* render their own grip internally. No-op.
|
|
70
|
+
*/
|
|
53
71
|
hideGrip?: boolean;
|
|
54
72
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* `pointer-events-none`). Defaults to "Drag to reorder".
|
|
73
|
+
* @deprecated The shell no longer renders a grip. Card components
|
|
74
|
+
* render their own grip internally. No-op.
|
|
58
75
|
*/
|
|
59
76
|
gripTitle?: string;
|
|
60
77
|
children: ReactNode;
|
|
@@ -86,13 +103,15 @@ interface SortableCardShellDraggableProps {
|
|
|
86
103
|
*/
|
|
87
104
|
export type SortableCardShellProps = SortableCardShellCommonProps & (SortableCardShellSortableProps | SortableCardShellDraggableProps);
|
|
88
105
|
/**
|
|
89
|
-
*
|
|
106
|
+
* Whole-card drag wrapper used by producer + importer journey boards.
|
|
90
107
|
*
|
|
91
|
-
* Visual states:
|
|
108
|
+
* Visual states applied to the wrapper:
|
|
92
109
|
* - `isDragSource` / `isDragging`: wrapper dims to `opacity-40`.
|
|
93
110
|
* - `isDropTarget` (sortable only): 2px primary line above the card.
|
|
94
111
|
* - `isShaking`: applies `card-shake` class (consumer-defined keyframes).
|
|
112
|
+
*
|
|
113
|
+
* The shell exposes `SortableCardContext` so children can render their
|
|
114
|
+
* own drag affordance (e.g. a grip icon in `JourneyCard`).
|
|
95
115
|
*/
|
|
96
116
|
export declare function SortableCardShell(props: SortableCardShellProps): import("react/jsx-runtime").JSX.Element;
|
|
97
|
-
export {};
|
|
98
117
|
//# sourceMappingURL=sortable-card-shell.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sortable-card-shell.d.ts","sourceRoot":"","sources":["../../src/components/sortable-card-shell.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAW,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"sortable-card-shell.d.ts","sourceRoot":"","sources":["../../src/components/sortable-card-shell.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAW,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAI1D,OAAO,EACL,mBAAmB,EACnB,KAAK,wBAAwB,EAC9B,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAC/B,YAAY,EAAE,wBAAwB,EAAE,CAAC;AAIzC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,8BAA8B,QAsB9B,CAAC;AAcd,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,WAAW,CAAC;AAE7D;;GAEG;AACH,UAAU,4BAA4B;IACpC,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IAEX;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,oFAAoF;IACpF,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;GAGG;AACH,UAAU,8BAA8B;IACtC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,UAAU,+BAA+B;IACvC,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,4BAA4B,GAC/D,CAAC,8BAA8B,GAAG,+BAA+B,CAAC,CAAC;AAIrE;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,2CAsD9D"}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
|
-
* SortableCardShell —
|
|
3
|
+
* SortableCardShell — whole-card drag wrapper.
|
|
4
4
|
*
|
|
5
|
-
* Journey/kanban
|
|
6
|
-
* 1. The whole card is the drag activation surface
|
|
7
|
-
* 2.
|
|
8
|
-
*
|
|
9
|
-
* they must NOT start a drag.
|
|
10
|
-
*
|
|
11
|
-
* This shell wraps children in a div whose ref is dnd-kit's activation region.
|
|
12
|
-
* The grip icon is purely visual (`pointer-events-none` + `aria-hidden`) and
|
|
13
|
-
* is NOT used as the drag handle — it's an affordance hint only.
|
|
5
|
+
* Journey/kanban cards want two things:
|
|
6
|
+
* 1. The whole card is the drag activation surface.
|
|
7
|
+
* 2. Clicks on `<button>`/`<a>`/menus/etc. inside the card must still
|
|
8
|
+
* work — they must NOT start a drag.
|
|
14
9
|
*
|
|
15
10
|
* To keep clicks on interactive descendants from activating a drag, we
|
|
16
11
|
* configure `PointerSensor` per-draggable with a `preventActivation` hook
|
|
17
|
-
* that inspects the pointer target with `Element.closest(...)`. Any
|
|
18
|
-
* matching a known interactive selector — or carrying a
|
|
19
|
-
* attribute — cancels activation before the drag starts.
|
|
12
|
+
* that inspects the pointer target with `Element.closest(...)`. Any
|
|
13
|
+
* element matching a known interactive selector — or carrying a
|
|
14
|
+
* `data-no-drag` attribute — cancels activation before the drag starts.
|
|
15
|
+
*
|
|
16
|
+
* This shell does NOT render a grip affordance. Consumers that want one
|
|
17
|
+
* (e.g. JourneyCard) can read the exported `SortableCardContext` to
|
|
18
|
+
* detect they are inside a drag shell and render their own grip in a
|
|
19
|
+
* layout-appropriate position.
|
|
20
20
|
*
|
|
21
21
|
* Requires the optional peer dependencies `@dnd-kit/react` and `@dnd-kit/dom`.
|
|
22
22
|
* Not exported from the main barrel — import directly from
|
|
@@ -24,15 +24,28 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
24
24
|
*/
|
|
25
25
|
import { useMemo } from "react";
|
|
26
26
|
import { PointerSensor } from "@dnd-kit/dom";
|
|
27
|
-
import { GripVertical } from "lucide-react";
|
|
28
27
|
import { cn } from "../lib/utils";
|
|
29
28
|
import { useDraggableCard, useSortableCard } from "../hooks/use-kanban-dnd";
|
|
29
|
+
import { SortableCardContext, } from "./sortable-card-context";
|
|
30
|
+
// Re-export for backwards compatibility: consumers that imported the
|
|
31
|
+
// context + type from `./sortable-card-shell` should keep working without
|
|
32
|
+
// changes. New code should import directly from `./sortable-card-context`
|
|
33
|
+
// to avoid pulling in `@dnd-kit/dom` at module load.
|
|
34
|
+
export { SortableCardContext };
|
|
30
35
|
// ─── Interactive-element guard ──────────────────────────────────────────────
|
|
31
36
|
/**
|
|
32
37
|
* CSS selector for elements inside a draggable card that should NOT
|
|
33
38
|
* activate a drag when clicked. Consumers can opt any element out by
|
|
34
39
|
* adding the `data-no-drag` attribute.
|
|
35
40
|
*
|
|
41
|
+
* Notable exclusion: `[role='button']` and `[role='link']` are NOT in
|
|
42
|
+
* this list. JourneyCard (and similar card wrappers) set `role='button'`
|
|
43
|
+
* on their root div for keyboard a11y. If we matched those, `closest()`
|
|
44
|
+
* would resolve to the card wrapper itself and drag would never activate.
|
|
45
|
+
* `@dnd-kit/dom`'s own activation constraints (5px distance, 200ms delay)
|
|
46
|
+
* already prevent tap-clicks from starting accidental drags, so dropping
|
|
47
|
+
* these roles is safe.
|
|
48
|
+
*
|
|
36
49
|
* Exported so consumers can extend or reuse it in custom sensor configs.
|
|
37
50
|
*/
|
|
38
51
|
export const SORTABLE_CARD_NO_DRAG_SELECTOR = [
|
|
@@ -44,8 +57,6 @@ export const SORTABLE_CARD_NO_DRAG_SELECTOR = [
|
|
|
44
57
|
"select",
|
|
45
58
|
"label",
|
|
46
59
|
"summary",
|
|
47
|
-
"[role='button']",
|
|
48
|
-
"[role='link']",
|
|
49
60
|
"[role='menuitem']",
|
|
50
61
|
"[role='menu']",
|
|
51
62
|
"[role='menubar']",
|
|
@@ -71,15 +82,18 @@ function shouldPreventDragActivation(event) {
|
|
|
71
82
|
}
|
|
72
83
|
// ─── Component ──────────────────────────────────────────────────────────────
|
|
73
84
|
/**
|
|
74
|
-
*
|
|
85
|
+
* Whole-card drag wrapper used by producer + importer journey boards.
|
|
75
86
|
*
|
|
76
|
-
* Visual states:
|
|
87
|
+
* Visual states applied to the wrapper:
|
|
77
88
|
* - `isDragSource` / `isDragging`: wrapper dims to `opacity-40`.
|
|
78
89
|
* - `isDropTarget` (sortable only): 2px primary line above the card.
|
|
79
90
|
* - `isShaking`: applies `card-shake` class (consumer-defined keyframes).
|
|
91
|
+
*
|
|
92
|
+
* The shell exposes `SortableCardContext` so children can render their
|
|
93
|
+
* own drag affordance (e.g. a grip icon in `JourneyCard`).
|
|
80
94
|
*/
|
|
81
95
|
export function SortableCardShell(props) {
|
|
82
|
-
const { id, data, disabled, isShaking, className,
|
|
96
|
+
const { id, data, disabled, isShaking, className, children } = props;
|
|
83
97
|
// Per-draggable PointerSensor with an interactive-element guard. Stable
|
|
84
98
|
// across renders — the sensor constructor doesn't depend on props.
|
|
85
99
|
const sensors = useMemo(() => [
|
|
@@ -87,14 +101,15 @@ export function SortableCardShell(props) {
|
|
|
87
101
|
preventActivation: (event) => shouldPreventDragActivation(event),
|
|
88
102
|
}),
|
|
89
103
|
], []);
|
|
104
|
+
const contextValue = useMemo(() => ({ isDraggable: !disabled }), [disabled]);
|
|
90
105
|
if (props.mode === "draggable") {
|
|
91
|
-
return (_jsx(DraggableShell, { id: id, data: data, disabled: disabled, isShaking: isShaking, className: className,
|
|
106
|
+
return (_jsx(SortableCardContext, { value: contextValue, children: _jsx(DraggableShell, { id: id, data: data, disabled: disabled, isShaking: isShaking, className: className, sensors: sensors, children: children }) }));
|
|
92
107
|
}
|
|
93
|
-
// Sortable mode (default). TS narrows `props` so `index` and `group`
|
|
94
|
-
// guaranteed to be `number` + `string` — no casts needed.
|
|
95
|
-
return (_jsx(SortableShell, { id: id, index: props.index, group: props.group, data: data, disabled: disabled, isShaking: isShaking, className: className,
|
|
108
|
+
// Sortable mode (default). TS narrows `props` so `index` and `group`
|
|
109
|
+
// are guaranteed to be `number` + `string` — no casts needed.
|
|
110
|
+
return (_jsx(SortableCardContext, { value: contextValue, children: _jsx(SortableShell, { id: id, index: props.index, group: props.group, data: data, disabled: disabled, isShaking: isShaking, className: className, sensors: sensors, children: children }) }));
|
|
96
111
|
}
|
|
97
|
-
function SortableShell({ id, index, group, data, disabled, isShaking, className,
|
|
112
|
+
function SortableShell({ id, index, group, data, disabled, isShaking, className, sensors, children, }) {
|
|
98
113
|
const { ref, isDragSource, isDropTarget } = useSortableCard({
|
|
99
114
|
id,
|
|
100
115
|
index,
|
|
@@ -103,32 +118,24 @@ function SortableShell({ id, index, group, data, disabled, isShaking, className,
|
|
|
103
118
|
disabled,
|
|
104
119
|
sensors,
|
|
105
120
|
});
|
|
106
|
-
return (_jsx(Wrapper, { innerRef: ref, isDragSource: isDragSource, isDropTarget: isDropTarget, showDropTargetLine: true, isShaking: isShaking, className: className,
|
|
121
|
+
return (_jsx(Wrapper, { innerRef: ref, isDragSource: isDragSource, isDropTarget: isDropTarget, showDropTargetLine: true, isShaking: isShaking, className: className, children: children }));
|
|
107
122
|
}
|
|
108
|
-
function DraggableShell({ id, data, disabled, isShaking, className,
|
|
123
|
+
function DraggableShell({ id, data, disabled, isShaking, className, sensors, children, }) {
|
|
109
124
|
const { ref, isDragging } = useDraggableCard({
|
|
110
125
|
id,
|
|
111
126
|
data,
|
|
112
127
|
disabled,
|
|
113
128
|
sensors,
|
|
114
129
|
});
|
|
115
|
-
return (_jsx(Wrapper, { innerRef: ref, isDragSource: isDragging, isDropTarget: false, showDropTargetLine: false, isShaking: isShaking, className: className,
|
|
130
|
+
return (_jsx(Wrapper, { innerRef: ref, isDragSource: isDragging, isDropTarget: false, showDropTargetLine: false, isShaking: isShaking, className: className, children: children }));
|
|
116
131
|
}
|
|
117
|
-
function Wrapper({ innerRef, isDragSource, isDropTarget, showDropTargetLine, isShaking, className,
|
|
118
|
-
return (
|
|
119
|
-
// No ARIA role — let the consumer's card content own semantics.
|
|
120
|
-
className: cn("relative group flex cursor-grab select-none items-stretch gap-1 transition-all hover:z-10 has-[[data-open]]:z-50 active:cursor-grabbing",
|
|
132
|
+
function Wrapper({ innerRef, isDragSource, isDropTarget, showDropTargetLine, isShaking, className, children, }) {
|
|
133
|
+
return (_jsx("div", { ref: innerRef, className: cn("relative cursor-grab select-none transition-all hover:z-10 has-[[data-open]]:z-50 active:cursor-grabbing",
|
|
121
134
|
// Unified drag-source dim (producer used 30, importer 50, standardizing on 40)
|
|
122
135
|
isDragSource && "opacity-40",
|
|
123
136
|
// Drop-target insertion line (sortable only)
|
|
124
137
|
showDropTargetLine &&
|
|
125
138
|
isDropTarget &&
|
|
126
|
-
"before:absolute before:-top-1 before:left-0 before:right-0 before:h-0.5 before:rounded-full before:bg-primary", isShaking && "card-shake", className), "data-drag-source": isDragSource ? "true" : undefined, "data-drop-target": isDropTarget ? "true" : undefined, children:
|
|
127
|
-
// Pointer-events off — grip is purely visual. The wrapper is the
|
|
128
|
-
// drag activation surface.
|
|
129
|
-
"pointer-events-none flex shrink-0 items-center justify-center p-1 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-60",
|
|
130
|
-
// While dragging, keep the grip visible (parent wrapper already
|
|
131
|
-
// dims to 40%, so this gives a ~40% grip which reads correctly).
|
|
132
|
-
isDragSource && "opacity-100", gripClassName), children: _jsx(GripVertical, { className: "size-3.5" }) })) : null, _jsx("div", { className: "min-w-0 flex-1", children: children })] }));
|
|
139
|
+
"before:absolute before:-top-1 before:left-0 before:right-0 before:h-0.5 before:rounded-full before:bg-primary", isShaking && "card-shake", className), "data-drag-source": isDragSource ? "true" : undefined, "data-drop-target": isDropTarget ? "true" : undefined, children: children }));
|
|
133
140
|
}
|
|
134
141
|
//# sourceMappingURL=sortable-card-shell.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sortable-card-shell.js","sourceRoot":"","sources":["../../src/components/sortable-card-shell.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,OAAO,EAA4B,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"sortable-card-shell.js","sourceRoot":"","sources":["../../src/components/sortable-card-shell.tsx"],"names":[],"mappings":"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"}
|
|
@@ -6,8 +6,8 @@ type Story = StoryObj<SortableCardShellProps>;
|
|
|
6
6
|
export declare const Default: Story;
|
|
7
7
|
export declare const Draggable: Story;
|
|
8
8
|
export declare const Shaking: Story;
|
|
9
|
-
export declare const HideGrip: Story;
|
|
10
9
|
export declare const DraggingVisual: Story;
|
|
11
10
|
export declare const DropTargetVisual: Story;
|
|
12
11
|
export declare const WithInteractiveButtons: Story;
|
|
12
|
+
export declare const WithRoleButtonWrapper: Story;
|
|
13
13
|
//# sourceMappingURL=sortable-card-shell.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sortable-card-shell.stories.d.ts","sourceRoot":"","sources":["../../src/components/sortable-card-shell.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEvF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,sBAAsB,
|
|
1
|
+
{"version":3,"file":"sortable-card-shell.stories.d.ts","sourceRoot":"","sources":["../../src/components/sortable-card-shell.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEvF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,sBAAsB,CAiCtC,CAAC;AAEF,eAAe,IAAI,CAAC;AAIpB,KAAK,KAAK,GAAG,QAAQ,CAAC,sBAAsB,CAAC,CAAC;AAe9C,eAAO,MAAM,OAAO,EAAE,KASrB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAOvB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAUrB,CAAC;AAOF,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,KAqDpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,KAkCnC,CAAC"}
|
|
@@ -5,7 +5,14 @@ const meta = {
|
|
|
5
5
|
title: "Components/SortableCardShell",
|
|
6
6
|
component: SortableCardShell,
|
|
7
7
|
tags: ["autodocs"],
|
|
8
|
-
parameters: {
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: "centered",
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component: "Whole-card drag wrapper. The shell no longer renders a grip affordance — cards (e.g. `JourneyCard`) render their own grip internally via the exported `SortableCardContext`. The shell is responsible for drag sensor wiring, the interactive-element guard (click-through), and drag-source / drop-target visual states.",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
9
16
|
argTypes: {
|
|
10
17
|
mode: {
|
|
11
18
|
control: { type: "inline-radio" },
|
|
@@ -16,7 +23,6 @@ const meta = {
|
|
|
16
23
|
group: { control: { type: "text" } },
|
|
17
24
|
disabled: { control: { type: "boolean" } },
|
|
18
25
|
isShaking: { control: { type: "boolean" } },
|
|
19
|
-
hideGrip: { control: { type: "boolean" } },
|
|
20
26
|
},
|
|
21
27
|
decorators: [
|
|
22
28
|
(Story) => (_jsx(DragDropProvider, { children: _jsx("div", { style: { width: 320 }, children: _jsx(Story, {}) }) })),
|
|
@@ -55,28 +61,17 @@ export const Shaking = {
|
|
|
55
61
|
children: _jsx(SampleCardBody, {}),
|
|
56
62
|
},
|
|
57
63
|
};
|
|
58
|
-
export const HideGrip = {
|
|
59
|
-
args: {
|
|
60
|
-
id: "card-4",
|
|
61
|
-
index: 0,
|
|
62
|
-
group: "drafting",
|
|
63
|
-
data: { itemId: "card-4", columnId: "drafting" },
|
|
64
|
-
mode: "sortable",
|
|
65
|
-
hideGrip: true,
|
|
66
|
-
children: _jsx(SampleCardBody, {}),
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
64
|
// Visual mock — these states are normally driven by live drag events, so
|
|
70
65
|
// for Storybook we demo them via the inline layout classes directly on a
|
|
71
66
|
// static wrapper. They match what `SortableCardShell` renders under
|
|
72
67
|
// `isDragSource` and `isDropTarget`.
|
|
73
68
|
export const DraggingVisual = {
|
|
74
69
|
name: "Visual: Dragging source",
|
|
75
|
-
render: () => (
|
|
70
|
+
render: () => (_jsx("div", { className: "relative cursor-grab opacity-40", children: _jsx(SampleCardBody, {}) })),
|
|
76
71
|
};
|
|
77
72
|
export const DropTargetVisual = {
|
|
78
73
|
name: "Visual: Drop target insertion line",
|
|
79
|
-
render: () => (
|
|
74
|
+
render: () => (_jsx("div", { className: "relative cursor-grab before:absolute before:-top-1 before:left-0 before:right-0 before:h-0.5 before:rounded-full before:bg-primary", children: _jsx(SampleCardBody, {}) })),
|
|
80
75
|
};
|
|
81
76
|
export const WithInteractiveButtons = {
|
|
82
77
|
args: {
|
|
@@ -91,4 +86,22 @@ export const WithInteractiveButtons = {
|
|
|
91
86
|
}, className: "rounded border border-border px-2 py-1 text-xs", children: "View" }), _jsx("span", { "data-no-drag": true, onClick: () => alert("data-no-drag element clicked"), className: "cursor-default rounded border border-dashed border-border px-2 py-1 text-xs", children: "data-no-drag" })] })] })),
|
|
92
87
|
},
|
|
93
88
|
};
|
|
89
|
+
export const WithRoleButtonWrapper = {
|
|
90
|
+
name: "Regression: role='button' wrapper must drag",
|
|
91
|
+
args: {
|
|
92
|
+
id: "card-role-btn",
|
|
93
|
+
index: 0,
|
|
94
|
+
group: "drafting",
|
|
95
|
+
data: { itemId: "card-role-btn", columnId: "drafting" },
|
|
96
|
+
mode: "sortable",
|
|
97
|
+
children: (_jsxs("div", { role: "button", tabIndex: 0, onClick: () => alert("card clicked"), className: "rounded-lg border border-border bg-background p-3 shadow-xs", children: [_jsx("p", { className: "text-sm/5 font-medium text-foreground", children: "Clickable card (role=button)" }), _jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: ["This card's root div has role=\"button\". The whole card should still be draggable \u2014 if it isn't, the no-drag selector regressed by reintroducing ", _jsx("code", { children: "[role='button']" }), "."] })] })),
|
|
98
|
+
},
|
|
99
|
+
parameters: {
|
|
100
|
+
docs: {
|
|
101
|
+
description: {
|
|
102
|
+
story: "JourneyCard sets `role='button'` on its root when `onClick` is provided. The interactive-element guard MUST exclude `[role='button']` (and `[role='link']`) or drag activation is blocked by the card wrapper itself.",
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
94
107
|
//# sourceMappingURL=sortable-card-shell.stories.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sortable-card-shell.stories.js","sourceRoot":"","sources":["../../src/components/sortable-card-shell.stories.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAA+B,MAAM,uBAAuB,CAAC;AAEvF,MAAM,IAAI,GAAiC;IACzC,KAAK,EAAE,8BAA8B;IACrC,SAAS,EAAE,iBAAiB;IAC5B,IAAI,EAAE,CAAC,UAAU,CAAC;IAClB,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"sortable-card-shell.stories.js","sourceRoot":"","sources":["../../src/components/sortable-card-shell.stories.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { describe, it, expect, beforeAll } from "vitest";
|
|
3
3
|
import { render, screen } from "@testing-library/react";
|
|
4
|
+
import * as React from "react";
|
|
4
5
|
// @dnd-kit/dom touches `ResizeObserver` at module load time; jsdom does not
|
|
5
6
|
// provide one. Install a no-op polyfill BEFORE importing @dnd-kit/react or
|
|
6
7
|
// the shell (which transitively imports @dnd-kit/dom).
|
|
@@ -15,7 +16,7 @@ if (typeof globalThis.ResizeObserver === "undefined") {
|
|
|
15
16
|
}
|
|
16
17
|
// Imports deferred to after the polyfill so module-level access succeeds.
|
|
17
18
|
const { DragDropProvider } = await import("@dnd-kit/react");
|
|
18
|
-
const { SortableCardShell, SORTABLE_CARD_NO_DRAG_SELECTOR } = await import("./sortable-card-shell");
|
|
19
|
+
const { SortableCardShell, SortableCardContext, SORTABLE_CARD_NO_DRAG_SELECTOR } = await import("./sortable-card-shell");
|
|
19
20
|
beforeAll(() => {
|
|
20
21
|
// Sanity check — confirm the polyfill stuck.
|
|
21
22
|
expect(typeof globalThis.ResizeObserver).toBe("function");
|
|
@@ -39,6 +40,16 @@ beforeAll(() => {
|
|
|
39
40
|
function renderWithProvider(ui) {
|
|
40
41
|
return render(_jsx(DragDropProvider, { children: ui }));
|
|
41
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Test helper: reads `SortableCardContext` and renders "yes"/"no" based on
|
|
45
|
+
* `isDraggable`. Kept at module level so eslint's
|
|
46
|
+
* `@eslint-react/component-hook-factories` stays happy (components must not
|
|
47
|
+
* be defined inside other functions).
|
|
48
|
+
*/
|
|
49
|
+
function ContextProbe() {
|
|
50
|
+
const ctx = React.use(SortableCardContext);
|
|
51
|
+
return _jsx("span", { "data-testid": "probe", children: ctx.isDraggable ? "yes" : "no" });
|
|
52
|
+
}
|
|
42
53
|
describe("SortableCardShell", () => {
|
|
43
54
|
it("renders children (smoke test, sortable mode)", () => {
|
|
44
55
|
renderWithProvider(_jsx(SortableCardShell, { id: "card-1", index: 0, group: "col-a", children: _jsx("div", { "data-testid": "card-body", children: "Ch\u00E2teau Margaux" }) }));
|
|
@@ -49,21 +60,24 @@ describe("SortableCardShell", () => {
|
|
|
49
60
|
renderWithProvider(_jsx(SortableCardShell, { id: "card-2", mode: "draggable", children: _jsx("div", { "data-testid": "card-body", children: "P\u00E9trus 2015" }) }));
|
|
50
61
|
expect(screen.getByTestId("card-body")).toBeInTheDocument();
|
|
51
62
|
});
|
|
52
|
-
it("
|
|
53
|
-
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
expect(grip?.className).toContain("pointer-events-none");
|
|
62
|
-
// lucide-react renders an inline SVG inside the grip.
|
|
63
|
-
expect(grip?.querySelector("svg")).not.toBeNull();
|
|
63
|
+
it("provides SortableCardContext with isDraggable=true to children", () => {
|
|
64
|
+
// Children read this context to decide whether to render their own grip
|
|
65
|
+
// affordance (e.g. JourneyCard's top-left corner dot-grid).
|
|
66
|
+
renderWithProvider(_jsx(SortableCardShell, { id: "card-ctx", index: 0, group: "col-a", children: _jsx(ContextProbe, {}) }));
|
|
67
|
+
expect(screen.getByTestId("probe").textContent).toBe("yes");
|
|
68
|
+
});
|
|
69
|
+
it("provides isDraggable=false when disabled", () => {
|
|
70
|
+
renderWithProvider(_jsx(SortableCardShell, { id: "card-disabled", index: 0, group: "col-a", disabled: true, children: _jsx(ContextProbe, {}) }));
|
|
71
|
+
expect(screen.getByTestId("probe").textContent).toBe("no");
|
|
64
72
|
});
|
|
65
|
-
it("
|
|
66
|
-
|
|
73
|
+
it("does not render a grip inside the shell itself", () => {
|
|
74
|
+
// The shell used to render an outer grip <span>. It no longer does —
|
|
75
|
+
// cards (e.g. JourneyCard) render their own grip internally. This test
|
|
76
|
+
// locks that contract so a future regression that reintroduces an outer
|
|
77
|
+
// grip (and the horizontal-space waste that came with it) is flagged.
|
|
78
|
+
const { container } = renderWithProvider(_jsx(SortableCardShell, { id: "card-no-outer-grip", index: 0, group: "col-a", children: _jsx("div", { "data-testid": "body", children: "body" }) }));
|
|
79
|
+
// The only aria-hidden element should be absent — the shell doesn't own
|
|
80
|
+
// any purely-visual affordance now.
|
|
67
81
|
expect(container.querySelector('[aria-hidden="true"]')).toBeNull();
|
|
68
82
|
});
|
|
69
83
|
// ─── Interactive-element guard ────────────────────────────────────────────
|
|
@@ -111,5 +125,32 @@ describe("SortableCardShell", () => {
|
|
|
111
125
|
expect(SORTABLE_CARD_NO_DRAG_SELECTOR).toContain("input");
|
|
112
126
|
expect(SORTABLE_CARD_NO_DRAG_SELECTOR).toContain("[role='menuitem']");
|
|
113
127
|
});
|
|
128
|
+
it("interactive guard: a role='button' wrapper does NOT block drag activation (regression)", () => {
|
|
129
|
+
// Critical regression: JourneyCard sets role='button' on its root div
|
|
130
|
+
// whenever onClick is provided (for keyboard a11y). If the no-drag
|
|
131
|
+
// selector matched [role='button'], closest() would walk up and match
|
|
132
|
+
// the card wrapper itself — so every pointerdown on a card would
|
|
133
|
+
// cancel drag activation and drag would be silently broken.
|
|
134
|
+
//
|
|
135
|
+
// The selector MUST NOT include [role='button'] (or [role='link']).
|
|
136
|
+
// dnd-kit's activation constraints (5px distance, 200ms delay) already
|
|
137
|
+
// prevent tap-clicks from starting an accidental drag, so dropping
|
|
138
|
+
// these roles from the no-drag list is safe.
|
|
139
|
+
renderWithProvider(_jsx(SortableCardShell, { id: "card-role-btn", index: 0, group: "col-a", children: _jsxs("div", { role: "button", tabIndex: 0, "data-testid": "card-root", onClick: () => { }, children: [_jsx("span", { "data-testid": "title", children: "Product name" }), _jsx("button", { type: "button", "data-testid": "inner-btn", children: "Kebab" })] }) }));
|
|
140
|
+
const title = screen.getByTestId("title");
|
|
141
|
+
const cardRoot = screen.getByTestId("card-root");
|
|
142
|
+
const innerBtn = screen.getByTestId("inner-btn");
|
|
143
|
+
// A click on the title (non-interactive area) should NOT match — drag
|
|
144
|
+
// proceeds as expected. This is the primary regression check.
|
|
145
|
+
expect(title.closest(SORTABLE_CARD_NO_DRAG_SELECTOR)).toBeNull();
|
|
146
|
+
// The card root itself carries role='button' but must ALSO not match.
|
|
147
|
+
expect(cardRoot.closest(SORTABLE_CARD_NO_DRAG_SELECTOR)).toBeNull();
|
|
148
|
+
// Real <button> descendants are still protected by the plain `button`
|
|
149
|
+
// selector — click-through works for kebab menus.
|
|
150
|
+
expect(innerBtn.closest(SORTABLE_CARD_NO_DRAG_SELECTOR)).toBe(innerBtn);
|
|
151
|
+
// Sanity: the selector does NOT contain role='button'/'link'.
|
|
152
|
+
expect(SORTABLE_CARD_NO_DRAG_SELECTOR).not.toContain("[role='button']");
|
|
153
|
+
expect(SORTABLE_CARD_NO_DRAG_SELECTOR).not.toContain("[role='link']");
|
|
154
|
+
});
|
|
114
155
|
});
|
|
115
156
|
//# sourceMappingURL=sortable-card-shell.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sortable-card-shell.test.js","sourceRoot":"","sources":["../../src/components/sortable-card-shell.test.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"sortable-card-shell.test.js","sourceRoot":"","sources":["../../src/components/sortable-card-shell.test.tsx"],"names":[],"mappings":"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"}
|