@mbao01/common 0.0.45 → 0.0.47
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/types/components/Chart/helpers.d.ts +3 -1
- package/dist/types/components/Chart/stories/args/index.d.ts +63 -0
- package/dist/types/components/DragAndDrop/Draggable/Draggable.d.ts +29 -0
- package/dist/types/components/DragAndDrop/Draggable/Draggable.example.d.ts +24 -0
- package/dist/types/components/DragAndDrop/Draggable/constants.d.ts +9 -0
- package/dist/types/components/DragAndDrop/Draggable/index.d.ts +1 -0
- package/dist/types/components/DragAndDrop/Draggable/types.d.ts +41 -0
- package/dist/types/components/DragAndDrop/Droppable/Droppable.d.ts +2 -0
- package/dist/types/components/DragAndDrop/Droppable/Droppable.example.d.ts +10 -0
- package/dist/types/components/DragAndDrop/Droppable/constants.d.ts +5 -0
- package/dist/types/components/DragAndDrop/Droppable/index.d.ts +1 -0
- package/dist/types/components/DragAndDrop/Droppable/types.d.ts +4 -0
- package/dist/types/components/DragAndDrop/Sortable/Sortable.d.ts +2 -0
- package/dist/types/components/DragAndDrop/Sortable/Sortable.example.d.ts +6 -0
- package/dist/types/components/DragAndDrop/Sortable/constants.d.ts +4 -0
- package/dist/types/components/DragAndDrop/Sortable/index.d.ts +1 -0
- package/dist/types/components/DragAndDrop/Sortable/types.d.ts +7 -0
- package/dist/types/components/DragAndDrop/index.d.ts +3 -0
- package/dist/types/components/Form/DatetimeInput/DatetimeInput.d.ts +1 -1
- package/dist/types/components/Menu/Menubar/Menubar.d.ts +42 -0
- package/dist/types/components/Menu/Menubar/types.d.ts +1 -0
- package/dist/types/components/Widget/InternalWidgetsContext.d.ts +2 -0
- package/dist/types/components/Widget/Widget.d.ts +2 -0
- package/dist/types/components/Widget/Widgets.example.d.ts +1 -0
- package/dist/types/components/Widget/WidgetsContext.d.ts +2 -0
- package/dist/types/components/Widget/hooks/index.d.ts +2 -0
- package/dist/types/components/Widget/hooks/useWidget/index.d.ts +1 -0
- package/dist/types/components/Widget/hooks/useWidget/useWidget.d.ts +7 -0
- package/dist/types/components/Widget/hooks/useWidgets/index.d.ts +1 -0
- package/dist/types/components/Widget/hooks/useWidgets/useWidgets.d.ts +1 -0
- package/dist/types/components/Widget/index.d.ts +3 -0
- package/dist/types/components/Widget/modifiers/index.d.ts +1 -0
- package/dist/types/components/Widget/modifiers/restrictToElement.d.ts +2 -0
- package/dist/types/components/Widget/types.d.ts +28 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +63 -59
- package/src/components/Chart/helpers.ts +14 -8
- package/src/components/Chart/stories/args/index.ts +12 -12
- package/src/components/DragAndDrop/Draggable/Draggable.example.tsx +147 -0
- package/src/components/DragAndDrop/Draggable/Draggable.tsx +161 -0
- package/src/components/DragAndDrop/Draggable/constants.ts +47 -0
- package/src/components/DragAndDrop/Draggable/index.ts +1 -0
- package/src/components/DragAndDrop/Draggable/types.ts +56 -0
- package/src/components/DragAndDrop/Droppable/Droppable.example.tsx +86 -0
- package/src/components/DragAndDrop/Droppable/Droppable.tsx +38 -0
- package/src/components/DragAndDrop/Droppable/constants.ts +15 -0
- package/src/components/DragAndDrop/Droppable/index.ts +1 -0
- package/src/components/DragAndDrop/Droppable/types.ts +7 -0
- package/src/components/DragAndDrop/Sortable/Sortable.example.tsx +61 -0
- package/src/components/DragAndDrop/Sortable/Sortable.tsx +65 -0
- package/src/components/DragAndDrop/Sortable/constants.ts +12 -0
- package/src/components/DragAndDrop/Sortable/index.ts +1 -0
- package/src/components/DragAndDrop/Sortable/types.ts +11 -0
- package/src/components/DragAndDrop/index.ts +3 -0
- package/src/components/Menu/Menubar/Menubar.tsx +5 -1
- package/src/components/Menu/Menubar/types.ts +2 -0
- package/src/components/Widget/InternalWidgetsContext.tsx +4 -0
- package/src/components/Widget/Widget.tsx +17 -0
- package/src/components/Widget/Widgets.example.tsx +118 -0
- package/src/components/Widget/WidgetsContext.tsx +97 -0
- package/src/components/Widget/hooks/index.ts +2 -0
- package/src/components/Widget/hooks/useWidget/index.ts +1 -0
- package/src/components/Widget/hooks/useWidget/useWidget.ts +21 -0
- package/src/components/Widget/hooks/useWidgets/index.ts +1 -0
- package/src/components/Widget/hooks/useWidgets/useWidgets.ts +12 -0
- package/src/components/Widget/index.ts +3 -0
- package/src/components/Widget/modifiers/index.ts +1 -0
- package/src/components/Widget/modifiers/restrictToElement.ts +8 -0
- package/src/components/Widget/types.ts +30 -0
- package/src/index.ts +2 -0
|
@@ -1,26 +1,32 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NameType,
|
|
3
|
+
Payload as TooltipPayload,
|
|
4
|
+
ValueType,
|
|
5
|
+
} from "recharts/types/component/DefaultTooltipContent";
|
|
6
|
+
import { type Payload as LegendPayload } from "recharts/types/component/DefaultLegendContent";
|
|
1
7
|
import { type ChartConfig } from "./types";
|
|
2
8
|
|
|
3
9
|
// Helper to extract item config from a payload.
|
|
4
|
-
export const getPayloadConfigFromPayload = (
|
|
10
|
+
export const getPayloadConfigFromPayload = (
|
|
11
|
+
config: ChartConfig,
|
|
12
|
+
payload: LegendPayload | TooltipPayload<ValueType, NameType>,
|
|
13
|
+
key: string
|
|
14
|
+
) => {
|
|
5
15
|
if (typeof payload !== "object" || payload === null) {
|
|
6
16
|
return undefined;
|
|
7
17
|
}
|
|
8
18
|
|
|
9
19
|
const payloadPayload =
|
|
10
20
|
"payload" in payload && typeof payload.payload === "object" && payload.payload !== null
|
|
11
|
-
? payload.payload
|
|
21
|
+
? (payload.payload as Record<string, unknown>)
|
|
12
22
|
: undefined;
|
|
13
23
|
|
|
14
24
|
let configLabelKey: string = key;
|
|
15
25
|
|
|
16
26
|
if (key in payload && typeof payload[key as keyof typeof payload] === "string") {
|
|
17
27
|
configLabelKey = payload[key as keyof typeof payload] as string;
|
|
18
|
-
} else if (
|
|
19
|
-
payloadPayload
|
|
20
|
-
key in payloadPayload &&
|
|
21
|
-
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
|
|
22
|
-
) {
|
|
23
|
-
configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string;
|
|
28
|
+
} else if (payloadPayload && key in payloadPayload && typeof payloadPayload[key] === "string") {
|
|
29
|
+
configLabelKey = payloadPayload[key];
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
return configLabelKey in config ? config[configLabelKey] : config[key];
|
|
@@ -52,12 +52,12 @@ const barArgKey = {
|
|
|
52
52
|
yAxis: "yAxis",
|
|
53
53
|
} satisfies Record<string, BarArgKey>;
|
|
54
54
|
|
|
55
|
-
export const barChartArgs = {
|
|
55
|
+
export const barChartArgs: ArgTypes = {
|
|
56
56
|
...categorizeArgs(barChartComponentArgs, barArgKey.barChart),
|
|
57
57
|
...categorizeArgs(xAxisArgs, barArgKey.xAxis),
|
|
58
58
|
...categorizeArgs(yAxisArgs, barArgKey.yAxis),
|
|
59
59
|
...categorizeArgs(barArgs, barArgKey.bar),
|
|
60
|
-
}
|
|
60
|
+
};
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Line chart
|
|
@@ -78,12 +78,12 @@ const lineArgKey = {
|
|
|
78
78
|
yAxis: "yAxis",
|
|
79
79
|
} satisfies Record<string, LineArgKey>;
|
|
80
80
|
|
|
81
|
-
export const lineChartArgs = {
|
|
81
|
+
export const lineChartArgs: ArgTypes = {
|
|
82
82
|
...categorizeArgs(lineChartComponentArgs, lineArgKey.lineChart),
|
|
83
83
|
...categorizeArgs(xAxisArgs, lineArgKey.xAxis),
|
|
84
84
|
...categorizeArgs(yAxisArgs, lineArgKey.yAxis),
|
|
85
85
|
...categorizeArgs(lineArgs, lineArgKey.line),
|
|
86
|
-
}
|
|
86
|
+
};
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
89
|
* Area chart
|
|
@@ -104,12 +104,12 @@ export const areaArgKey = {
|
|
|
104
104
|
yAxis: "yAxis",
|
|
105
105
|
} satisfies Record<string, AreaArgKey>;
|
|
106
106
|
|
|
107
|
-
export const areaChartArgs = {
|
|
107
|
+
export const areaChartArgs: ArgTypes = {
|
|
108
108
|
...categorizeArgs(areaChartComponentArgs, areaArgKey.areaChart),
|
|
109
109
|
...categorizeArgs(xAxisArgs, areaArgKey.xAxis),
|
|
110
110
|
...categorizeArgs(yAxisArgs, areaArgKey.yAxis),
|
|
111
111
|
...categorizeArgs(areaArgs, areaArgKey.area),
|
|
112
|
-
}
|
|
112
|
+
};
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* Pie chart
|
|
@@ -128,10 +128,10 @@ export const pieArgKey = {
|
|
|
128
128
|
pieChart: "pieChart",
|
|
129
129
|
} satisfies Record<string, PieArgKey>;
|
|
130
130
|
|
|
131
|
-
export const pieChartArgs = {
|
|
131
|
+
export const pieChartArgs: ArgTypes = {
|
|
132
132
|
...categorizeArgs(pieChartComponentArgs, pieArgKey.pieChart),
|
|
133
133
|
...categorizeArgs(pieArgs, pieArgKey.pie),
|
|
134
|
-
}
|
|
134
|
+
};
|
|
135
135
|
|
|
136
136
|
/**
|
|
137
137
|
* RadialBar chart
|
|
@@ -150,10 +150,10 @@ export const radialBarArgKey = {
|
|
|
150
150
|
radialBarChart: "radialBarChart",
|
|
151
151
|
} satisfies Record<string, RadialBarArgKey>;
|
|
152
152
|
|
|
153
|
-
export const radialBarChartArgs = {
|
|
153
|
+
export const radialBarChartArgs: ArgTypes = {
|
|
154
154
|
...categorizeArgs(radialBarChartComponentArgs, radialBarArgKey.radialBarChart),
|
|
155
155
|
...categorizeArgs(radialBarArgs, radialBarArgKey.radialBar),
|
|
156
|
-
}
|
|
156
|
+
};
|
|
157
157
|
|
|
158
158
|
/**
|
|
159
159
|
* Radar chart
|
|
@@ -172,7 +172,7 @@ export const radarArgKey = {
|
|
|
172
172
|
radarChart: "radarChart",
|
|
173
173
|
} satisfies Record<string, RadarArgKey>;
|
|
174
174
|
|
|
175
|
-
export const radarChartArgs = {
|
|
175
|
+
export const radarChartArgs: ArgTypes = {
|
|
176
176
|
...categorizeArgs(radarChartComponentArgs, radarArgKey.radarChart),
|
|
177
177
|
...categorizeArgs(radarArgs, radarArgKey.radar),
|
|
178
|
-
}
|
|
178
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { DropAnimation, Modifiers, PointerActivationConstraint } from "@dnd-kit/core";
|
|
2
|
+
import type { Coordinates } from "@dnd-kit/utilities";
|
|
3
|
+
import type { CSSProperties } from "react";
|
|
4
|
+
import { useMemo, useState } from "react";
|
|
5
|
+
import {
|
|
6
|
+
DndContext,
|
|
7
|
+
KeyboardSensor,
|
|
8
|
+
MouseSensor,
|
|
9
|
+
TouchSensor,
|
|
10
|
+
useSensor,
|
|
11
|
+
useSensors,
|
|
12
|
+
} from "@dnd-kit/core";
|
|
13
|
+
import { createSnapModifier } from "@dnd-kit/modifiers";
|
|
14
|
+
import type { DraggableAxis } from "./types";
|
|
15
|
+
import { Draggable } from "./Draggable";
|
|
16
|
+
import { type DraggableHandleElement } from "./types";
|
|
17
|
+
|
|
18
|
+
type DraggableExampleProps = Partial<{
|
|
19
|
+
activationConstraint: PointerActivationConstraint;
|
|
20
|
+
axis: DraggableAxis;
|
|
21
|
+
handle: DraggableHandleElement;
|
|
22
|
+
modifiers: Modifiers;
|
|
23
|
+
buttonStyle: CSSProperties;
|
|
24
|
+
label: string;
|
|
25
|
+
}>;
|
|
26
|
+
|
|
27
|
+
export const DraggableExample = ({
|
|
28
|
+
activationConstraint,
|
|
29
|
+
axis,
|
|
30
|
+
handle,
|
|
31
|
+
modifiers,
|
|
32
|
+
label = "Go ahead, drag me.",
|
|
33
|
+
}: DraggableExampleProps) => {
|
|
34
|
+
const [{ x, y }, setCoordinates] = useState<Coordinates>({ x: 0, y: 0 });
|
|
35
|
+
const mouseSensor = useSensor(MouseSensor, {
|
|
36
|
+
activationConstraint,
|
|
37
|
+
});
|
|
38
|
+
const touchSensor = useSensor(TouchSensor, {
|
|
39
|
+
activationConstraint,
|
|
40
|
+
});
|
|
41
|
+
const keyboardSensor = useSensor(KeyboardSensor, {});
|
|
42
|
+
const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<DndContext
|
|
46
|
+
sensors={sensors}
|
|
47
|
+
onDragEnd={({ delta }) => {
|
|
48
|
+
setCoordinates(({ x, y }) => {
|
|
49
|
+
return {
|
|
50
|
+
x: x + delta.x,
|
|
51
|
+
y: y + delta.y,
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
}}
|
|
55
|
+
modifiers={modifiers}
|
|
56
|
+
>
|
|
57
|
+
<Draggable
|
|
58
|
+
id="my-draggable"
|
|
59
|
+
axis={axis}
|
|
60
|
+
handle={handle}
|
|
61
|
+
style={{ top: y, left: x }}
|
|
62
|
+
className="w-fit border border-base-content rounded-md p-2 flex items-center gap-2"
|
|
63
|
+
>
|
|
64
|
+
{label}
|
|
65
|
+
</Draggable>
|
|
66
|
+
</DndContext>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const DraggableSnapToGridExample = () => {
|
|
71
|
+
const [gridSize] = useState(30);
|
|
72
|
+
const buttonStyle = {
|
|
73
|
+
marginLeft: gridSize - 20 + 1,
|
|
74
|
+
marginTop: gridSize - 20 + 1,
|
|
75
|
+
width: gridSize * 8 - 1,
|
|
76
|
+
height: gridSize * 2 - 1,
|
|
77
|
+
};
|
|
78
|
+
const snapToGrid = useMemo(() => createSnapModifier(gridSize), [gridSize]);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<>
|
|
82
|
+
<DraggableExample
|
|
83
|
+
label={`Snapping to ${gridSize}px increments`}
|
|
84
|
+
modifiers={[snapToGrid]}
|
|
85
|
+
buttonStyle={buttonStyle}
|
|
86
|
+
key={gridSize}
|
|
87
|
+
/>
|
|
88
|
+
<div
|
|
89
|
+
className="fixed top-0 left-0 w-full h-full -z-10 pointer-events-none"
|
|
90
|
+
style={
|
|
91
|
+
{
|
|
92
|
+
"--grid-size": `${gridSize}px`,
|
|
93
|
+
backgroundSize: "var(--grid-size) var(--grid-size)",
|
|
94
|
+
backgroundImage: `repeating-linear-gradient(
|
|
95
|
+
0deg,
|
|
96
|
+
transparent,
|
|
97
|
+
transparent calc(var(--grid-size) - 1px),
|
|
98
|
+
#9999991a calc(var(--grid-size) - 1px),
|
|
99
|
+
#9999991a var(--grid-size)
|
|
100
|
+
),
|
|
101
|
+
repeating-linear-gradient(
|
|
102
|
+
-90deg,
|
|
103
|
+
transparent,
|
|
104
|
+
transparent calc(var(--grid-size) - 1px),
|
|
105
|
+
#9999991a calc(var(--grid-size) - 1px),
|
|
106
|
+
#9999991a var(--grid-size)
|
|
107
|
+
)`,
|
|
108
|
+
} as React.CSSProperties
|
|
109
|
+
}
|
|
110
|
+
/>
|
|
111
|
+
</>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
type DraggableOverlayExampleProps = Partial<{
|
|
116
|
+
activationConstraint: PointerActivationConstraint;
|
|
117
|
+
axis: DraggableAxis;
|
|
118
|
+
handle: DraggableHandleElement;
|
|
119
|
+
modifiers: Modifiers;
|
|
120
|
+
label: string;
|
|
121
|
+
dragOverlayModifiers: Modifiers;
|
|
122
|
+
dropAnimation: DropAnimation | null;
|
|
123
|
+
}>;
|
|
124
|
+
|
|
125
|
+
export const DraggableOverlayExample = ({
|
|
126
|
+
axis,
|
|
127
|
+
dropAnimation,
|
|
128
|
+
handle,
|
|
129
|
+
label = "Drag me to see the <Draggable.Overlay>",
|
|
130
|
+
modifiers,
|
|
131
|
+
}: DraggableOverlayExampleProps) => {
|
|
132
|
+
return (
|
|
133
|
+
<DndContext modifiers={modifiers}>
|
|
134
|
+
<div>
|
|
135
|
+
<Draggable
|
|
136
|
+
id="my-draggable"
|
|
137
|
+
axis={axis}
|
|
138
|
+
handle={handle}
|
|
139
|
+
className="w-fit border border-base-content rounded-md p-2 flex items-center gap-2 data-[draggable-active]:opacity-0"
|
|
140
|
+
>
|
|
141
|
+
{label}
|
|
142
|
+
</Draggable>
|
|
143
|
+
</div>
|
|
144
|
+
<Draggable.Overlay axis={axis} dropAnimation={dropAnimation} />
|
|
145
|
+
</DndContext>
|
|
146
|
+
);
|
|
147
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { CSSProperties, Ref } from "react";
|
|
4
|
+
import { forwardRef } from "react";
|
|
5
|
+
import { createPortal } from "react-dom";
|
|
6
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
7
|
+
import { DragOverlay, useDndContext, useDraggable } from "@dnd-kit/core";
|
|
8
|
+
import type {
|
|
9
|
+
DraggableActionProps,
|
|
10
|
+
DraggableOverlayProps,
|
|
11
|
+
DraggableProps,
|
|
12
|
+
DraggableRootProps,
|
|
13
|
+
} from "./types";
|
|
14
|
+
import { cn } from "../../../utilities";
|
|
15
|
+
import { DROP_ANIMATION_CONFIG, getDraggableClasses, getDraggableRootClasses } from "./constants";
|
|
16
|
+
|
|
17
|
+
const Draggable = ({
|
|
18
|
+
id,
|
|
19
|
+
axis,
|
|
20
|
+
data,
|
|
21
|
+
disabled,
|
|
22
|
+
attributes,
|
|
23
|
+
style,
|
|
24
|
+
handle,
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
}: DraggableProps) => {
|
|
28
|
+
const {
|
|
29
|
+
attributes: draggableAttributes,
|
|
30
|
+
isDragging,
|
|
31
|
+
listeners,
|
|
32
|
+
transform,
|
|
33
|
+
setNodeRef,
|
|
34
|
+
setActivatorNodeRef,
|
|
35
|
+
} = useDraggable({
|
|
36
|
+
id,
|
|
37
|
+
data,
|
|
38
|
+
disabled,
|
|
39
|
+
attributes,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<DraggableRoot
|
|
44
|
+
{...props}
|
|
45
|
+
{...draggableAttributes}
|
|
46
|
+
ref={setNodeRef}
|
|
47
|
+
activatorNodeRef={setActivatorNodeRef}
|
|
48
|
+
axis={axis}
|
|
49
|
+
handle={handle}
|
|
50
|
+
isDragging={isDragging}
|
|
51
|
+
listeners={listeners}
|
|
52
|
+
transform={transform}
|
|
53
|
+
style={style}
|
|
54
|
+
className={cn(className, getDraggableClasses({ isDragging }))}
|
|
55
|
+
data-draggable={true}
|
|
56
|
+
data-draggable-active={isDragging || undefined}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const DraggableRoot = forwardRef<HTMLDivElement, DraggableRootProps>(
|
|
62
|
+
(
|
|
63
|
+
{
|
|
64
|
+
handle,
|
|
65
|
+
actions,
|
|
66
|
+
activatorNodeRef,
|
|
67
|
+
className,
|
|
68
|
+
isDragging,
|
|
69
|
+
isDragOverlay,
|
|
70
|
+
listeners,
|
|
71
|
+
transform,
|
|
72
|
+
style,
|
|
73
|
+
children,
|
|
74
|
+
...props
|
|
75
|
+
},
|
|
76
|
+
ref
|
|
77
|
+
) => {
|
|
78
|
+
const draggable = { listeners, ref: activatorNodeRef };
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div
|
|
82
|
+
{...props}
|
|
83
|
+
{...(actions || handle ? {} : listeners)}
|
|
84
|
+
ref={ref}
|
|
85
|
+
style={
|
|
86
|
+
{
|
|
87
|
+
...style,
|
|
88
|
+
"--translate-x": `${transform?.x ?? 0}px`,
|
|
89
|
+
"--translate-y": `${transform?.y ?? 0}px`,
|
|
90
|
+
} as CSSProperties
|
|
91
|
+
}
|
|
92
|
+
className={cn(className, getDraggableRootClasses({ isDragging, isDragOverlay }))}
|
|
93
|
+
>
|
|
94
|
+
{actions?.({ draggable })}
|
|
95
|
+
{handle ? (
|
|
96
|
+
<Slot {...draggable.listeners} ref={draggable.ref}>
|
|
97
|
+
{handle}
|
|
98
|
+
</Slot>
|
|
99
|
+
) : null}
|
|
100
|
+
{children}
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
DraggableRoot.displayName = "DraggableRoot";
|
|
106
|
+
|
|
107
|
+
const DraggableAction = forwardRef<HTMLElement, DraggableActionProps>(
|
|
108
|
+
({ active, children, className, cursor, style, ...props }, ref) => {
|
|
109
|
+
return (
|
|
110
|
+
<button
|
|
111
|
+
ref={ref as Ref<HTMLButtonElement>}
|
|
112
|
+
{...props}
|
|
113
|
+
tabIndex={0}
|
|
114
|
+
className={className}
|
|
115
|
+
style={
|
|
116
|
+
{
|
|
117
|
+
...style,
|
|
118
|
+
cursor,
|
|
119
|
+
"--fill": active?.fill,
|
|
120
|
+
"--background": active?.background,
|
|
121
|
+
} as CSSProperties
|
|
122
|
+
}
|
|
123
|
+
>
|
|
124
|
+
{children}
|
|
125
|
+
</button>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
DraggableAction.displayName = "DraggableAction";
|
|
130
|
+
|
|
131
|
+
const DraggableOverlay = ({
|
|
132
|
+
axis,
|
|
133
|
+
dropAnimation = DROP_ANIMATION_CONFIG,
|
|
134
|
+
className,
|
|
135
|
+
...props
|
|
136
|
+
}: DraggableOverlayProps) => {
|
|
137
|
+
const { active, activeNode } = useDndContext();
|
|
138
|
+
|
|
139
|
+
return createPortal(
|
|
140
|
+
<DragOverlay dropAnimation={dropAnimation} {...props}>
|
|
141
|
+
{active ? (
|
|
142
|
+
<DraggableRoot
|
|
143
|
+
axis={axis}
|
|
144
|
+
isDragging
|
|
145
|
+
isDragOverlay
|
|
146
|
+
className={cn(className, activeNode?.className)}
|
|
147
|
+
>
|
|
148
|
+
<div dangerouslySetInnerHTML={{ __html: activeNode?.innerHTML ?? "" }} />
|
|
149
|
+
</DraggableRoot>
|
|
150
|
+
) : null}
|
|
151
|
+
</DragOverlay>,
|
|
152
|
+
document.body
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
DraggableOverlay.displayName = "DraggableOverlay";
|
|
156
|
+
|
|
157
|
+
Draggable.Root = DraggableRoot;
|
|
158
|
+
Draggable.Action = DraggableAction;
|
|
159
|
+
Draggable.Overlay = DraggableOverlay;
|
|
160
|
+
|
|
161
|
+
export { Draggable };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { DropAnimation } from "@dnd-kit/core";
|
|
2
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
3
|
+
import { cva } from "../../../libs";
|
|
4
|
+
|
|
5
|
+
export const DROP_ANIMATION_CONFIG: DropAnimation = {
|
|
6
|
+
keyframes({ transform }) {
|
|
7
|
+
return [
|
|
8
|
+
{ transform: CSS.Transform.toString(transform.initial) },
|
|
9
|
+
{
|
|
10
|
+
transform: CSS.Transform.toString({
|
|
11
|
+
...transform.final,
|
|
12
|
+
scaleX: 0.96,
|
|
13
|
+
scaleY: 0.96,
|
|
14
|
+
}),
|
|
15
|
+
},
|
|
16
|
+
];
|
|
17
|
+
},
|
|
18
|
+
sideEffects({ active }) {
|
|
19
|
+
active.node.style.opacity = "0";
|
|
20
|
+
|
|
21
|
+
return () => {
|
|
22
|
+
active.node.style.opacity = "";
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const getDraggableClasses = cva(
|
|
28
|
+
"translate-x-[--translate-x] translate-y-[--translate-y] translate-z-0",
|
|
29
|
+
{
|
|
30
|
+
variants: {
|
|
31
|
+
isDragging: {
|
|
32
|
+
true: "transition-none z-10 cursor-grabbing",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
export const getDraggableRootClasses = cva("relative", {
|
|
39
|
+
variants: {
|
|
40
|
+
isDragging: {
|
|
41
|
+
true: "",
|
|
42
|
+
},
|
|
43
|
+
isDragOverlay: {
|
|
44
|
+
true: "",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Draggable } from "./Draggable";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DraggableSyntheticListeners,
|
|
3
|
+
DragOverlayProps,
|
|
4
|
+
DropAnimation,
|
|
5
|
+
UseDraggableArguments,
|
|
6
|
+
} from "@dnd-kit/core";
|
|
7
|
+
import type { CSSProperties, ReactNode, Ref } from "react";
|
|
8
|
+
import { type Transform } from "@dnd-kit/utilities";
|
|
9
|
+
|
|
10
|
+
export enum DraggableAxis {
|
|
11
|
+
All,
|
|
12
|
+
Vertical,
|
|
13
|
+
Horizontal,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type DraggableHandleElement = JSX.Element | null;
|
|
17
|
+
|
|
18
|
+
export type DraggableActionsArgs = {
|
|
19
|
+
draggable: {
|
|
20
|
+
ref: Ref<HTMLElement> | undefined;
|
|
21
|
+
listeners: DraggableSyntheticListeners;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type BaseDraggableProps = Partial<{
|
|
26
|
+
axis: DraggableAxis;
|
|
27
|
+
style: CSSProperties;
|
|
28
|
+
handle: DraggableHandleElement;
|
|
29
|
+
actions: (args: Partial<DraggableActionsArgs>) => ReactNode;
|
|
30
|
+
}> &
|
|
31
|
+
React.HTMLAttributes<HTMLDivElement>;
|
|
32
|
+
|
|
33
|
+
export type DraggableProps = BaseDraggableProps & UseDraggableArguments;
|
|
34
|
+
|
|
35
|
+
export type DraggableRootProps = BaseDraggableProps &
|
|
36
|
+
Partial<{
|
|
37
|
+
isDragOverlay: boolean;
|
|
38
|
+
|
|
39
|
+
isDragging: boolean;
|
|
40
|
+
listeners: DraggableSyntheticListeners;
|
|
41
|
+
transform: Transform | null;
|
|
42
|
+
activatorNodeRef: Ref<HTMLElement>;
|
|
43
|
+
}>;
|
|
44
|
+
|
|
45
|
+
export type DraggableActionProps = React.HTMLAttributes<HTMLButtonElement> & {
|
|
46
|
+
active?: Partial<{
|
|
47
|
+
fill: string;
|
|
48
|
+
background: string;
|
|
49
|
+
}>;
|
|
50
|
+
cursor?: CSSProperties["cursor"];
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type DraggableOverlayProps = {
|
|
54
|
+
axis?: DraggableRootProps["axis"];
|
|
55
|
+
dropAnimation?: DropAnimation | null;
|
|
56
|
+
} & DragOverlayProps;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Modifiers, UniqueIdentifier } from "@dnd-kit/core";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import {
|
|
4
|
+
closestCenter,
|
|
5
|
+
closestCorners,
|
|
6
|
+
DndContext,
|
|
7
|
+
pointerWithin,
|
|
8
|
+
rectIntersection,
|
|
9
|
+
} from "@dnd-kit/core";
|
|
10
|
+
import { Draggable } from "../Draggable";
|
|
11
|
+
import { Droppable } from "./Droppable";
|
|
12
|
+
|
|
13
|
+
type CollisionDetectionType =
|
|
14
|
+
| "rectIntersection"
|
|
15
|
+
| "closestCenter"
|
|
16
|
+
| "closestCorners"
|
|
17
|
+
| "pointerWithin";
|
|
18
|
+
|
|
19
|
+
const collisionDetectionAlgorithms = {
|
|
20
|
+
rectIntersection,
|
|
21
|
+
closestCenter,
|
|
22
|
+
closestCorners,
|
|
23
|
+
pointerWithin,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type DroppableExampleProps = {
|
|
27
|
+
collisionDetection?: CollisionDetectionType;
|
|
28
|
+
containers?: UniqueIdentifier[];
|
|
29
|
+
modifiers?: Modifiers;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const DroppableExample = ({
|
|
33
|
+
containers = ["A"],
|
|
34
|
+
collisionDetection = "rectIntersection",
|
|
35
|
+
modifiers,
|
|
36
|
+
}: DroppableExampleProps) => {
|
|
37
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
38
|
+
const [parentContainerId, setParentContainerId] = useState<UniqueIdentifier | null>(null);
|
|
39
|
+
|
|
40
|
+
const item = (
|
|
41
|
+
<Draggable
|
|
42
|
+
id="my-draggable"
|
|
43
|
+
className="w-fit border border-base-content rounded-md p-2 flex items-center gap-2 data-[draggable-active]:opacity-0"
|
|
44
|
+
>
|
|
45
|
+
Go ahead, drag me.
|
|
46
|
+
</Draggable>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<DndContext
|
|
51
|
+
collisionDetection={collisionDetectionAlgorithms[collisionDetection]}
|
|
52
|
+
modifiers={parentContainerId !== null ? undefined : modifiers}
|
|
53
|
+
onDragStart={() => setIsDragging(true)}
|
|
54
|
+
onDragEnd={({ over }) => {
|
|
55
|
+
setParentContainerId(over ? over.id : null);
|
|
56
|
+
setIsDragging(false);
|
|
57
|
+
}}
|
|
58
|
+
onDragCancel={() => setIsDragging(false)}
|
|
59
|
+
>
|
|
60
|
+
<div className="flex gap-6 items-center">
|
|
61
|
+
<div className="my-10 w-52">{parentContainerId === null ? item : null}</div>
|
|
62
|
+
<div className="grid grid-cols-2 gap-6">
|
|
63
|
+
{containers.map((id) => (
|
|
64
|
+
<Droppable
|
|
65
|
+
key={id}
|
|
66
|
+
id={id}
|
|
67
|
+
isDragging={isDragging}
|
|
68
|
+
className="relative p-6 border border-base-300 rounded-md w-72 h-72 bg-base-200 box-border data-[draggable-active]:opacity-80 data-[draggable-over]:opacity-100 transition-opacity"
|
|
69
|
+
>
|
|
70
|
+
<div className="absolute bottom-6">Container {id}</div>
|
|
71
|
+
{parentContainerId === id ? item : null}
|
|
72
|
+
</Droppable>
|
|
73
|
+
))}
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
<Draggable.Overlay />
|
|
77
|
+
</DndContext>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const CollisionDetectionAlgorithmsDroppableExample = ({
|
|
82
|
+
collisionDetection,
|
|
83
|
+
...props
|
|
84
|
+
}: DroppableExampleProps) => {
|
|
85
|
+
return <DroppableExample {...props} collisionDetection={collisionDetection} />;
|
|
86
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useDroppable } from "@dnd-kit/core";
|
|
4
|
+
import { cn } from "../../../utilities";
|
|
5
|
+
import { getDroppableClasses } from "./constants";
|
|
6
|
+
import { type DroppableProps } from "./types";
|
|
7
|
+
|
|
8
|
+
export const Droppable = ({
|
|
9
|
+
children,
|
|
10
|
+
id,
|
|
11
|
+
disabled,
|
|
12
|
+
data,
|
|
13
|
+
resizeObserverConfig,
|
|
14
|
+
isDragging,
|
|
15
|
+
className,
|
|
16
|
+
...props
|
|
17
|
+
}: DroppableProps) => {
|
|
18
|
+
const { isOver, setNodeRef } = useDroppable({
|
|
19
|
+
id,
|
|
20
|
+
data,
|
|
21
|
+
disabled,
|
|
22
|
+
resizeObserverConfig,
|
|
23
|
+
});
|
|
24
|
+
const isEmpty = !children || undefined;
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div
|
|
28
|
+
ref={setNodeRef}
|
|
29
|
+
className={cn(className, getDroppableClasses({ isDragging, isOver, isEmpty }))}
|
|
30
|
+
data-empty={isEmpty}
|
|
31
|
+
data-draggable-over={isOver || undefined}
|
|
32
|
+
data-draggable-active={isDragging || undefined}
|
|
33
|
+
{...props}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Droppable } from "./Droppable";
|