@rovula/ui 0.1.13 → 0.1.15

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.
Files changed (41) hide show
  1. package/dist/cjs/bundle.css +7 -36
  2. package/dist/cjs/bundle.js +2 -2
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/AlertDialog/AlertDialog.stories.d.ts +3 -0
  5. package/dist/cjs/types/components/Dialog/Dialog.stories.d.ts +4 -1
  6. package/dist/cjs/types/components/Form/Form.d.ts +1 -1
  7. package/dist/cjs/types/patterns/confirm-dialog/ConfirmDialog.d.ts +24 -0
  8. package/dist/cjs/types/patterns/confirm-dialog/ConfirmDialog.stories.d.ts +53 -0
  9. package/dist/cjs/types/patterns/form-dialog/FormDialog.d.ts +39 -0
  10. package/dist/cjs/types/patterns/form-dialog/FormDialog.stories.d.ts +62 -0
  11. package/dist/components/AlertDialog/AlertDialog.js +5 -5
  12. package/dist/components/AlertDialog/AlertDialog.stories.js +22 -0
  13. package/dist/components/Dialog/Dialog.js +6 -6
  14. package/dist/components/Dialog/Dialog.stories.js +6 -34
  15. package/dist/components/Form/Form.js +15 -4
  16. package/dist/esm/bundle.css +7 -36
  17. package/dist/esm/bundle.js +1 -1
  18. package/dist/esm/bundle.js.map +1 -1
  19. package/dist/esm/types/components/AlertDialog/AlertDialog.stories.d.ts +3 -0
  20. package/dist/esm/types/components/Dialog/Dialog.stories.d.ts +4 -1
  21. package/dist/esm/types/components/Form/Form.d.ts +1 -1
  22. package/dist/esm/types/patterns/confirm-dialog/ConfirmDialog.d.ts +24 -0
  23. package/dist/esm/types/patterns/confirm-dialog/ConfirmDialog.stories.d.ts +53 -0
  24. package/dist/esm/types/patterns/form-dialog/FormDialog.d.ts +39 -0
  25. package/dist/esm/types/patterns/form-dialog/FormDialog.stories.d.ts +62 -0
  26. package/dist/index.d.ts +1 -1
  27. package/dist/patterns/confirm-dialog/ConfirmDialog.js +44 -0
  28. package/dist/patterns/confirm-dialog/ConfirmDialog.stories.js +103 -0
  29. package/dist/patterns/form-dialog/FormDialog.js +10 -0
  30. package/dist/patterns/form-dialog/FormDialog.stories.js +223 -0
  31. package/dist/src/theme/global.css +9 -40
  32. package/package.json +1 -1
  33. package/src/components/AlertDialog/AlertDialog.stories.tsx +69 -2
  34. package/src/components/AlertDialog/AlertDialog.tsx +13 -15
  35. package/src/components/Dialog/Dialog.stories.tsx +62 -99
  36. package/src/components/Dialog/Dialog.tsx +6 -12
  37. package/src/components/Form/Form.tsx +19 -4
  38. package/src/patterns/confirm-dialog/ConfirmDialog.stories.tsx +193 -0
  39. package/src/patterns/confirm-dialog/ConfirmDialog.tsx +153 -0
  40. package/src/patterns/form-dialog/FormDialog.stories.tsx +437 -0
  41. package/src/patterns/form-dialog/FormDialog.tsx +137 -0
