@rovula/ui 0.1.14 → 0.1.16
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 +1545 -1545
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/cjs/types/components/Form/Form.d.ts +1 -1
- package/dist/cjs/types/index.d.ts +2 -0
- package/dist/cjs/types/patterns/confirm-dialog/ConfirmDialog.d.ts +25 -0
- package/dist/cjs/types/patterns/confirm-dialog/ConfirmDialog.stories.d.ts +54 -0
- package/dist/cjs/types/patterns/form-dialog/FormDialog.d.ts +40 -0
- package/dist/cjs/types/patterns/form-dialog/FormDialog.stories.d.ts +63 -0
- package/dist/components/AlertDialog/AlertDialog.js +1 -1
- package/dist/components/Dialog/Dialog.js +1 -1
- package/dist/components/Form/Form.js +15 -4
- package/dist/esm/bundle.js +1545 -1545
- package/dist/esm/bundle.js.map +1 -1
- package/dist/esm/types/components/Form/Form.d.ts +1 -1
- package/dist/esm/types/index.d.ts +2 -0
- package/dist/esm/types/patterns/confirm-dialog/ConfirmDialog.d.ts +25 -0
- package/dist/esm/types/patterns/confirm-dialog/ConfirmDialog.stories.d.ts +54 -0
- package/dist/esm/types/patterns/form-dialog/FormDialog.d.ts +40 -0
- package/dist/esm/types/patterns/form-dialog/FormDialog.stories.d.ts +63 -0
- package/dist/index.d.ts +67 -2
- package/dist/index.js +3 -0
- package/dist/patterns/confirm-dialog/ConfirmDialog.js +45 -0
- package/dist/patterns/confirm-dialog/ConfirmDialog.stories.js +103 -0
- package/dist/patterns/form-dialog/FormDialog.js +10 -0
- package/dist/patterns/form-dialog/FormDialog.stories.js +223 -0
- package/package.json +1 -1
- package/src/components/AlertDialog/AlertDialog.tsx +11 -13
- package/src/components/Dialog/Dialog.tsx +3 -9
- package/src/components/Form/Form.tsx +19 -4
- package/src/index.ts +4 -0
- package/src/patterns/confirm-dialog/ConfirmDialog.stories.tsx +193 -0
- package/src/patterns/confirm-dialog/ConfirmDialog.tsx +164 -0
- package/src/patterns/form-dialog/FormDialog.stories.tsx +437 -0
- package/src/patterns/form-dialog/FormDialog.tsx +144 -0
|
@@ -40,7 +40,7 @@ export declare const createControlledForm: <TFieldValues extends FieldValues>({
|
|
|
40
40
|
FormRoot: React.ForwardRefExoticComponent<Omit<FormProps<TFieldValues>, "methods" | "defaultValues" | "controllerRef"> & React.RefAttributes<FormController<TFieldValues>>>;
|
|
41
41
|
};
|
|
42
42
|
export declare const useControlledForm: <TFieldValues extends FieldValues>({ defaultValues, controllerRef, resolver, validationSchema, mode, reValidateMode, }: UseControlledFormOptions<TFieldValues>) => {
|
|
43
|
-
methods: UseFormReturn<TFieldValues>;
|
|
43
|
+
methods: UseFormReturn<TFieldValues, any, TFieldValues>;
|
|
44
44
|
FormRoot: React.ForwardRefExoticComponent<Omit<FormProps<TFieldValues>, "methods" | "defaultValues" | "controllerRef"> & React.RefAttributes<FormController<TFieldValues>>>;
|
|
45
45
|
};
|
|
46
46
|
type FormComponent = <TFieldValues extends FieldValues>(props: FormProps<TFieldValues> & {
|
|
@@ -44,6 +44,8 @@ export * from "./components/Tree";
|
|
|
44
44
|
export * from "./components/FocusedScrollView/FocusedScrollView";
|
|
45
45
|
export * from "./components/RadioGroup/RadioGroup";
|
|
46
46
|
export * from "./components/Form";
|
|
47
|
+
export * from "./patterns/confirm-dialog/ConfirmDialog";
|
|
48
|
+
export * from "./patterns/form-dialog/FormDialog";
|
|
47
49
|
export type { ButtonProps } from "./components/Button/Button";
|
|
48
50
|
export type { InputProps } from "./components/TextInput/TextInput";
|
|
49
51
|
export type { PasswordInputProps } from "./components/PasswordInput/PasswordInput";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type ConfirmDialogProps = {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
onOpenChange?: (open: boolean) => void;
|
|
5
|
+
title: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
confirmLabel?: string;
|
|
8
|
+
cancelLabel?: string;
|
|
9
|
+
onConfirm?: () => void;
|
|
10
|
+
onCancel?: () => void;
|
|
11
|
+
/** Fires whenever the dialog closes, regardless of how (cancel button, overlay, Escape). */
|
|
12
|
+
onClose?: () => void;
|
|
13
|
+
trigger?: React.ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* When provided, the user must type this exact text before the confirm button is enabled.
|
|
16
|
+
* e.g. typeToConfirm="confirm" or typeToConfirm="delete"
|
|
17
|
+
*/
|
|
18
|
+
typeToConfirm?: string;
|
|
19
|
+
/**
|
|
20
|
+
* When true, hides the cancel button — useful for info/error alerts that only need one action.
|
|
21
|
+
*/
|
|
22
|
+
hideCancelButton?: boolean;
|
|
23
|
+
testId?: string;
|
|
24
|
+
};
|
|
25
|
+
export declare const ConfirmDialog: React.FC<ConfirmDialogProps>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { StoryObj } from "@storybook/react";
|
|
3
|
+
import { ConfirmDialog } from "./ConfirmDialog";
|
|
4
|
+
declare const meta: {
|
|
5
|
+
title: string;
|
|
6
|
+
component: React.FC<import("./ConfirmDialog").ConfirmDialogProps>;
|
|
7
|
+
tags: string[];
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: string;
|
|
10
|
+
};
|
|
11
|
+
decorators: ((Story: import("@storybook/csf").PartialStoryFn<import("@storybook/react").ReactRenderer, {
|
|
12
|
+
open?: boolean | undefined;
|
|
13
|
+
onOpenChange?: ((open: boolean) => void) | undefined;
|
|
14
|
+
title: string;
|
|
15
|
+
description?: string | undefined;
|
|
16
|
+
confirmLabel?: string | undefined;
|
|
17
|
+
cancelLabel?: string | undefined;
|
|
18
|
+
onConfirm?: (() => void) | undefined;
|
|
19
|
+
onCancel?: (() => void) | undefined;
|
|
20
|
+
onClose?: (() => void) | undefined;
|
|
21
|
+
trigger?: React.ReactNode;
|
|
22
|
+
typeToConfirm?: string | undefined;
|
|
23
|
+
hideCancelButton?: boolean | undefined;
|
|
24
|
+
testId?: string | undefined;
|
|
25
|
+
}>) => import("react/jsx-runtime").JSX.Element)[];
|
|
26
|
+
argTypes: {
|
|
27
|
+
open: {
|
|
28
|
+
control: "boolean";
|
|
29
|
+
};
|
|
30
|
+
typeToConfirm: {
|
|
31
|
+
control: "text";
|
|
32
|
+
};
|
|
33
|
+
title: {
|
|
34
|
+
control: "text";
|
|
35
|
+
};
|
|
36
|
+
description: {
|
|
37
|
+
control: "text";
|
|
38
|
+
};
|
|
39
|
+
confirmLabel: {
|
|
40
|
+
control: "text";
|
|
41
|
+
};
|
|
42
|
+
cancelLabel: {
|
|
43
|
+
control: "text";
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export default meta;
|
|
48
|
+
type Story = StoryObj<typeof ConfirmDialog>;
|
|
49
|
+
export declare const Default: Story;
|
|
50
|
+
export declare const WithoutDescription: Story;
|
|
51
|
+
export declare const WithoutCancelButton: Story;
|
|
52
|
+
export declare const RequireConfirmText: Story;
|
|
53
|
+
export declare const FigmaDefaultOpen: Story;
|
|
54
|
+
export declare const FigmaRequirePasswordDefaultOpen: Story;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import Button from "@/components/Button/Button";
|
|
3
|
+
export type FormDialogAction = {
|
|
4
|
+
label: string;
|
|
5
|
+
onClick?: () => void;
|
|
6
|
+
variant?: React.ComponentProps<typeof Button>["variant"];
|
|
7
|
+
color?: React.ComponentProps<typeof Button>["color"];
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
isLoading?: boolean;
|
|
10
|
+
type?: "button" | "submit" | "reset";
|
|
11
|
+
};
|
|
12
|
+
export type FormDialogProps = {
|
|
13
|
+
open?: boolean;
|
|
14
|
+
onOpenChange?: (open: boolean) => void;
|
|
15
|
+
title: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
children?: React.ReactNode;
|
|
18
|
+
trigger?: React.ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* Primary action (right side of footer).
|
|
21
|
+
*/
|
|
22
|
+
confirmAction?: FormDialogAction;
|
|
23
|
+
/**
|
|
24
|
+
* Secondary cancel action (right side of footer, outline style).
|
|
25
|
+
*/
|
|
26
|
+
cancelAction?: FormDialogAction;
|
|
27
|
+
/**
|
|
28
|
+
* Optional extra action placed on the left side of the footer.
|
|
29
|
+
*/
|
|
30
|
+
extraAction?: FormDialogAction;
|
|
31
|
+
scrollable?: boolean;
|
|
32
|
+
className?: string;
|
|
33
|
+
/**
|
|
34
|
+
* When provided, the confirm button becomes type="submit" and is linked to this form id.
|
|
35
|
+
* Use together with a <Form id={formId} .../> inside children.
|
|
36
|
+
*/
|
|
37
|
+
formId?: string;
|
|
38
|
+
testId?: string;
|
|
39
|
+
};
|
|
40
|
+
export declare const FormDialog: React.FC<FormDialogProps>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { StoryObj } from "@storybook/react";
|
|
3
|
+
import { FormDialog } from "./FormDialog";
|
|
4
|
+
declare const meta: {
|
|
5
|
+
title: string;
|
|
6
|
+
component: React.FC<import("./FormDialog").FormDialogProps>;
|
|
7
|
+
tags: string[];
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: string;
|
|
10
|
+
};
|
|
11
|
+
decorators: ((Story: import("@storybook/csf").PartialStoryFn<import("@storybook/react").ReactRenderer, {
|
|
12
|
+
open?: boolean | undefined;
|
|
13
|
+
onOpenChange?: ((open: boolean) => void) | undefined;
|
|
14
|
+
title: string;
|
|
15
|
+
description?: string | undefined;
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
trigger?: React.ReactNode;
|
|
18
|
+
confirmAction?: import("./FormDialog").FormDialogAction | undefined;
|
|
19
|
+
cancelAction?: import("./FormDialog").FormDialogAction | undefined;
|
|
20
|
+
extraAction?: import("./FormDialog").FormDialogAction | undefined;
|
|
21
|
+
scrollable?: boolean | undefined;
|
|
22
|
+
className?: string | undefined;
|
|
23
|
+
formId?: string | undefined;
|
|
24
|
+
testId?: string | undefined;
|
|
25
|
+
}>) => import("react/jsx-runtime").JSX.Element)[];
|
|
26
|
+
argTypes: {
|
|
27
|
+
open: {
|
|
28
|
+
control: "boolean";
|
|
29
|
+
};
|
|
30
|
+
title: {
|
|
31
|
+
control: "text";
|
|
32
|
+
};
|
|
33
|
+
description: {
|
|
34
|
+
control: "text";
|
|
35
|
+
};
|
|
36
|
+
scrollable: {
|
|
37
|
+
control: "boolean";
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
export default meta;
|
|
42
|
+
type Story = StoryObj<typeof FormDialog>;
|
|
43
|
+
export declare const Default: Story;
|
|
44
|
+
export declare const WithExtraAction: Story;
|
|
45
|
+
export declare const WithForm: Story;
|
|
46
|
+
export declare const FigmaFormDefaultOpen: Story;
|
|
47
|
+
export declare const FigmaFormWithActionDefaultOpen: Story;
|
|
48
|
+
/**
|
|
49
|
+
* Pattern A: useControlledForm
|
|
50
|
+
*
|
|
51
|
+
* Use when you need to:
|
|
52
|
+
* - access formState (isValid, isDirty) to control the confirm button
|
|
53
|
+
* - reset the form on close
|
|
54
|
+
* - trigger validation outside the form element
|
|
55
|
+
*/
|
|
56
|
+
export declare const WithRovulaForm: Story;
|
|
57
|
+
/**
|
|
58
|
+
* Pattern B: useControlledForm + async API call + loading state
|
|
59
|
+
*
|
|
60
|
+
* Use when the confirm action calls an API.
|
|
61
|
+
* isLoading disables + shows spinner on the confirm button while the request is in flight.
|
|
62
|
+
*/
|
|
63
|
+
export declare const WithRovulaFormAndApiLoading: Story;
|
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { ToastProviderProps } from '@radix-ui/react-toast';
|
|
|
19
19
|
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
20
20
|
import { FieldValues, UseFormReturn, DefaultValues, SubmitHandler, SubmitErrorHandler, Resolver, Mode, FieldPath, RegisterOptions, FieldPathValue } from 'react-hook-form';
|
|
21
21
|
import * as yup from 'yup';
|
|
22
|
+
import Button$1 from '@/components/Button/Button';
|
|
22
23
|
import { ClassValue } from 'clsx';
|
|
23
24
|
|
|
24
25
|
type ButtonProps = {
|
|
@@ -1207,7 +1208,7 @@ declare const createControlledForm: <TFieldValues extends FieldValues>({ methods
|
|
|
1207
1208
|
FormRoot: React__default.ForwardRefExoticComponent<Omit<FormProps<TFieldValues>, "methods" | "defaultValues" | "controllerRef"> & React__default.RefAttributes<FormController<TFieldValues>>>;
|
|
1208
1209
|
};
|
|
1209
1210
|
declare const useControlledForm: <TFieldValues extends FieldValues>({ defaultValues, controllerRef, resolver, validationSchema, mode, reValidateMode, }: UseControlledFormOptions<TFieldValues>) => {
|
|
1210
|
-
methods: UseFormReturn<TFieldValues>;
|
|
1211
|
+
methods: UseFormReturn<TFieldValues, any, TFieldValues>;
|
|
1211
1212
|
FormRoot: React__default.ForwardRefExoticComponent<Omit<FormProps<TFieldValues>, "methods" | "defaultValues" | "controllerRef"> & React__default.RefAttributes<FormController<TFieldValues>>>;
|
|
1212
1213
|
};
|
|
1213
1214
|
type FormComponent = <TFieldValues extends FieldValues>(props: FormProps<TFieldValues> & {
|
|
@@ -1281,6 +1282,70 @@ declare const useOptionBridge: <TValue extends OptionValue = string, TOption ext
|
|
|
1281
1282
|
optionsByValue: Map<TValue, TOption>;
|
|
1282
1283
|
};
|
|
1283
1284
|
|
|
1285
|
+
type ConfirmDialogProps = {
|
|
1286
|
+
open?: boolean;
|
|
1287
|
+
onOpenChange?: (open: boolean) => void;
|
|
1288
|
+
title: string;
|
|
1289
|
+
description?: string;
|
|
1290
|
+
confirmLabel?: string;
|
|
1291
|
+
cancelLabel?: string;
|
|
1292
|
+
onConfirm?: () => void;
|
|
1293
|
+
onCancel?: () => void;
|
|
1294
|
+
/** Fires whenever the dialog closes, regardless of how (cancel button, overlay, Escape). */
|
|
1295
|
+
onClose?: () => void;
|
|
1296
|
+
trigger?: React.ReactNode;
|
|
1297
|
+
/**
|
|
1298
|
+
* When provided, the user must type this exact text before the confirm button is enabled.
|
|
1299
|
+
* e.g. typeToConfirm="confirm" or typeToConfirm="delete"
|
|
1300
|
+
*/
|
|
1301
|
+
typeToConfirm?: string;
|
|
1302
|
+
/**
|
|
1303
|
+
* When true, hides the cancel button — useful for info/error alerts that only need one action.
|
|
1304
|
+
*/
|
|
1305
|
+
hideCancelButton?: boolean;
|
|
1306
|
+
testId?: string;
|
|
1307
|
+
};
|
|
1308
|
+
declare const ConfirmDialog: React.FC<ConfirmDialogProps>;
|
|
1309
|
+
|
|
1310
|
+
type FormDialogAction = {
|
|
1311
|
+
label: string;
|
|
1312
|
+
onClick?: () => void;
|
|
1313
|
+
variant?: React.ComponentProps<typeof Button$1>["variant"];
|
|
1314
|
+
color?: React.ComponentProps<typeof Button$1>["color"];
|
|
1315
|
+
disabled?: boolean;
|
|
1316
|
+
isLoading?: boolean;
|
|
1317
|
+
type?: "button" | "submit" | "reset";
|
|
1318
|
+
};
|
|
1319
|
+
type FormDialogProps = {
|
|
1320
|
+
open?: boolean;
|
|
1321
|
+
onOpenChange?: (open: boolean) => void;
|
|
1322
|
+
title: string;
|
|
1323
|
+
description?: string;
|
|
1324
|
+
children?: React.ReactNode;
|
|
1325
|
+
trigger?: React.ReactNode;
|
|
1326
|
+
/**
|
|
1327
|
+
* Primary action (right side of footer).
|
|
1328
|
+
*/
|
|
1329
|
+
confirmAction?: FormDialogAction;
|
|
1330
|
+
/**
|
|
1331
|
+
* Secondary cancel action (right side of footer, outline style).
|
|
1332
|
+
*/
|
|
1333
|
+
cancelAction?: FormDialogAction;
|
|
1334
|
+
/**
|
|
1335
|
+
* Optional extra action placed on the left side of the footer.
|
|
1336
|
+
*/
|
|
1337
|
+
extraAction?: FormDialogAction;
|
|
1338
|
+
scrollable?: boolean;
|
|
1339
|
+
className?: string;
|
|
1340
|
+
/**
|
|
1341
|
+
* When provided, the confirm button becomes type="submit" and is linked to this form id.
|
|
1342
|
+
* Use together with a <Form id={formId} .../> inside children.
|
|
1343
|
+
*/
|
|
1344
|
+
formId?: string;
|
|
1345
|
+
testId?: string;
|
|
1346
|
+
};
|
|
1347
|
+
declare const FormDialog: React.FC<FormDialogProps>;
|
|
1348
|
+
|
|
1284
1349
|
declare const resloveTimestamp: (timestamp: number) => number;
|
|
1285
1350
|
declare const getStartDateOfDay: (date: Date) => Date;
|
|
1286
1351
|
declare const getEndDateOfDay: (date: Date) => Date;
|
|
@@ -1720,4 +1785,4 @@ declare const srgbToHex: (color: string) => string;
|
|
|
1720
1785
|
*/
|
|
1721
1786
|
declare function getLucideIconNames(): Promise<string[]>;
|
|
1722
1787
|
|
|
1723
|
-
export { ActionButton, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Button, type ButtonProps, Calendar, Checkbox, Collapsible, type ControlledFormFactoryOptions, type CustomSliderProps, DataTable, type DataTableProps, DatePicker, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Dropdown, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type DropdownProps, Field, FieldMessage, type FieldMessageProps, type FieldProps, FocusedScrollView, Footer, type FooterProps, type FooterVariant, Form, type FormController, type FormProps, Icon, Input, InputFilter, type InputFilterProps, type InputProps, Label, Loading, type MaskRule, MaskedTextInput, type MaskedTextInputProps, Menu, MenuItem, type MenuItemType, MenuLabel, type MenuOption, type MenuProps, MenuSeparator, Navbar, type NavbarProps, type NavbarVariant, NumberInput, type NumberInputProps, type OptionLike, type Options$1 as Options, OtpInput, OtpInputGroup, type OtpInputGroupProps, type OtpInputProps, PasswordInput, type PasswordInputProps, Popover, PopoverContent, PopoverTrigger, ProgressBar, RadioGroup, RadioGroupItem, Search, type SearchProps, Slider, type SliderProps, Switch, THEME_COLOR_KEYS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, Text, TextArea, type TextAreaProps, TextInput, type ThemeColorKey, Toast$1 as Toast, ToastAction, type ToastActionElement, ToastClose, ToastDescription, type ToastProps, ToastProvider, ToastTitle, ToastViewport, Toaster, Tooltip, TooltipArrow, TooltipContent, TooltipProvider, TooltipSimple, TooltipTrigger, Tree, type TreeData, TreeItem, type TreeItemProps, type TreeProps, type UseControlledFormOptions, type UseOptionBridgeOptions, ValidationHintList, type ValidationHintListProps, type ValidationHintMode, type ValidationHintRule, type ValidationHintState, cn, createControlledForm, createYupResolver, getEndDateOfDay, getLucideIconNames, getStartDateOfDay, getStartEndTimestampOfDay, getThemeColor, getThemeColors, getTimestampUTC, reducer, resloveTimestamp, srgbToHex, toast, useControlledForm, useOptionBridge, usePrevious, useToast };
|
|
1788
|
+
export { ActionButton, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Button, type ButtonProps, Calendar, Checkbox, Collapsible, ConfirmDialog, type ConfirmDialogProps, type ControlledFormFactoryOptions, type CustomSliderProps, DataTable, type DataTableProps, DatePicker, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Dropdown, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type DropdownProps, Field, FieldMessage, type FieldMessageProps, type FieldProps, FocusedScrollView, Footer, type FooterProps, type FooterVariant, Form, type FormController, FormDialog, type FormDialogAction, type FormDialogProps, type FormProps, Icon, Input, InputFilter, type InputFilterProps, type InputProps, Label, Loading, type MaskRule, MaskedTextInput, type MaskedTextInputProps, Menu, MenuItem, type MenuItemType, MenuLabel, type MenuOption, type MenuProps, MenuSeparator, Navbar, type NavbarProps, type NavbarVariant, NumberInput, type NumberInputProps, type OptionLike, type Options$1 as Options, OtpInput, OtpInputGroup, type OtpInputGroupProps, type OtpInputProps, PasswordInput, type PasswordInputProps, Popover, PopoverContent, PopoverTrigger, ProgressBar, RadioGroup, RadioGroupItem, Search, type SearchProps, Slider, type SliderProps, Switch, THEME_COLOR_KEYS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, Text, TextArea, type TextAreaProps, TextInput, type ThemeColorKey, Toast$1 as Toast, ToastAction, type ToastActionElement, ToastClose, ToastDescription, type ToastProps, ToastProvider, ToastTitle, ToastViewport, Toaster, Tooltip, TooltipArrow, TooltipContent, TooltipProvider, TooltipSimple, TooltipTrigger, Tree, type TreeData, TreeItem, type TreeItemProps, type TreeProps, type UseControlledFormOptions, type UseOptionBridgeOptions, ValidationHintList, type ValidationHintListProps, type ValidationHintMode, type ValidationHintRule, type ValidationHintState, cn, createControlledForm, createYupResolver, getEndDateOfDay, getLucideIconNames, getStartDateOfDay, getStartEndTimestampOfDay, getThemeColor, getThemeColors, getTimestampUTC, reducer, resloveTimestamp, srgbToHex, toast, useControlledForm, useOptionBridge, usePrevious, useToast };
|
package/dist/index.js
CHANGED
|
@@ -46,6 +46,9 @@ export * from "./components/Tree";
|
|
|
46
46
|
export * from "./components/FocusedScrollView/FocusedScrollView";
|
|
47
47
|
export * from "./components/RadioGroup/RadioGroup";
|
|
48
48
|
export * from "./components/Form";
|
|
49
|
+
// Patterns
|
|
50
|
+
export * from "./patterns/confirm-dialog/ConfirmDialog";
|
|
51
|
+
export * from "./patterns/form-dialog/FormDialog";
|
|
49
52
|
// UTILS
|
|
50
53
|
export { resloveTimestamp, getStartDateOfDay, getEndDateOfDay, getStartEndTimestampOfDay, getTimestampUTC, } from "./utils/datetime";
|
|
51
54
|
// Hooks
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as yup from "yup";
|
|
5
|
+
import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogAction, AlertDialogCancel, AlertDialogTrigger, } from "@/components/AlertDialog/AlertDialog";
|
|
6
|
+
import { useControlledForm, Field } from "@/components/Form";
|
|
7
|
+
import { TextInput } from "@/components/TextInput/TextInput";
|
|
8
|
+
export const ConfirmDialog = ({ open, onOpenChange, title, description, confirmLabel = "Confirm", cancelLabel = "Cancel", onConfirm, onCancel, onClose, trigger, typeToConfirm, hideCancelButton = false, testId, }) => {
|
|
9
|
+
const formId = React.useId();
|
|
10
|
+
const requiresInput = !!typeToConfirm;
|
|
11
|
+
const validationSchema = React.useMemo(() => yup.object({
|
|
12
|
+
confirmInput: yup
|
|
13
|
+
.string()
|
|
14
|
+
.required("This field is required.")
|
|
15
|
+
.test("type-to-confirm", `Please type '${typeToConfirm}' to proceed`, (value) => value === typeToConfirm),
|
|
16
|
+
}), [typeToConfirm]);
|
|
17
|
+
const { methods, FormRoot } = useControlledForm({
|
|
18
|
+
defaultValues: { confirmInput: "" },
|
|
19
|
+
validationSchema,
|
|
20
|
+
mode: "onTouched",
|
|
21
|
+
reValidateMode: "onChange",
|
|
22
|
+
});
|
|
23
|
+
const isFormValid = methods.formState.isValid;
|
|
24
|
+
const handleOpenChange = (nextOpen) => {
|
|
25
|
+
if (!nextOpen) {
|
|
26
|
+
methods.reset();
|
|
27
|
+
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
28
|
+
}
|
|
29
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen);
|
|
30
|
+
};
|
|
31
|
+
const handleCancel = () => {
|
|
32
|
+
methods.reset();
|
|
33
|
+
onCancel === null || onCancel === void 0 ? void 0 : onCancel();
|
|
34
|
+
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
35
|
+
};
|
|
36
|
+
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 }))] }), requiresInput && (_jsxs(FormRoot, { id: formId, className: "flex flex-col gap-4 w-full", onSubmit: () => onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(), 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
|
+
label: "Type to confirm",
|
|
38
|
+
required: true,
|
|
39
|
+
hasClearIcon: true,
|
|
40
|
+
keepFooterSpace: true,
|
|
41
|
+
fullwidth: true,
|
|
42
|
+
testId: testId && `${testId}-type-to-confirm-input`,
|
|
43
|
+
} })] })), _jsxs(AlertDialogFooter, { children: [!hideCancelButton && (_jsx(AlertDialogCancel, { "data-testid": testId && `${testId}-cancel-button`, onClick: handleCancel, children: cancelLabel })), _jsx(AlertDialogAction, { type: "submit", form: requiresInput ? formId : undefined, disabled: requiresInput && !isFormValid, onClick: requiresInput ? undefined : () => onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(), "data-testid": testId && `${testId}-confirm-button`, children: confirmLabel })] })] })] }));
|
|
44
|
+
};
|
|
45
|
+
ConfirmDialog.displayName = "ConfirmDialog";
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useArgs } from "@storybook/preview-api";
|
|
3
|
+
import { ConfirmDialog } from "./ConfirmDialog";
|
|
4
|
+
import Button from "@/components/Button/Button";
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Patterns/ConfirmDialog",
|
|
7
|
+
component: ConfirmDialog,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: "fullscreen",
|
|
11
|
+
},
|
|
12
|
+
decorators: [
|
|
13
|
+
(Story) => (_jsx("div", { className: "p-5 flex w-full", children: _jsx(Story, {}) })),
|
|
14
|
+
],
|
|
15
|
+
argTypes: {
|
|
16
|
+
open: { control: "boolean" },
|
|
17
|
+
typeToConfirm: { control: "text" },
|
|
18
|
+
title: { control: "text" },
|
|
19
|
+
description: { control: "text" },
|
|
20
|
+
confirmLabel: { control: "text" },
|
|
21
|
+
cancelLabel: { control: "text" },
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
export default meta;
|
|
25
|
+
export const Default = {
|
|
26
|
+
args: {
|
|
27
|
+
open: false,
|
|
28
|
+
title: "Are you sure?",
|
|
29
|
+
description: "This action cannot be undone.",
|
|
30
|
+
confirmLabel: "Confirm",
|
|
31
|
+
cancelLabel: "Cancel",
|
|
32
|
+
},
|
|
33
|
+
render: (args) => {
|
|
34
|
+
const [{ open }, updateArgs] = useArgs();
|
|
35
|
+
return (_jsx(ConfirmDialog, Object.assign({}, args, { open: open, onOpenChange: (next) => updateArgs({ open: next }), onConfirm: () => updateArgs({ open: false }), onCancel: () => updateArgs({ open: false }), trigger: _jsx(Button, { fullwidth: false, onClick: () => updateArgs({ open: true }), children: "Open" }) })));
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
export const WithoutDescription = {
|
|
39
|
+
args: {
|
|
40
|
+
open: false,
|
|
41
|
+
title: "Delete item?",
|
|
42
|
+
confirmLabel: "Delete",
|
|
43
|
+
cancelLabel: "Cancel",
|
|
44
|
+
},
|
|
45
|
+
render: (args) => {
|
|
46
|
+
const [{ open }, updateArgs] = useArgs();
|
|
47
|
+
return (_jsx(ConfirmDialog, Object.assign({}, args, { open: open, onOpenChange: (next) => updateArgs({ open: next }), onConfirm: () => updateArgs({ open: false }), onCancel: () => updateArgs({ open: false }), trigger: _jsx(Button, { fullwidth: false, color: "error", onClick: () => updateArgs({ open: true }), children: "Delete" }) })));
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
export const WithoutCancelButton = {
|
|
51
|
+
args: {
|
|
52
|
+
open: false,
|
|
53
|
+
title: "Are you sure?",
|
|
54
|
+
description: "This action cannot be undone.",
|
|
55
|
+
confirmLabel: "Confirm",
|
|
56
|
+
hideCancelButton: true,
|
|
57
|
+
},
|
|
58
|
+
render: (args) => {
|
|
59
|
+
const [{ open }, updateArgs] = useArgs();
|
|
60
|
+
return (_jsx(ConfirmDialog, Object.assign({}, args, { open: open, onOpenChange: (next) => updateArgs({ open: next }), onConfirm: () => updateArgs({ open: false }), onCancel: () => updateArgs({ open: false }), trigger: _jsx(Button, { fullwidth: false, color: "error", onClick: () => updateArgs({ open: true }), children: "Confirm" }) })));
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
export const RequireConfirmText = {
|
|
64
|
+
args: {
|
|
65
|
+
open: false,
|
|
66
|
+
title: "Title",
|
|
67
|
+
description: "Subtitle description",
|
|
68
|
+
confirmLabel: "Confirm",
|
|
69
|
+
cancelLabel: "Cancel",
|
|
70
|
+
typeToConfirm: "confirm",
|
|
71
|
+
},
|
|
72
|
+
render: (args) => {
|
|
73
|
+
const [{ open }, updateArgs] = useArgs();
|
|
74
|
+
return (_jsx(ConfirmDialog, Object.assign({}, args, { open: open, onOpenChange: (next) => updateArgs({ open: next }), onConfirm: () => updateArgs({ open: false }), onCancel: () => updateArgs({ open: false }), trigger: _jsx(Button, { fullwidth: false, onClick: () => updateArgs({ open: true }), children: "Open (require confirm)" }) })));
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
export const FigmaDefaultOpen = {
|
|
78
|
+
args: {
|
|
79
|
+
open: false,
|
|
80
|
+
title: "Title",
|
|
81
|
+
description: "Subtitle description",
|
|
82
|
+
confirmLabel: "Confirm",
|
|
83
|
+
cancelLabel: "Cancel",
|
|
84
|
+
},
|
|
85
|
+
render: (args) => {
|
|
86
|
+
const [{ open }, updateArgs] = useArgs();
|
|
87
|
+
return (_jsx(ConfirmDialog, Object.assign({}, args, { open: open, onOpenChange: (next) => updateArgs({ open: next }), onConfirm: () => updateArgs({ open: false }), onCancel: () => updateArgs({ open: false }) })));
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
export const FigmaRequirePasswordDefaultOpen = {
|
|
91
|
+
args: {
|
|
92
|
+
open: false,
|
|
93
|
+
title: "Title",
|
|
94
|
+
description: "Subtitle description",
|
|
95
|
+
confirmLabel: "Confirm",
|
|
96
|
+
cancelLabel: "Cancel",
|
|
97
|
+
typeToConfirm: "confirm",
|
|
98
|
+
},
|
|
99
|
+
render: (args) => {
|
|
100
|
+
const [{ open }, updateArgs] = useArgs();
|
|
101
|
+
return (_jsx(ConfirmDialog, Object.assign({}, args, { open: open, onOpenChange: (next) => updateArgs({ open: next }), onConfirm: () => updateArgs({ open: false }), onCancel: () => updateArgs({ open: false }) })));
|
|
102
|
+
},
|
|
103
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogBody, DialogFooter, DialogTrigger, } from "@/components/Dialog/Dialog";
|
|
4
|
+
import Button from "@/components/Button/Button";
|
|
5
|
+
export const FormDialog = ({ open, onOpenChange, title, description, children, trigger, confirmAction, cancelAction, extraAction, scrollable = false, className, formId, testId, }) => {
|
|
6
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
7
|
+
const hasFooter = confirmAction || cancelAction || extraAction;
|
|
8
|
+
return (_jsxs(Dialog, { open: open, onOpenChange: onOpenChange, children: [trigger && _jsx(DialogTrigger, { asChild: true, children: trigger }), _jsxs(DialogContent, { className: className, "data-testid": testId, children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { "data-testid": testId && `${testId}-title`, children: title }), description && (_jsx(DialogDescription, { "data-testid": testId && `${testId}-description`, children: description }))] }), children && (_jsx(DialogBody, { scrollable: scrollable, children: children })), hasFooter && (_jsxs(DialogFooter, { className: extraAction ? "justify-between" : undefined, children: [extraAction && (_jsx(Button, { type: (_a = extraAction.type) !== null && _a !== void 0 ? _a : "button", variant: (_b = extraAction.variant) !== null && _b !== void 0 ? _b : "outline", color: (_c = extraAction.color) !== null && _c !== void 0 ? _c : "secondary", fullwidth: false, disabled: extraAction.disabled, isLoading: extraAction.isLoading, onClick: extraAction.onClick, "data-testid": testId && `${testId}-extra-button`, children: extraAction.label })), _jsxs("div", { className: "flex items-center gap-4", children: [cancelAction && (_jsx(Button, { type: (_d = cancelAction.type) !== null && _d !== void 0 ? _d : "button", variant: (_e = cancelAction.variant) !== null && _e !== void 0 ? _e : "outline", color: (_f = cancelAction.color) !== null && _f !== void 0 ? _f : "primary", fullwidth: false, disabled: cancelAction.disabled, isLoading: cancelAction.isLoading, onClick: cancelAction.onClick, "data-testid": testId && `${testId}-cancel-button`, children: cancelAction.label })), confirmAction && (_jsx(Button, { type: formId ? "submit" : (_g = confirmAction.type) !== null && _g !== void 0 ? _g : "button", form: formId, variant: (_h = confirmAction.variant) !== null && _h !== void 0 ? _h : "solid", color: (_j = confirmAction.color) !== null && _j !== void 0 ? _j : "primary", fullwidth: false, disabled: confirmAction.disabled, isLoading: confirmAction.isLoading, onClick: confirmAction.onClick, "data-testid": testId && `${testId}-confirm-button`, children: confirmAction.label }))] })] }))] })] }));
|
|
9
|
+
};
|
|
10
|
+
FormDialog.displayName = "FormDialog";
|