@rovula/ui 0.1.24 → 0.1.26
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/cjs/bundle.js +1 -1
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/esm/bundle.js +1 -1
- package/dist/esm/bundle.js.map +1 -1
- package/dist/patterns/confirm-dialog/ConfirmDialog.js +8 -3
- package/dist/patterns/menu/Menu.js +6 -1
- package/package.json +1 -1
- package/src/patterns/confirm-dialog/ConfirmDialog.tsx +15 -7
- package/src/patterns/menu/Menu.tsx +24 -18
|
@@ -6,7 +6,6 @@ import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, A
|
|
|
6
6
|
import { useControlledForm, Field } from "@/components/Form";
|
|
7
7
|
import { TextInput } from "@/components/TextInput/TextInput";
|
|
8
8
|
export const ConfirmDialog = ({ open, onOpenChange, title, description, children, confirmLabel = "Confirm", cancelLabel = "Cancel", onConfirm, onCancel, onClose, trigger, typeToConfirm, hideCancelButton = false, testId, cancelClassName, confirmClassName, }) => {
|
|
9
|
-
const formId = React.useId();
|
|
10
9
|
const requiresInput = !!typeToConfirm;
|
|
11
10
|
const validationSchema = React.useMemo(() => yup.object({
|
|
12
11
|
confirmInput: yup
|
|
@@ -33,13 +32,19 @@ export const ConfirmDialog = ({ open, onOpenChange, title, description, children
|
|
|
33
32
|
onCancel === null || onCancel === void 0 ? void 0 : onCancel();
|
|
34
33
|
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
35
34
|
};
|
|
36
|
-
|
|
35
|
+
const handleSubmit = () => {
|
|
36
|
+
methods.reset();
|
|
37
|
+
onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm();
|
|
38
|
+
};
|
|
39
|
+
return (_jsxs(AlertDialog, { open: open, onOpenChange: handleOpenChange, children: [trigger && _jsx(AlertDialogTrigger, { asChild: true, children: trigger }), _jsxs(AlertDialogContent, { "data-testid": testId, children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { "data-testid": testId && `${testId}-title`, children: title }), description && (_jsx(AlertDialogDescription, { "data-testid": testId && `${testId}-description`, children: description }))] }), children, requiresInput && (_jsxs(FormRoot, { className: "flex flex-col gap-4 w-full", onSubmit: handleSubmit, children: [_jsxs("p", { className: "typography-small1 text-text-contrast-max", children: ["Type \u201C", typeToConfirm, "\u201D to proceed."] }), _jsx(Field, { name: "confirmInput", component: TextInput, componentProps: {
|
|
37
40
|
label: "Type to confirm",
|
|
38
41
|
required: true,
|
|
39
42
|
hasClearIcon: true,
|
|
40
43
|
keepFooterSpace: true,
|
|
41
44
|
fullwidth: true,
|
|
42
45
|
testId: testId && `${testId}-type-to-confirm-input`,
|
|
43
|
-
} })] })), _jsxs(AlertDialogFooter, { children: [!hideCancelButton && (_jsx(AlertDialogCancel, { className: cancelClassName, "data-testid": testId && `${testId}-cancel-button`, onClick: handleCancel, children: cancelLabel })), _jsx(AlertDialogAction, { type: "
|
|
46
|
+
} })] })), _jsxs(AlertDialogFooter, { children: [!hideCancelButton && (_jsx(AlertDialogCancel, { className: cancelClassName, "data-testid": testId && `${testId}-cancel-button`, onClick: handleCancel, children: cancelLabel })), _jsx(AlertDialogAction, { type: "button", disabled: requiresInput && !isFormValid, onClick: requiresInput
|
|
47
|
+
? () => methods.handleSubmit(handleSubmit)()
|
|
48
|
+
: () => onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(), className: confirmClassName, "data-testid": testId && `${testId}-confirm-button`, children: confirmLabel })] })] })] }));
|
|
44
49
|
};
|
|
45
50
|
ConfirmDialog.displayName = "ConfirmDialog";
|
|
@@ -86,7 +86,12 @@ function renderMenuItems(items, selectedValues, onSelect) {
|
|
|
86
86
|
// - Full a11y / WAI-ARIA
|
|
87
87
|
// - Sub-menu support via DropdownMenuSub
|
|
88
88
|
// ---------------------------------------------------------------------------
|
|
89
|
-
export const Menu = ({ trigger, items, selectedValues = [], onSelect, header, open, onOpenChange, align = "start", side = "bottom", sideOffset = 4, contentClassName, testId, }) => (
|
|
89
|
+
export const Menu = ({ trigger, items, selectedValues = [], onSelect, header, open, onOpenChange, align = "start", side = "bottom", sideOffset = 4, contentClassName, testId, }) => (
|
|
90
|
+
// Stop click events from bubbling through React's portal event system.
|
|
91
|
+
// DropdownMenuContent renders in a DOM portal (document.body) but React
|
|
92
|
+
// synthetic events still bubble through the component tree, so clicks on
|
|
93
|
+
// menu items reach ancestor onClick handlers (e.g. a clickable card).
|
|
94
|
+
_jsx("div", { onClick: (e) => e.stopPropagation(), children: _jsxs(DropdownMenuRoot, { open: open, onOpenChange: onOpenChange, children: [trigger && (_jsx(DropdownMenuTrigger, { asChild: true, children: trigger })), _jsxs(DropdownMenuContent, { align: align, side: side, sideOffset: sideOffset, className: contentClassName, "data-testid": testId, children: [header && (_jsx("div", { className: "sticky top-0 z-10 bg-modal-surface border-b border-[var(--dropdown-menu-seperator-bg)]", children: header })), renderMenuItems(items, selectedValues, onSelect)] })] }) }));
|
|
90
95
|
Menu.displayName = "Menu";
|
|
91
96
|
// ---------------------------------------------------------------------------
|
|
92
97
|
// Re-exports — backward compat for consumers using Menu's sub-components
|
package/package.json
CHANGED
|
@@ -63,7 +63,6 @@ export const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
|
|
|
63
63
|
cancelClassName,
|
|
64
64
|
confirmClassName,
|
|
65
65
|
}) => {
|
|
66
|
-
const formId = React.useId();
|
|
67
66
|
const requiresInput = !!typeToConfirm;
|
|
68
67
|
|
|
69
68
|
const validationSchema = React.useMemo(
|
|
@@ -104,6 +103,11 @@ export const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
|
|
|
104
103
|
onClose?.();
|
|
105
104
|
};
|
|
106
105
|
|
|
106
|
+
const handleSubmit = () => {
|
|
107
|
+
methods.reset();
|
|
108
|
+
onConfirm?.();
|
|
109
|
+
};
|
|
110
|
+
|
|
107
111
|
return (
|
|
108
112
|
<AlertDialog open={open} onOpenChange={handleOpenChange}>
|
|
109
113
|
{trigger && <AlertDialogTrigger asChild>{trigger}</AlertDialogTrigger>}
|
|
@@ -113,7 +117,9 @@ export const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
|
|
|
113
117
|
{title}
|
|
114
118
|
</AlertDialogTitle>
|
|
115
119
|
{description && (
|
|
116
|
-
<AlertDialogDescription
|
|
120
|
+
<AlertDialogDescription
|
|
121
|
+
data-testid={testId && `${testId}-description`}
|
|
122
|
+
>
|
|
117
123
|
{description}
|
|
118
124
|
</AlertDialogDescription>
|
|
119
125
|
)}
|
|
@@ -123,9 +129,8 @@ export const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
|
|
|
123
129
|
|
|
124
130
|
{requiresInput && (
|
|
125
131
|
<FormRoot
|
|
126
|
-
id={formId}
|
|
127
132
|
className="flex flex-col gap-4 w-full"
|
|
128
|
-
onSubmit={
|
|
133
|
+
onSubmit={handleSubmit}
|
|
129
134
|
>
|
|
130
135
|
<p className="typography-small1 text-text-contrast-max">
|
|
131
136
|
Type “{typeToConfirm}” to proceed.
|
|
@@ -156,10 +161,13 @@ export const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
|
|
|
156
161
|
</AlertDialogCancel>
|
|
157
162
|
)}
|
|
158
163
|
<AlertDialogAction
|
|
159
|
-
type="
|
|
160
|
-
form={requiresInput ? formId : undefined}
|
|
164
|
+
type="button"
|
|
161
165
|
disabled={requiresInput && !isFormValid}
|
|
162
|
-
onClick={
|
|
166
|
+
onClick={
|
|
167
|
+
requiresInput
|
|
168
|
+
? () => methods.handleSubmit(handleSubmit)()
|
|
169
|
+
: () => onConfirm?.()
|
|
170
|
+
}
|
|
163
171
|
className={confirmClassName}
|
|
164
172
|
data-testid={testId && `${testId}-confirm-button`}
|
|
165
173
|
>
|
|
@@ -255,25 +255,31 @@ export const Menu = ({
|
|
|
255
255
|
contentClassName,
|
|
256
256
|
testId,
|
|
257
257
|
}: MenuProps) => (
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
className={contentClassName}
|
|
267
|
-
data-testid={testId}
|
|
268
|
-
>
|
|
269
|
-
{header && (
|
|
270
|
-
<div className="sticky top-0 z-10 bg-modal-surface border-b border-[var(--dropdown-menu-seperator-bg)]">
|
|
271
|
-
{header}
|
|
272
|
-
</div>
|
|
258
|
+
// Stop click events from bubbling through React's portal event system.
|
|
259
|
+
// DropdownMenuContent renders in a DOM portal (document.body) but React
|
|
260
|
+
// synthetic events still bubble through the component tree, so clicks on
|
|
261
|
+
// menu items reach ancestor onClick handlers (e.g. a clickable card).
|
|
262
|
+
<div onClick={(e) => e.stopPropagation()}>
|
|
263
|
+
<DropdownMenuRoot open={open} onOpenChange={onOpenChange}>
|
|
264
|
+
{trigger && (
|
|
265
|
+
<DropdownMenuTrigger asChild>{trigger}</DropdownMenuTrigger>
|
|
273
266
|
)}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
267
|
+
<DropdownMenuContent
|
|
268
|
+
align={align}
|
|
269
|
+
side={side}
|
|
270
|
+
sideOffset={sideOffset}
|
|
271
|
+
className={contentClassName}
|
|
272
|
+
data-testid={testId}
|
|
273
|
+
>
|
|
274
|
+
{header && (
|
|
275
|
+
<div className="sticky top-0 z-10 bg-modal-surface border-b border-[var(--dropdown-menu-seperator-bg)]">
|
|
276
|
+
{header}
|
|
277
|
+
</div>
|
|
278
|
+
)}
|
|
279
|
+
{renderMenuItems(items, selectedValues, onSelect)}
|
|
280
|
+
</DropdownMenuContent>
|
|
281
|
+
</DropdownMenuRoot>
|
|
282
|
+
</div>
|
|
277
283
|
);
|
|
278
284
|
|
|
279
285
|
Menu.displayName = "Menu";
|