@@ -25,3 +25,6 @@ export declare const CustomStyle: {
25
25
  export declare const FigmaFail: {
26
26
  render: () => import("react/jsx-runtime").JSX.Element;
27
27
  };
28
+ export declare const FigmaConfirmRequirePassword: {
29
+ render: () => import("react/jsx-runtime").JSX.Element;
30
+ };
@@ -23,6 +23,9 @@ export declare const Demo: {
23
23
  args: {};
24
24
  render: (args: {}) => import("react/jsx-runtime").JSX.Element;
25
25
  };
26
- export declare const FigmaChangePassword: {
26
+ export declare const FigmaFunctionForm: {
27
+ render: () => import("react/jsx-runtime").JSX.Element;
28
+ };
29
+ export declare const FigmaFunctionFormWithAction: {
27
30
  render: () => import("react/jsx-runtime").JSX.Element;
28
31
  };
@@ -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> & {
@@ -0,0 +1,24 @@
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
+ };
24
+ export declare const ConfirmDialog: React.FC<ConfirmDialogProps>;
@@ -0,0 +1,53 @@
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
+ }>) => import("react/jsx-runtime").JSX.Element)[];
25
+ argTypes: {
26
+ open: {
27
+ control: "boolean";
28
+ };
29
+ typeToConfirm: {
30
+ control: "text";
31
+ };
32
+ title: {
33
+ control: "text";
34
+ };
35
+ description: {
36
+ control: "text";
37
+ };
38
+ confirmLabel: {
39
+ control: "text";
40
+ };
41
+ cancelLabel: {
42
+ control: "text";
43
+ };
44
+ };
45
+ };
46
+ export default meta;
47
+ type Story = StoryObj<typeof ConfirmDialog>;
48
+ export declare const Default: Story;
49
+ export declare const WithoutDescription: Story;
50
+ export declare const WithoutCancelButton: Story;
51
+ export declare const RequireConfirmText: Story;
52
+ export declare const FigmaDefaultOpen: Story;
53
+ export declare const FigmaRequirePasswordDefaultOpen: Story;
@@ -0,0 +1,39 @@
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
+ };
39
+ export declare const FormDialog: React.FC<FormDialogProps>;
@@ -0,0 +1,62 @@
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
+ }>) => import("react/jsx-runtime").JSX.Element)[];
25
+ argTypes: {
26
+ open: {
27
+ control: "boolean";
28
+ };
29
+ title: {
30
+ control: "text";
31
+ };
32
+ description: {
33
+ control: "text";
34
+ };
35
+ scrollable: {
36
+ control: "boolean";
37
+ };
38
+ };
39
+ };
40
+ export default meta;
41
+ type Story = StoryObj<typeof FormDialog>;
42
+ export declare const Default: Story;
43
+ export declare const WithExtraAction: Story;
44
+ export declare const WithForm: Story;
45
+ export declare const FigmaFormDefaultOpen: Story;
46
+ export declare const FigmaFormWithActionDefaultOpen: Story;
47
+ /**
48
+ * Pattern A: useControlledForm
49
+ *
50
+ * Use when you need to:
51
+ * - access formState (isValid, isDirty) to control the confirm button
52
+ * - reset the form on close
53
+ * - trigger validation outside the form element
54
+ */
55
+ export declare const WithRovulaForm: Story;
56
+ /**
57
+ * Pattern B: useControlledForm + async API call + loading state
58
+ *
59
+ * Use when the confirm action calls an API.
60
+ * isLoading disables + shows spinner on the confirm button while the request is in flight.
61
+ */
62
+ export declare const WithRovulaFormAndApiLoading: Story;
@@ -25,7 +25,7 @@ const AlertDialogOverlay = React.forwardRef((_a, ref) => {
25
25
  AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
26
26
  const AlertDialogContent = React.forwardRef((_a, ref) => {
27
27
  var { className } = _a, props = __rest(_a, ["className"]);
28
- return (_jsxs(AlertDialogPortal, { children: [_jsx(AlertDialogOverlay, {}), _jsx(AlertDialogPrimitive.Content, Object.assign({ ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-[calc(100%-32px)] max-w-[460px] translate-x-[-50%] translate-y-[-50%] gap-8 rounded-md bg-modal-surface px-6 py-8 text-text-contrast-max shadow-[0px_12px_24px_-4px_rgba(0,0,0,0.12)] duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]", className) }, props))] }));
28
+ return (_jsxs(AlertDialogPortal, { children: [_jsx(AlertDialogOverlay, {}), _jsx(AlertDialogPrimitive.Content, Object.assign({ ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-[calc(100%-32px)] max-w-[460px] translate-x-[-50%] translate-y-[-50%] gap-6 rounded-md bg-modal-surface px-6 py-8 text-text-contrast-max shadow-[0px_12px_24px_-4px_rgba(0,0,0,0.12)] duration-200 focus:outline-none focus-visible:outline-none outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]", className) }, props))] }));
29
29
  });
30
30
  AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
31
31
  const AlertDialogHeader = (_a) => {
@@ -35,7 +35,7 @@ const AlertDialogHeader = (_a) => {
35
35
  AlertDialogHeader.displayName = "AlertDialogHeader";
36
36
  const AlertDialogFooter = (_a) => {
37
37
  var { className } = _a, props = __rest(_a, ["className"]);
38
- return (_jsx("div", Object.assign({ className: cn("flex flex-col-reverse items-center justify-center gap-3 sm:flex-row sm:gap-4", className) }, props)));
38
+ return (_jsx("div", Object.assign({ className: cn("flex flex-row items-center justify-center gap-4", className) }, props)));
39
39
  };
40
40
  AlertDialogFooter.displayName = "AlertDialogFooter";
41
41
  const AlertDialogTitle = React.forwardRef((_a, ref) => {
@@ -45,18 +45,18 @@ const AlertDialogTitle = React.forwardRef((_a, ref) => {
45
45
  AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
46
46
  const AlertDialogDescription = React.forwardRef((_a, ref) => {
47
47
  var { className } = _a, props = __rest(_a, ["className"]);
48
- return (_jsx(AlertDialogPrimitive.Description, Object.assign({ ref: ref, className: cn("typography-small1 text-text-contrast-max", className) }, props)));
48
+ return (_jsx(AlertDialogPrimitive.Description, Object.assign({ ref: ref, className: cn("typography-body3 text-text-contrast-max", className) }, props)));
49
49
  });
50
50
  AlertDialogDescription.displayName =
51
51
  AlertDialogPrimitive.Description.displayName;
52
52
  const AlertDialogAction = React.forwardRef((_a, ref) => {
53
53
  var { className } = _a, props = __rest(_a, ["className"]);
54
- return (_jsx(AlertDialogPrimitive.Action, Object.assign({ ref: ref, className: cn(buttonVariants({ fullwidth: false }), className) }, props)));
54
+ return (_jsx(AlertDialogPrimitive.Action, Object.assign({ ref: ref, className: cn(buttonVariants({ fullwidth: false }), "w-[100px] justify-center", className) }, props)));
55
55
  });
56
56
  AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
57
57
  const AlertDialogCancel = React.forwardRef((_a, ref) => {
58
58
  var { className } = _a, props = __rest(_a, ["className"]);
59
- return (_jsx(AlertDialogPrimitive.Cancel, Object.assign({ ref: ref, className: cn(buttonVariants({ fullwidth: false, variant: "outline" }), "mt-2 sm:mt-0", className) }, props)));
59
+ return (_jsx(AlertDialogPrimitive.Cancel, Object.assign({ ref: ref, className: cn(buttonVariants({ fullwidth: false, variant: "outline" }), "w-[100px] justify-center", className) }, props)));
60
60
  });
61
61
  AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
62
62
  export { AlertDialog, AlertDialogPortal, AlertDialogOverlay, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel, };
@@ -1,5 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
2
3
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "./AlertDialog";
4
+ import { TextInput } from "../TextInput/TextInput";
3
5
  // More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
4
6
  const meta = {
5
7
  title: "Components/AlertDialog",
@@ -41,3 +43,23 @@ export const CustomStyle = {
41
43
  export const FigmaFail = {
42
44
  render: () => (_jsx("div", { className: "flex w-full", children: _jsx(AlertDialog, { defaultOpen: true, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Infomation update failed" }), _jsx(AlertDialogDescription, { children: "Please login again and complete your profile to activate your account." })] }), _jsx(AlertDialogFooter, { children: _jsx(AlertDialogAction, { className: "w-[140px] justify-center", children: "Try again" }) })] }) }) })),
43
45
  };
46
+ export const FigmaConfirmRequirePassword = {
47
+ render: () => {
48
+ const [value, setValue] = useState("");
49
+ const [submitted, setSubmitted] = useState(false);
50
+ const isRequired = submitted && value === "";
51
+ const isWrongWord = submitted && value !== "" && value !== "confirm";
52
+ const isValid = value === "confirm";
53
+ return (_jsx("div", { className: "flex w-full", children: _jsx(AlertDialog, { defaultOpen: true, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Title" }), _jsx(AlertDialogDescription, { children: "Subtitle description" })] }), _jsxs("div", { className: "flex flex-col gap-4 w-full", children: [_jsx("p", { className: "typography-small1 text-text-contrast-max", children: "Type \u201Cconfirm\u201D to proceed." }), _jsx(TextInput, { label: "Type to confirm", required: true, value: value, onChange: (e) => {
54
+ setValue(e.target.value);
55
+ setSubmitted(false);
56
+ }, errorMessage: isRequired
57
+ ? "This field is required."
58
+ : isWrongWord
59
+ ? "Please type 'confirm' to proceed"
60
+ : undefined, hasClearIcon: true, keepFooterSpace: true, fullwidth: true })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { onClick: () => {
61
+ setValue("");
62
+ setSubmitted(false);
63
+ }, children: "Cancel" }), _jsx(AlertDialogAction, { disabled: !isValid, onClick: () => setSubmitted(true), children: "Confirm" })] })] }) }) }));
64
+ },
65
+ };
@@ -26,32 +26,32 @@ const DialogOverlay = React.forwardRef((_a, ref) => {
26
26
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
27
27
  const DialogContent = React.forwardRef((_a, ref) => {
28
28
  var { className, children, showCloseButton = false, closeButtonClassName } = _a, props = __rest(_a, ["className", "children", "showCloseButton", "closeButtonClassName"]);
29
- return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, Object.assign({ ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 flex w-[calc(100%-32px)] max-w-[650px] translate-x-[-50%] translate-y-[-50%] flex-col rounded-md bg-modal-surface p-8 text-text-g-contrast-medium shadow-[0px_12px_24px_-4px_rgba(0,0,0,0.12)] duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]", className) }, props, { children: [children, showCloseButton && (_jsxs(DialogPrimitive.Close, { className: cn("absolute right-8 top-8 rounded-sm opacity-70 ring-offset-bg-bg1 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-input-active-stroke focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-primary data-[state=open]:text-state-primary-text-solid", closeButtonClassName), children: [_jsx(XMarkIcon, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: "Close" })] }))] }))] }));
29
+ return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, Object.assign({ ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 flex w-[calc(100%-32px)] max-w-[650px] translate-x-[-50%] translate-y-[-50%] flex-col gap-6 rounded-md bg-modal-surface p-8 text-text-g-contrast-medium shadow-[0px_12px_24px_-4px_rgba(0,0,0,0.12)] duration-200 focus:outline-none focus-visible:outline-none outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]", className) }, props, { children: [children, showCloseButton && (_jsxs(DialogPrimitive.Close, { className: cn("absolute right-8 top-8 rounded-sm opacity-70 ring-offset-bg-bg1 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-input-active-stroke focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-primary data-[state=open]:text-state-primary-text-solid", closeButtonClassName), children: [_jsx(XMarkIcon, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: "Close" })] }))] }))] }));
30
30
  });
31
31
  DialogContent.displayName = DialogPrimitive.Content.displayName;
32
32
  const DialogHeader = (_a) => {
33
33
  var { className } = _a, props = __rest(_a, ["className"]);
34
- return (_jsx("div", Object.assign({ className: cn("flex flex-col gap-2 text-left", className) }, props)));
34
+ return (_jsx("div", Object.assign({ className: cn("flex flex-col gap-1 text-left", className) }, props)));
35
35
  };
36
36
  DialogHeader.displayName = "DialogHeader";
37
37
  const DialogBody = (_a) => {
38
38
  var { className, scrollable = false } = _a, props = __rest(_a, ["className", "scrollable"]);
39
- return (_jsx("div", Object.assign({ className: cn("flex flex-1 min-h-0 flex-col mt-8", scrollable && "overflow-y-auto", className) }, props)));
39
+ return (_jsx("div", Object.assign({ className: cn("flex flex-1 min-h-0 flex-col", scrollable && "overflow-y-auto", className) }, props)));
40
40
  };
41
41
  DialogBody.displayName = "DialogBody";
42
42
  const DialogFooter = (_a) => {
43
43
  var { className } = _a, props = __rest(_a, ["className"]);
44
- return (_jsx("div", Object.assign({ className: cn("flex flex-col-reverse gap-3 sm:flex-row sm:items-center sm:justify-end sm:gap-6", className) }, props)));
44
+ return (_jsx("div", Object.assign({ className: cn("flex flex-row items-center justify-end gap-4", className) }, props)));
45
45
  };
46
46
  DialogFooter.displayName = "DialogFooter";
47
47
  const DialogTitle = React.forwardRef((_a, ref) => {
48
48
  var { className } = _a, props = __rest(_a, ["className"]);
49
- return (_jsx(DialogPrimitive.Title, Object.assign({ ref: ref, className: cn("typography-h4 tracking-tight text-text-contrast-max", className) }, props)));
49
+ return (_jsx(DialogPrimitive.Title, Object.assign({ ref: ref, className: cn("typography-h6 tracking-tight text-text-contrast-max", className) }, props)));
50
50
  });
51
51
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
52
52
  const DialogDescription = React.forwardRef((_a, ref) => {
53
53
  var { className } = _a, props = __rest(_a, ["className"]);
54
- return (_jsx(DialogPrimitive.Description, Object.assign({ ref: ref, className: cn("typography-subtitle1 text-text-g-contrast-medium", className) }, props)));
54
+ return (_jsx(DialogPrimitive.Description, Object.assign({ ref: ref, className: cn("typography-body3 text-text-contrast-max", className) }, props)));
55
55
  });
56
56
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
57
57
  export { Dialog, DialogPortal, DialogOverlay, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogBody, DialogFooter, DialogTitle, DialogDescription, };
@@ -1,11 +1,9 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as yup from "yup";
3
3
  import { Dialog, DialogContent, DialogDescription, DialogBody, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "./Dialog";
4
4
  import Button from "../Button/Button";
5
5
  import { Label } from "../Label/Label";
6
6
  import { Input } from "../Input/Input";
7
- import { Field, Form, ValidationHintList } from "../Form";
8
- import PasswordInput from "../PasswordInput";
9
7
  const meta = {
10
8
  title: "Components/Dialog",
11
9
  component: Dialog,
@@ -95,35 +93,9 @@ const changePasswordSchema = yup.object({
95
93
  .required("Please confirm your password")
96
94
  .oneOf([yup.ref("newPassword")], "Passwords must match"),
97
95
  });
98
- export const FigmaChangePassword = {
99
- render: () => {
100
- return (_jsx("div", { className: "flex w-full", children: _jsx(Dialog, { defaultOpen: true, children: _jsx(DialogContent, { className: "min-h-[686px] max-w-[650px]", children: _jsx(Form, { className: "contents", defaultValues: {
101
- newPassword: "",
102
- confirmPassword: "",
103
- }, mode: "onTouched", validationSchema: changePasswordSchema, onSubmit: (values) => {
104
- // eslint-disable-next-line no-console
105
- console.log("Change password submit:", values);
106
- }, children: ({ formState, watch }) => {
107
- const newPassword = watch("newPassword");
108
- const confirmPassword = watch("confirmPassword");
109
- return (_jsxs(_Fragment, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Welcome!" }), _jsx(DialogDescription, { children: "Please create a new password to replace the temporary password." })] }), _jsx(DialogBody, { children: _jsxs("div", { className: "flex flex-col gap-4", children: [_jsx(Field, { name: "newPassword", component: PasswordInput, componentProps: {
110
- id: "new-password",
111
- label: "New password",
112
- type: "password",
113
- required: true,
114
- fullwidth: true,
115
- size: "lg",
116
- } }), _jsx(Field, { name: "confirmPassword", component: PasswordInput, componentProps: {
117
- id: "confirm-password",
118
- label: "Confirm password",
119
- type: "password",
120
- required: true,
121
- fullwidth: true,
122
- size: "lg",
123
- } }), _jsx(ValidationHintList, { values: {
124
- newPassword: newPassword || "",
125
- confirmPassword: confirmPassword || "",
126
- }, rules: passwordHints })] }) }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "outline", color: "primary", size: "lg", fullwidth: false, children: "Back" }), _jsx(Button, { type: "submit", size: "lg", fullwidth: false, className: "w-[180px]", disabled: !formState.isValid || formState.isSubmitting, isLoading: formState.isSubmitting, children: "Save changes" })] })] }));
127
- } }) }) }) }));
128
- },
96
+ export const FigmaFunctionForm = {
97
+ render: () => (_jsx("div", { className: "flex w-full", children: _jsx(Dialog, { defaultOpen: true, children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Title" }), _jsx(DialogDescription, { children: "Subtitle description" })] }), _jsx(DialogBody, { children: _jsx("div", { className: "flex items-center justify-center bg-ramps-secondary-150 h-[200px] w-full rounded-sm", children: _jsx("p", { className: "typography-body3 text-text-contrast-max", children: "Content - Form Area" }) }) }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", color: "primary", fullwidth: false, children: "Cancel" }), _jsx(Button, { disabled: true, fullwidth: false, children: "Confirm" })] })] }) }) })),
98
+ };
99
+ export const FigmaFunctionFormWithAction = {
100
+ render: () => (_jsx("div", { className: "flex w-full", children: _jsx(Dialog, { defaultOpen: true, children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Title" }), _jsx(DialogDescription, { children: "Subtitle description" })] }), _jsx(DialogBody, { children: _jsx("div", { className: "flex items-center justify-center bg-ramps-secondary-150 h-[200px] w-full rounded-sm", children: _jsx("p", { className: "typography-body3 text-text-contrast-max", children: "Content - Form Area" }) }) }), _jsxs(DialogFooter, { className: "justify-between", children: [_jsx(Button, { variant: "outline", color: "secondary", fullwidth: false, children: "Medium" }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsx(Button, { variant: "outline", color: "primary", fullwidth: false, children: "Cancel" }), _jsx(Button, { disabled: true, fullwidth: false, children: "Confirm" })] })] })] }) }) })),
129
101
  };
@@ -35,11 +35,22 @@ export const useControlledForm = ({ defaultValues, controllerRef, resolver, vali
35
35
  mode,
36
36
  reValidateMode,
37
37
  });
38
- return createControlledForm({
38
+ // Keep FormRoot component reference stable across re-renders.
39
+ // createControlledForm creates a new component type (via forwardRef) on every call —
40
+ // if FormRoot changes reference, React unmounts + remounts the entire form tree,
41
+ // causing inputs to lose focus whenever parent state changes (e.g. isValid).
42
+ const stableRef = React.useRef(null);
43
+ if (!stableRef.current) {
44
+ stableRef.current = createControlledForm({
45
+ methods,
46
+ defaultValues,
47
+ controllerRef,
48
+ });
49
+ }
50
+ return {
39
51
  methods,
40
- defaultValues,
41
- controllerRef,
42
- });
52
+ FormRoot: stableRef.current.FormRoot,
53
+ };
43
54
  };
44
55
  const FormInner = (_a, ref) => {
45
56
  var { children, defaultValues, methods: externalMethods, controllerRef, onSubmit, onInvalidSubmit, resolver, validationSchema, mode = "onSubmit", reValidateMode = "onChange", noValidate = true } = _a, formProps = __rest(_a, ["children", "defaultValues", "methods", "controllerRef", "onSubmit", "onInvalidSubmit", "resolver", "validationSchema", "mode", "reValidateMode", "noValidate"]);
@@ -770,9 +770,6 @@ input[type=number] {
770
770
  .mt-4{
771
771
  margin-top: 1rem;
772
772
  }
773
- .mt-8{
774
- margin-top: 2rem;
775
- }
776
773
  .mt-\[6px\]{
777
774
  margin-top: 6px;
778
775
  }
@@ -797,9 +794,6 @@ input[type=number] {
797
794
  .grid{
798
795
  display: grid;
799
796
  }
800
- .contents{
801
- display: contents;
802
- }
803
797
  .hidden{
804
798
  display: none;
805
799
  }
@@ -899,6 +893,9 @@ input[type=number] {
899
893
  .h-60{
900
894
  height: 15rem;
901
895
  }
896
+ .h-\[200px\]{
897
+ height: 200px;
898
+ }
902
899
  .h-\[200vh\]{
903
900
  height: 200vh;
904
901
  }
@@ -969,9 +966,6 @@ input[type=number] {
969
966
  .min-h-\[18px\]{
970
967
  min-height: 18px;
971
968
  }
972
- .min-h-\[686px\]{
973
- min-height: 686px;
974
- }
975
969
  .min-h-screen{
976
970
  min-height: 100vh;
977
971
  }
@@ -1017,9 +1011,6 @@ input[type=number] {
1017
1011
  .w-\[140px\]{
1018
1012
  width: 140px;
1019
1013
  }
1020
- .w-\[180px\]{
1021
- width: 180px;
1022
- }
1023
1014
  .w-\[200px\]{
1024
1015
  width: 200px;
1025
1016
  }
@@ -2552,6 +2543,10 @@ input[type=number] {
2552
2543
  --tw-bg-opacity: 1;
2553
2544
  background-color: color-mix(in srgb, var(--transparent-primary-8) calc(100% * var(--tw-bg-opacity, 1)), transparent);
2554
2545
  }
2546
+ .bg-ramps-secondary-150{
2547
+ --tw-bg-opacity: 1;
2548
+ background-color: color-mix(in srgb, var(--ramps-secondary-150) calc(100% * var(--tw-bg-opacity, 1)), transparent);
2549
+ }
2555
2550
  .bg-red-100{
2556
2551
  --tw-bg-opacity: 1;
2557
2552
  background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1));
@@ -6410,37 +6405,13 @@ input[type=number] {
6410
6405
  }
6411
6406
  @media (min-width: 640px){
6412
6407
 
6413
- .sm\:mt-0{
6414
- margin-top: 0px;
6415
- }
6416
-
6417
6408
  .sm\:max-w-\[425px\]{
6418
6409
  max-width: 425px;
6419
6410
  }
6420
6411
 
6421
- .sm\:flex-row{
6422
- flex-direction: row;
6423
- }
6424
-
6425
- .sm\:items-center{
6426
- align-items: center;
6427
- }
6428
-
6429
- .sm\:justify-end{
6430
- justify-content: flex-end;
6431
- }
6432
-
6433
6412
  .sm\:justify-stretch{
6434
6413
  justify-content: stretch;
6435
6414
  }
6436
-
6437
- .sm\:gap-4{
6438
- gap: 1rem;
6439
- }
6440
-
6441
- .sm\:gap-6{
6442
- gap: 1.5rem;
6443
- }
6444
6415
  }
6445
6416
  @media (min-width: 768px){
6446
6417