@seedgrid/fe-components 2026.3.9 → 2026.3.11-1
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/buttons/SgButton.d.ts +2 -0
- package/dist/buttons/SgButton.d.ts.map +1 -1
- package/dist/buttons/SgButton.js +4 -3
- package/dist/digits/segment-digit/SgSegmentDigit.d.ts +15 -0
- package/dist/digits/segment-digit/SgSegmentDigit.d.ts.map +1 -0
- package/dist/digits/segment-digit/SgSegmentDigit.js +96 -0
- package/dist/digits/segment-digit/index.d.ts +3 -0
- package/dist/digits/segment-digit/index.d.ts.map +1 -0
- package/dist/digits/segment-digit/index.js +1 -0
- package/dist/digits/seven-segment-digit/SgSevenSegmentDigit.d.ts +36 -0
- package/dist/digits/seven-segment-digit/SgSevenSegmentDigit.d.ts.map +1 -0
- package/dist/digits/seven-segment-digit/SgSevenSegmentDigit.js +123 -0
- package/dist/digits/seven-segment-digit/index.d.ts +3 -0
- package/dist/digits/seven-segment-digit/index.d.ts.map +1 -0
- package/dist/digits/seven-segment-digit/index.js +1 -0
- package/dist/gadgets/calendar/SgCalendar.d.ts +29 -0
- package/dist/gadgets/calendar/SgCalendar.d.ts.map +1 -0
- package/dist/gadgets/calendar/SgCalendar.js +248 -0
- package/dist/gadgets/calendar/index.d.ts +3 -0
- package/dist/gadgets/calendar/index.d.ts.map +1 -0
- package/dist/gadgets/calendar/index.js +1 -0
- package/dist/gadgets/clock/SgClock.d.ts +4 -1
- package/dist/gadgets/clock/SgClock.d.ts.map +1 -1
- package/dist/gadgets/clock/SgClock.js +74 -115
- package/dist/i18n/en-US.d.ts.map +1 -1
- package/dist/i18n/en-US.js +11 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +11 -1
- package/dist/i18n/pt-BR.d.ts.map +1 -1
- package/dist/i18n/pt-BR.js +11 -1
- package/dist/i18n/pt-PT.d.ts.map +1 -1
- package/dist/i18n/pt-PT.js +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/inputs/SgDatatable.d.ts +104 -0
- package/dist/inputs/SgDatatable.d.ts.map +1 -0
- package/dist/inputs/SgDatatable.js +441 -0
- package/dist/layout/SgCard.d.ts +12 -0
- package/dist/layout/SgCard.d.ts.map +1 -1
- package/dist/layout/SgCard.js +228 -12
- package/dist/overlay/SgConfirmationDialog.d.ts +34 -0
- package/dist/overlay/SgConfirmationDialog.d.ts.map +1 -0
- package/dist/overlay/SgConfirmationDialog.js +81 -0
- package/dist/overlay/SgDialog.d.ts +5 -0
- package/dist/overlay/SgDialog.d.ts.map +1 -1
- package/dist/overlay/SgDialog.js +28 -3
- package/dist/sandbox.cjs +83 -83
- package/package.json +1 -1
package/dist/layout/SgCard.js
CHANGED
|
@@ -1,16 +1,152 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { useHasSgEnvironmentProvider, useSgPersistence } from "../environment/SgEnvironmentProvider";
|
|
4
5
|
function cn(...parts) {
|
|
5
6
|
return parts.filter(Boolean).join(" ");
|
|
6
7
|
}
|
|
7
|
-
function
|
|
8
|
-
|
|
8
|
+
function parseStoredCardPosition(raw) {
|
|
9
|
+
const value = typeof raw === "string"
|
|
10
|
+
? (() => {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(raw);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
})()
|
|
18
|
+
: raw;
|
|
19
|
+
if (!value ||
|
|
20
|
+
typeof value !== "object" ||
|
|
21
|
+
typeof value.x !== "number" ||
|
|
22
|
+
typeof value.y !== "number" ||
|
|
23
|
+
!Number.isFinite(value.x) ||
|
|
24
|
+
!Number.isFinite(value.y)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
x: value.x,
|
|
29
|
+
y: value.y
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function mergeTransforms(baseTransform, extraTransform) {
|
|
33
|
+
if (typeof baseTransform === "string" && baseTransform.trim().length > 0) {
|
|
34
|
+
return `${baseTransform} ${extraTransform}`;
|
|
35
|
+
}
|
|
36
|
+
return extraTransform;
|
|
37
|
+
}
|
|
38
|
+
function DefaultCaret({ open, size }) {
|
|
39
|
+
return (_jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", className: cn("shrink-0 transition-transform duration-200", open ? "rotate-90" : "rotate-0"), "aria-hidden": "true", children: _jsx("path", { fill: "currentColor", d: "M9.29 6.71a1 1 0 0 0 0 1.41L13.17 12l-3.88 3.88a1 1 0 1 0 1.41 1.41l4.59-4.59a1 1 0 0 0 0-1.41L10.7 6.7a1 1 0 0 0-1.41.01Z" }) }));
|
|
9
40
|
}
|
|
10
41
|
export function SgCard(props) {
|
|
11
|
-
const { className, headerClassName, bodyClassName, footerClassName, cardStyle = "default", size = "md", leading, trailing, trailer, title, description, actions, header, footer, clickable = false, disabled = false, collapsible = false, defaultOpen = true, open: controlledOpen, onOpenChange, collapseIcon, collapseToggleAlign = "left", toggleOnHeaderClick = true, onClick, children, ...rest } = props;
|
|
12
|
-
const
|
|
42
|
+
const { id, className, headerClassName, bodyClassName, footerClassName, bgColor, bgColorTitle, bgColorFooter, cardStyle = "default", size = "md", leading, trailing, trailer, title, description, actions, header, footer, clickable = false, disabled = false, collapsible = false, defaultOpen = true, open: controlledOpen, onOpenChange, collapseIcon, collapseIconSize = 18, collapseToggleAlign = "left", toggleOnHeaderClick = true, draggable = false, defaultPosition, dragPersistKey, onPositionChange, style, onClick, children, ...rest } = props;
|
|
43
|
+
const hasEnvironmentProvider = useHasSgEnvironmentProvider();
|
|
44
|
+
const { load: loadPersistedState, save: savePersistedState, clear: clearPersistedState } = useSgPersistence();
|
|
45
|
+
const isInteractive = (clickable || typeof onClick === "function") && !collapsible && !draggable;
|
|
13
46
|
const trailingNode = trailing ?? trailer;
|
|
47
|
+
const [dragPosition, setDragPosition] = React.useState({
|
|
48
|
+
x: defaultPosition?.x ?? 0,
|
|
49
|
+
y: defaultPosition?.y ?? 0
|
|
50
|
+
});
|
|
51
|
+
const dragPositionRef = React.useRef(dragPosition);
|
|
52
|
+
const [dragHydrated, setDragHydrated] = React.useState(false);
|
|
53
|
+
const [dragging, setDragging] = React.useState(false);
|
|
54
|
+
const dragStateRef = React.useRef(null);
|
|
55
|
+
const suppressNextToggleRef = React.useRef(false);
|
|
56
|
+
const dragStorageKey = React.useMemo(() => {
|
|
57
|
+
if (typeof dragPersistKey === "string" && dragPersistKey.trim().length > 0) {
|
|
58
|
+
return dragPersistKey.trim();
|
|
59
|
+
}
|
|
60
|
+
if (typeof id === "string" && id.trim().length > 0) {
|
|
61
|
+
return `sg-card-pos:${id.trim()}`;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}, [dragPersistKey, id]);
|
|
65
|
+
React.useEffect(() => {
|
|
66
|
+
dragPositionRef.current = dragPosition;
|
|
67
|
+
onPositionChange?.(dragPosition);
|
|
68
|
+
}, [dragPosition, onPositionChange]);
|
|
69
|
+
React.useEffect(() => {
|
|
70
|
+
if (!draggable) {
|
|
71
|
+
setDragHydrated(false);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
let alive = true;
|
|
75
|
+
(async () => {
|
|
76
|
+
let loaded = null;
|
|
77
|
+
if (dragStorageKey) {
|
|
78
|
+
if (hasEnvironmentProvider) {
|
|
79
|
+
try {
|
|
80
|
+
const state = await loadPersistedState(dragStorageKey);
|
|
81
|
+
loaded = parseStoredCardPosition(state);
|
|
82
|
+
if (!loaded && state !== null && state !== undefined) {
|
|
83
|
+
await clearPersistedState(dragStorageKey);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
loaded = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
try {
|
|
92
|
+
const raw = localStorage.getItem(dragStorageKey);
|
|
93
|
+
loaded = parseStoredCardPosition(raw);
|
|
94
|
+
if (!loaded && raw !== null) {
|
|
95
|
+
localStorage.removeItem(dragStorageKey);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
loaded = null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (!alive)
|
|
104
|
+
return;
|
|
105
|
+
if (loaded) {
|
|
106
|
+
setDragPosition(loaded);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
setDragPosition({
|
|
110
|
+
x: defaultPosition?.x ?? 0,
|
|
111
|
+
y: defaultPosition?.y ?? 0
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
setDragHydrated(true);
|
|
115
|
+
})();
|
|
116
|
+
return () => {
|
|
117
|
+
alive = false;
|
|
118
|
+
};
|
|
119
|
+
}, [
|
|
120
|
+
clearPersistedState,
|
|
121
|
+
defaultPosition?.x,
|
|
122
|
+
defaultPosition?.y,
|
|
123
|
+
dragStorageKey,
|
|
124
|
+
draggable,
|
|
125
|
+
hasEnvironmentProvider,
|
|
126
|
+
loadPersistedState
|
|
127
|
+
]);
|
|
128
|
+
React.useEffect(() => {
|
|
129
|
+
if (!draggable || !dragHydrated || !dragStorageKey || dragging)
|
|
130
|
+
return;
|
|
131
|
+
if (hasEnvironmentProvider) {
|
|
132
|
+
void savePersistedState(dragStorageKey, dragPosition);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
localStorage.setItem(dragStorageKey, JSON.stringify(dragPosition));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// ignore
|
|
140
|
+
}
|
|
141
|
+
}, [
|
|
142
|
+
dragHydrated,
|
|
143
|
+
dragPosition,
|
|
144
|
+
dragStorageKey,
|
|
145
|
+
draggable,
|
|
146
|
+
dragging,
|
|
147
|
+
hasEnvironmentProvider,
|
|
148
|
+
savePersistedState
|
|
149
|
+
]);
|
|
14
150
|
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
|
|
15
151
|
const isControlled = typeof controlledOpen === "boolean";
|
|
16
152
|
const isOpen = collapsible ? (isControlled ? controlledOpen : uncontrolledOpen) : true;
|
|
@@ -58,9 +194,13 @@ export function SgCard(props) {
|
|
|
58
194
|
? cn("transition-[box-shadow,transform] duration-150", "hover:shadow-md", "focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-[hsl(var(--primary)/0.35)]", disabled ? "" : "cursor-pointer", disabled ? "" : "active:translate-y-[0.5px]")
|
|
59
195
|
: "";
|
|
60
196
|
const disabledClasses = disabled ? "opacity-60 pointer-events-none select-none" : "";
|
|
61
|
-
const rootClasses = cn("w-full", sizeClasses.root, variantClasses, interactiveClasses, disabledClasses, className);
|
|
197
|
+
const rootClasses = cn("w-full", sizeClasses.root, variantClasses, interactiveClasses, disabledClasses, draggable ? "touch-none" : "", className);
|
|
62
198
|
const toggle = React.useCallback(() => setOpen(!isOpen), [isOpen, setOpen]);
|
|
63
199
|
const onHeaderClick = () => {
|
|
200
|
+
if (suppressNextToggleRef.current) {
|
|
201
|
+
suppressNextToggleRef.current = false;
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
64
204
|
if (!collapsible)
|
|
65
205
|
return;
|
|
66
206
|
if (!toggleOnHeaderClick)
|
|
@@ -69,10 +209,74 @@ export function SgCard(props) {
|
|
|
69
209
|
return;
|
|
70
210
|
toggle();
|
|
71
211
|
};
|
|
72
|
-
const
|
|
212
|
+
const onHeaderPointerDown = React.useCallback((event) => {
|
|
213
|
+
if (!draggable || disabled)
|
|
214
|
+
return;
|
|
215
|
+
if (event.button !== 0)
|
|
216
|
+
return;
|
|
217
|
+
const target = event.target;
|
|
218
|
+
const interactiveAncestor = target?.closest("[data-sg-card-toggle=\"true\"],button,a,input,textarea,select,[role=\"button\"],[data-sg-card-no-drag=\"true\"]");
|
|
219
|
+
if (interactiveAncestor && interactiveAncestor !== event.currentTarget) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
dragStateRef.current = {
|
|
223
|
+
pointerId: event.pointerId,
|
|
224
|
+
startX: event.clientX,
|
|
225
|
+
startY: event.clientY,
|
|
226
|
+
originX: dragPositionRef.current.x,
|
|
227
|
+
originY: dragPositionRef.current.y,
|
|
228
|
+
moved: false
|
|
229
|
+
};
|
|
230
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
231
|
+
setDragging(true);
|
|
232
|
+
event.preventDefault();
|
|
233
|
+
}, [disabled, draggable]);
|
|
234
|
+
const onHeaderPointerMove = React.useCallback((event) => {
|
|
235
|
+
const state = dragStateRef.current;
|
|
236
|
+
if (!state || state.pointerId !== event.pointerId)
|
|
237
|
+
return;
|
|
238
|
+
const dx = event.clientX - state.startX;
|
|
239
|
+
const dy = event.clientY - state.startY;
|
|
240
|
+
if (!state.moved && (Math.abs(dx) > 2 || Math.abs(dy) > 2)) {
|
|
241
|
+
state.moved = true;
|
|
242
|
+
}
|
|
243
|
+
setDragPosition({
|
|
244
|
+
x: state.originX + dx,
|
|
245
|
+
y: state.originY + dy
|
|
246
|
+
});
|
|
247
|
+
if (state.moved) {
|
|
248
|
+
event.preventDefault();
|
|
249
|
+
}
|
|
250
|
+
}, []);
|
|
251
|
+
const endHeaderDrag = React.useCallback((event) => {
|
|
252
|
+
const state = dragStateRef.current;
|
|
253
|
+
if (!state || state.pointerId !== event.pointerId)
|
|
254
|
+
return;
|
|
255
|
+
if (state.moved) {
|
|
256
|
+
suppressNextToggleRef.current = true;
|
|
257
|
+
}
|
|
258
|
+
dragStateRef.current = null;
|
|
259
|
+
setDragging(false);
|
|
260
|
+
try {
|
|
261
|
+
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
// ignore
|
|
265
|
+
}
|
|
266
|
+
}, []);
|
|
267
|
+
const headerInteractionClasses = disabled
|
|
268
|
+
? ""
|
|
269
|
+
: draggable
|
|
270
|
+
? dragging
|
|
271
|
+
? "cursor-grabbing"
|
|
272
|
+
: "cursor-grab"
|
|
273
|
+
: collapsible && toggleOnHeaderClick
|
|
274
|
+
? "cursor-pointer"
|
|
275
|
+
: "";
|
|
276
|
+
const ToggleButton = collapsible ? (_jsx("button", { "data-sg-card-toggle": "true", type: "button", onClick: (e) => {
|
|
73
277
|
e.stopPropagation();
|
|
74
278
|
toggle();
|
|
75
|
-
}, className: cn("inline-flex h-
|
|
279
|
+
}, className: cn("inline-flex h-9 w-9 items-center justify-center rounded-md", "text-muted-foreground hover:text-foreground", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--primary)/0.35)]"), "aria-label": isOpen ? "Recolher" : "Expandir", "aria-expanded": isOpen, disabled: disabled, children: collapseIcon ?? _jsx(DefaultCaret, { open: isOpen, size: collapseIconSize }) })) : null;
|
|
76
280
|
const headerHasContent = Boolean(header) ||
|
|
77
281
|
Boolean(leading) ||
|
|
78
282
|
Boolean(title) ||
|
|
@@ -80,7 +284,7 @@ export function SgCard(props) {
|
|
|
80
284
|
Boolean(trailingNode) ||
|
|
81
285
|
Boolean(actions) ||
|
|
82
286
|
collapsible;
|
|
83
|
-
const renderDefaultHeader = headerHasContent ? (_jsxs("div", { className: cn("flex items-start gap-3", "border-b border-border/60", sizeClasses.header, headerClassName,
|
|
287
|
+
const renderDefaultHeader = headerHasContent ? (_jsxs("div", { className: cn("flex items-start gap-3", "border-b border-border/60", sizeClasses.header, headerClassName, headerInteractionClasses), style: bgColorTitle ? { backgroundColor: bgColorTitle } : undefined, onClick: onHeaderClick, onPointerDown: onHeaderPointerDown, onPointerMove: onHeaderPointerMove, onPointerUp: endHeaderDrag, onPointerCancel: endHeaderDrag, role: collapsible && toggleOnHeaderClick ? "button" : undefined, tabIndex: collapsible && toggleOnHeaderClick && !disabled ? 0 : undefined, onKeyDown: (e) => {
|
|
84
288
|
if (!collapsible || !toggleOnHeaderClick || disabled)
|
|
85
289
|
return;
|
|
86
290
|
if (e.key === "Enter" || e.key === " ") {
|
|
@@ -88,7 +292,7 @@ export function SgCard(props) {
|
|
|
88
292
|
toggle();
|
|
89
293
|
}
|
|
90
294
|
}, "aria-expanded": collapsible ? isOpen : undefined, children: [collapseToggleAlign === "left" ? ToggleButton : null, leading ? _jsx("div", { className: "shrink-0 pt-0.5", children: leading }) : null, _jsxs("div", { className: "min-w-0 flex-1", children: [title ? (_jsx("div", { className: cn("font-medium text-foreground", sizeClasses.title), children: title })) : null, description ? (_jsx("div", { className: cn("mt-0.5 text-muted-foreground", sizeClasses.desc), children: description })) : null] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [trailingNode ? _jsx("div", { className: "shrink-0", children: trailingNode }) : null, actions ? _jsx("div", { className: "shrink-0", children: actions }) : null, collapseToggleAlign === "right" ? ToggleButton : null] })] })) : null;
|
|
91
|
-
const headerNode = header ? (_jsx("div", { className: cn("border-b border-border/60", sizeClasses.header, headerClassName,
|
|
295
|
+
const headerNode = header ? (_jsx("div", { className: cn("border-b border-border/60", sizeClasses.header, headerClassName, headerInteractionClasses), style: bgColorTitle ? { backgroundColor: bgColorTitle } : undefined, onClick: onHeaderClick, onPointerDown: onHeaderPointerDown, onPointerMove: onHeaderPointerMove, onPointerUp: endHeaderDrag, onPointerCancel: endHeaderDrag, role: collapsible && toggleOnHeaderClick ? "button" : undefined, tabIndex: collapsible && toggleOnHeaderClick && !disabled ? 0 : undefined, onKeyDown: (e) => {
|
|
92
296
|
if (!collapsible || !toggleOnHeaderClick || disabled)
|
|
93
297
|
return;
|
|
94
298
|
if (e.key === "Enter" || e.key === " ") {
|
|
@@ -96,11 +300,23 @@ export function SgCard(props) {
|
|
|
96
300
|
toggle();
|
|
97
301
|
}
|
|
98
302
|
}, "aria-expanded": collapsible ? isOpen : undefined, children: header })) : (renderDefaultHeader);
|
|
99
|
-
const collapsibleBodyWrapper = collapsible ? (_jsx("div", { className: cn("grid transition-all duration-200 ease-out motion-reduce:transition-none", isOpen ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"), children: _jsxs("div", { className: "overflow-hidden", children: [_jsx("div", { className: cn(sizeClasses.body, bodyClassName), children: children }), footer ? (_jsx("div", { className: cn("border-t border-border/60", sizeClasses.footer, footerClassName), children: footer })) : null] }) })) : null;
|
|
303
|
+
const collapsibleBodyWrapper = collapsible ? (_jsx("div", { className: cn("grid transition-all duration-200 ease-out motion-reduce:transition-none", isOpen ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"), children: _jsxs("div", { className: isOpen ? "overflow-visible" : "overflow-hidden", children: [_jsx("div", { className: cn(sizeClasses.body, bodyClassName), children: children }), footer ? (_jsx("div", { className: cn("border-t border-border/60", sizeClasses.footer, footerClassName), style: bgColorFooter ? { backgroundColor: bgColorFooter } : undefined, children: footer })) : null] }) })) : null;
|
|
100
304
|
const bodyNode = !collapsible ? _jsx("div", { className: cn(sizeClasses.body, bodyClassName), children: children }) : null;
|
|
101
|
-
const footerNode = !collapsible && footer ? (_jsx("div", { className: cn("border-t border-border/60", sizeClasses.footer, footerClassName), children: footer })) : null;
|
|
305
|
+
const footerNode = !collapsible && footer ? (_jsx("div", { className: cn("border-t border-border/60", sizeClasses.footer, footerClassName), style: bgColorFooter ? { backgroundColor: bgColorFooter } : undefined, children: footer })) : null;
|
|
102
306
|
const Component = isInteractive ? "button" : "section";
|
|
103
307
|
const buttonLikeProps = isInteractive ? { type: "button", onClick: disabled ? undefined : onClick, disabled } : {};
|
|
104
|
-
|
|
308
|
+
const passiveOnClickProps = !isInteractive && typeof onClick === "function" ? { onClick: disabled ? undefined : onClick } : {};
|
|
309
|
+
const roundedDragX = Math.round(dragPosition.x);
|
|
310
|
+
const roundedDragY = Math.round(dragPosition.y);
|
|
311
|
+
const shouldApplyDragTransform = draggable && (dragging || roundedDragX !== 0 || roundedDragY !== 0);
|
|
312
|
+
const rootStyle = {
|
|
313
|
+
...style,
|
|
314
|
+
backgroundColor: bgColor ?? style?.backgroundColor,
|
|
315
|
+
transform: shouldApplyDragTransform
|
|
316
|
+
? mergeTransforms(style?.transform, `translate3d(${roundedDragX}px, ${roundedDragY}px, 0)`)
|
|
317
|
+
: style?.transform,
|
|
318
|
+
willChange: shouldApplyDragTransform ? "transform" : style?.willChange
|
|
319
|
+
};
|
|
320
|
+
return (_jsxs(Component, { id: id, className: rootClasses, style: rootStyle, ...buttonLikeProps, ...passiveOnClickProps, ...rest, children: [headerNode, collapsible ? collapsibleBodyWrapper : null, !collapsible ? bodyNode : null, !collapsible ? footerNode : null] }));
|
|
105
321
|
}
|
|
106
322
|
SgCard.displayName = "SgCard";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type SgButtonProps } from "../buttons/SgButton";
|
|
3
|
+
import { type SgDialogProps, type SgDialogSeverity } from "./SgDialog";
|
|
4
|
+
export type SgConfirmationDialogButtonConfig = {
|
|
5
|
+
label?: React.ReactNode;
|
|
6
|
+
icon?: React.ReactNode;
|
|
7
|
+
severity?: SgButtonProps["severity"];
|
|
8
|
+
appearance?: SgButtonProps["appearance"];
|
|
9
|
+
shape?: SgButtonProps["shape"];
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
onClick?: () => void;
|
|
13
|
+
};
|
|
14
|
+
export type SgConfirmationDialogProps = Omit<SgDialogProps, "title" | "children" | "footer" | "severity" | "shadow" | "showTopAccent"> & {
|
|
15
|
+
title?: React.ReactNode;
|
|
16
|
+
message?: React.ReactNode;
|
|
17
|
+
icon?: React.ReactNode;
|
|
18
|
+
iconPlacement?: "left" | "top";
|
|
19
|
+
severity?: SgDialogSeverity;
|
|
20
|
+
customColor?: SgDialogProps["customColor"];
|
|
21
|
+
elevation?: SgDialogProps["elevation"];
|
|
22
|
+
showSeverityAccent?: boolean;
|
|
23
|
+
cancelButton?: SgConfirmationDialogButtonConfig;
|
|
24
|
+
confirmButton?: SgConfirmationDialogButtonConfig;
|
|
25
|
+
onCancel?: () => void;
|
|
26
|
+
onConfirm?: () => void;
|
|
27
|
+
closeOnCancel?: boolean;
|
|
28
|
+
closeOnConfirm?: boolean;
|
|
29
|
+
};
|
|
30
|
+
export declare function SgConfirmationDialog(props: Readonly<SgConfirmationDialogProps>): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare namespace SgConfirmationDialog {
|
|
32
|
+
var displayName: string;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=SgConfirmationDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SgConfirmationDialog.d.ts","sourceRoot":"","sources":["../../src/overlay/SgConfirmationDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EAAY,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEjF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,aAAa,EACb,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,eAAe,CAC1E,GAAG;IACF,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC/B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,WAAW,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IACvC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,gCAAgC,CAAC;IAChD,aAAa,CAAC,EAAE,gCAAgC,CAAC;IACjD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAoEF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,yBAAyB,CAAC,2CA2I9E;yBA3Ie,oBAAoB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { SgButton } from "../buttons/SgButton";
|
|
5
|
+
import { t, useComponentsI18n } from "../i18n";
|
|
6
|
+
import { SgDialog } from "./SgDialog";
|
|
7
|
+
function resolveButtonSeverity(dialogSeverity, fallback) {
|
|
8
|
+
if (!dialogSeverity || dialogSeverity === "plain")
|
|
9
|
+
return fallback;
|
|
10
|
+
return dialogSeverity;
|
|
11
|
+
}
|
|
12
|
+
function DefaultCancelIcon() {
|
|
13
|
+
return (_jsx("svg", { viewBox: "0 0 24 24", className: "size-4", "aria-hidden": "true", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
|
|
14
|
+
}
|
|
15
|
+
function DefaultConfirmIcon() {
|
|
16
|
+
return (_jsx("svg", { viewBox: "0 0 24 24", className: "size-4", "aria-hidden": "true", children: _jsx("path", { d: "M5 12l5 5L20 7", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
17
|
+
}
|
|
18
|
+
function DefaultInfoSeverityIcon() {
|
|
19
|
+
return (_jsxs("svg", { viewBox: "0 0 24 24", className: "size-5 text-sky-600", "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "12", r: "9", fill: "none", stroke: "currentColor", strokeWidth: "2" }), _jsx("path", { d: "M12 10v6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }), _jsx("circle", { cx: "12", cy: "7", r: "1.25", fill: "currentColor" })] }));
|
|
20
|
+
}
|
|
21
|
+
function DefaultWarningSeverityIcon() {
|
|
22
|
+
return (_jsxs("svg", { viewBox: "0 0 24 24", className: "size-5 text-amber-600", "aria-hidden": "true", children: [_jsx("path", { d: "M12 3L22 20H2L12 3z", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" }), _jsx("path", { d: "M12 9v5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }), _jsx("circle", { cx: "12", cy: "17.25", r: "1.1", fill: "currentColor" })] }));
|
|
23
|
+
}
|
|
24
|
+
function DefaultDangerSeverityIcon() {
|
|
25
|
+
return (_jsxs("svg", { viewBox: "0 0 24 24", className: "size-5 text-red-600", "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "12", r: "9", fill: "none", stroke: "currentColor", strokeWidth: "2" }), _jsx("path", { d: "M9 9l6 6M15 9l-6 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })] }));
|
|
26
|
+
}
|
|
27
|
+
function defaultSeverityIcon(severity) {
|
|
28
|
+
switch (severity) {
|
|
29
|
+
case "info":
|
|
30
|
+
return _jsx(DefaultInfoSeverityIcon, {});
|
|
31
|
+
case "warning":
|
|
32
|
+
return _jsx(DefaultWarningSeverityIcon, {});
|
|
33
|
+
case "danger":
|
|
34
|
+
return _jsx(DefaultDangerSeverityIcon, {});
|
|
35
|
+
default:
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function SgConfirmationDialog(props) {
|
|
40
|
+
const { open: openProp, defaultOpen = false, onOpenChange, onClose, title, message, icon, iconPlacement = "left", severity = "warning", customColor, elevation, showSeverityAccent = false, cancelButton, confirmButton, onCancel, onConfirm, closeOnCancel = true, closeOnConfirm = true, closeable = false, size = "sm", ...dialogProps } = props;
|
|
41
|
+
const i18n = useComponentsI18n();
|
|
42
|
+
const isControlled = openProp !== undefined;
|
|
43
|
+
const [openUncontrolled, setOpenUncontrolled] = React.useState(defaultOpen);
|
|
44
|
+
const open = isControlled ? Boolean(openProp) : openUncontrolled;
|
|
45
|
+
const setOpen = React.useCallback((next) => {
|
|
46
|
+
if (!isControlled)
|
|
47
|
+
setOpenUncontrolled(next);
|
|
48
|
+
onOpenChange?.(next);
|
|
49
|
+
}, [isControlled, onOpenChange]);
|
|
50
|
+
const fireCancel = React.useCallback(() => {
|
|
51
|
+
cancelButton?.onClick?.();
|
|
52
|
+
onCancel?.();
|
|
53
|
+
}, [cancelButton, onCancel]);
|
|
54
|
+
const handleCancel = React.useCallback(() => {
|
|
55
|
+
fireCancel();
|
|
56
|
+
if (closeOnCancel)
|
|
57
|
+
setOpen(false);
|
|
58
|
+
}, [fireCancel, closeOnCancel, setOpen]);
|
|
59
|
+
const handleConfirm = React.useCallback(() => {
|
|
60
|
+
confirmButton?.onClick?.();
|
|
61
|
+
onConfirm?.();
|
|
62
|
+
if (closeOnConfirm)
|
|
63
|
+
setOpen(false);
|
|
64
|
+
}, [confirmButton, onConfirm, closeOnConfirm, setOpen]);
|
|
65
|
+
const handleDialogOpenChange = React.useCallback((next) => {
|
|
66
|
+
if (!next && open) {
|
|
67
|
+
fireCancel();
|
|
68
|
+
}
|
|
69
|
+
setOpen(next);
|
|
70
|
+
}, [open, fireCancel, setOpen]);
|
|
71
|
+
const cancelLabel = cancelButton?.label ?? t(i18n, "components.actions.cancel");
|
|
72
|
+
const confirmLabel = confirmButton?.label ?? t(i18n, "components.actions.confirm");
|
|
73
|
+
const cancelIcon = cancelButton?.icon ?? _jsx(DefaultCancelIcon, {});
|
|
74
|
+
const confirmIcon = confirmButton?.icon ?? _jsx(DefaultConfirmIcon, {});
|
|
75
|
+
const resolvedIcon = icon !== undefined ? icon : defaultSeverityIcon(severity);
|
|
76
|
+
const cancelSeverity = cancelButton?.severity ?? "secondary";
|
|
77
|
+
const confirmSeverity = confirmButton?.severity ?? resolveButtonSeverity(severity, "primary");
|
|
78
|
+
const messageBlock = (_jsx("div", { className: "text-sm text-muted-foreground", children: message }));
|
|
79
|
+
return (_jsx(SgDialog, { ...dialogProps, open: open, onOpenChange: handleDialogOpenChange, onClose: onClose, closeable: closeable, severity: severity, showTopAccent: showSeverityAccent, customColor: customColor, elevation: elevation, title: title, size: size, footer: (_jsxs(_Fragment, { children: [_jsx(SgButton, { size: "sm", appearance: cancelButton?.appearance ?? "ghost", severity: cancelSeverity, shape: cancelButton?.shape ?? "rounded", disabled: cancelButton?.disabled, className: cancelButton?.className, leftIcon: cancelIcon, onClick: handleCancel, children: cancelLabel }), _jsx(SgButton, { size: "sm", appearance: confirmButton?.appearance ?? "solid", severity: confirmSeverity, shape: confirmButton?.shape ?? "rounded", disabled: confirmButton?.disabled, className: confirmButton?.className, leftIcon: confirmIcon, onClick: handleConfirm, children: confirmLabel })] })), children: resolvedIcon ? (iconPlacement === "top" ? (_jsxs("div", { className: "flex flex-col items-start gap-3", children: [_jsx("div", { className: "shrink-0", children: resolvedIcon }), messageBlock] })) : (_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "shrink-0", children: resolvedIcon }), _jsx("div", { className: "min-w-0", children: messageBlock })] }))) : (messageBlock) }));
|
|
80
|
+
}
|
|
81
|
+
SgConfirmationDialog.displayName = "SgConfirmationDialog";
|
|
@@ -19,6 +19,11 @@ export type SgDialogProps = {
|
|
|
19
19
|
autoCloseMs?: number;
|
|
20
20
|
className?: string;
|
|
21
21
|
style?: React.CSSProperties;
|
|
22
|
+
customColor?: React.CSSProperties["backgroundColor"];
|
|
23
|
+
elevation?: "none" | "sm" | "md" | "lg" | React.CSSProperties["boxShadow"];
|
|
24
|
+
/** @deprecated use elevation */
|
|
25
|
+
shadow?: React.CSSProperties["boxShadow"];
|
|
26
|
+
showTopAccent?: boolean;
|
|
22
27
|
overlayClassName?: string;
|
|
23
28
|
contentClassName?: string;
|
|
24
29
|
headerClassName?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgDialog.d.ts","sourceRoot":"","sources":["../../src/overlay/SgDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAC9D,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,SAAS,GACT,MAAM,GACN,SAAS,GACT,MAAM,GACN,QAAQ,GACR,OAAO,CAAC;AACZ,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEzB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;
|
|
1
|
+
{"version":3,"file":"SgDialog.d.ts","sourceRoot":"","sources":["../../src/overlay/SgDialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAC9D,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,SAAS,GACT,MAAM,GACN,SAAS,GACT,MAAM,GACN,QAAQ,GACR,OAAO,CAAC;AACZ,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEzB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC3E,gCAAgC;IAChC,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA2EF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,4BAmQtD;yBAnQe,QAAQ"}
|
package/dist/overlay/SgDialog.js
CHANGED
|
@@ -51,8 +51,26 @@ function contentStateClass(animation, entered) {
|
|
|
51
51
|
return cn(common, entered ? "translate-y-0" : "translate-y-2");
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
function resolveDialogShadow(elevation, shadow) {
|
|
55
|
+
if (elevation === undefined)
|
|
56
|
+
return shadow;
|
|
57
|
+
if (typeof elevation !== "string")
|
|
58
|
+
return elevation;
|
|
59
|
+
switch (elevation) {
|
|
60
|
+
case "none":
|
|
61
|
+
return "none";
|
|
62
|
+
case "sm":
|
|
63
|
+
return "0 1px 2px rgba(2, 8, 23, 0.12)";
|
|
64
|
+
case "md":
|
|
65
|
+
return "0 10px 24px rgba(2, 8, 23, 0.2), 0 4px 10px rgba(2, 8, 23, 0.12)";
|
|
66
|
+
case "lg":
|
|
67
|
+
return "0 24px 60px rgba(2, 8, 23, 0.32), 0 12px 24px rgba(2, 8, 23, 0.18)";
|
|
68
|
+
default:
|
|
69
|
+
return elevation;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
54
72
|
export function SgDialog(props) {
|
|
55
|
-
const { open: openProp, onOpenChange, defaultOpen = false, title, subtitle, leading, trailing, children, footer, size = "md", severity = "plain", animation = "zoom", transitionMs = 160, autoCloseMs, className, style, overlayClassName, contentClassName, headerClassName, bodyClassName, footerClassName, closeable = true, onClose, closeOnOverlayClick = true, closeOnEsc = true, lockBodyScroll = true, initialFocusRef, restoreFocus = true, ariaLabel } = props;
|
|
73
|
+
const { open: openProp, onOpenChange, defaultOpen = false, title, subtitle, leading, trailing, children, footer, size = "md", severity = "plain", animation = "zoom", transitionMs = 160, autoCloseMs, className, style, customColor, elevation, shadow, showTopAccent = true, overlayClassName, contentClassName, headerClassName, bodyClassName, footerClassName, closeable = true, onClose, closeOnOverlayClick = true, closeOnEsc = true, lockBodyScroll = true, initialFocusRef, restoreFocus = true, ariaLabel } = props;
|
|
56
74
|
const isControlled = openProp !== undefined;
|
|
57
75
|
const [openUncontrolled, setOpenUncontrolled] = React.useState(defaultOpen);
|
|
58
76
|
const open = isControlled ? !!openProp : openUncontrolled;
|
|
@@ -167,9 +185,16 @@ export function SgDialog(props) {
|
|
|
167
185
|
const overlayBase = "fixed inset-0 bg-black/60 backdrop-blur-[1px] transition-opacity";
|
|
168
186
|
const overlayState = entered ? "opacity-100" : "opacity-0";
|
|
169
187
|
const contentBase = "w-full rounded-2xl bg-background text-foreground shadow-2xl border border-border " +
|
|
170
|
-
"max-h-[85vh] flex flex-col transition duration-150 ease-out
|
|
188
|
+
"max-h-[85vh] flex flex-col transition duration-150 ease-out" +
|
|
189
|
+
(showTopAccent ? " border-t-4" : "");
|
|
190
|
+
const resolvedShadow = resolveDialogShadow(elevation, shadow);
|
|
171
191
|
const transitionStyle = { transitionDuration: `${transitionMs}ms` };
|
|
172
|
-
|
|
192
|
+
const contentStyle = {
|
|
193
|
+
...transitionStyle,
|
|
194
|
+
...(customColor !== undefined ? { backgroundColor: customColor } : {}),
|
|
195
|
+
...(resolvedShadow !== undefined ? { boxShadow: resolvedShadow } : {})
|
|
196
|
+
};
|
|
197
|
+
return createPortal(_jsxs("div", { className: cn("fixed inset-0 z-[1000]", className), style: style, role: "dialog", "aria-modal": "true", "aria-label": a11yLabel, children: [_jsx("div", { ref: overlayRef, onMouseDown: onOverlayMouseDown, className: cn(overlayBase, overlayState, overlayClassName), style: transitionStyle }), _jsx("div", { className: "fixed inset-0 flex items-center justify-center p-4", children: _jsxs("div", { ref: contentRef, className: cn(contentBase, sizeClass(size), contentStateClass(animation, entered), showTopAccent ? severityClass(severity) : false, contentClassName), style: contentStyle, children: [(title || subtitle || closeable || leading || trailing) && (_jsxs("div", { className: cn("px-5 py-4 border-b border-border flex items-start gap-3", headerClassName), children: [leading ? _jsx("div", { className: "shrink-0 pt-0.5", children: leading }) : null, _jsxs("div", { className: "min-w-0 flex-1", children: [title ? _jsx("div", { className: "text-base font-semibold leading-6", children: title }) : null, subtitle ? _jsx("div", { className: "text-sm text-muted-foreground mt-1", children: subtitle }) : null] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [trailing ? _jsx("div", { className: "shrink-0", children: trailing }) : null, closeable ? (_jsx("button", { type: "button", onClick: close, className: cn("inline-flex items-center justify-center h-9 w-9 rounded-lg", "hover:bg-muted/60 active:bg-muted", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring,var(--primary)))]"), "aria-label": "Close", children: _jsx(CloseIcon, {}) })) : null] })] })), _jsx("div", { className: cn("px-5 py-4 overflow-auto", bodyClassName), children: children }), footer ? (_jsx("div", { className: cn("px-5 py-4 border-t border-border flex items-center justify-end gap-2", footerClassName), children: footer })) : null] }) })] }), document.body);
|
|
173
198
|
}
|
|
174
199
|
function CloseIcon() {
|
|
175
200
|
return (_jsx("svg", { viewBox: "0 0 24 24", className: "size-5", "aria-hidden": "true", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
|