@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.
- package/dist/cjs/bundle.css +7 -36
- package/dist/cjs/bundle.js +2 -2
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/cjs/types/components/AlertDialog/AlertDialog.stories.d.ts +3 -0
- package/dist/cjs/types/components/Dialog/Dialog.stories.d.ts +4 -1
- package/dist/cjs/types/components/Form/Form.d.ts +1 -1
- package/dist/cjs/types/patterns/confirm-dialog/ConfirmDialog.d.ts +24 -0
- package/dist/cjs/types/patterns/confirm-dialog/ConfirmDialog.stories.d.ts +53 -0
- package/dist/cjs/types/patterns/form-dialog/FormDialog.d.ts +39 -0
- package/dist/cjs/types/patterns/form-dialog/FormDialog.stories.d.ts +62 -0
- package/dist/components/AlertDialog/AlertDialog.js +5 -5
- package/dist/components/AlertDialog/AlertDialog.stories.js +22 -0
- package/dist/components/Dialog/Dialog.js +6 -6
- package/dist/components/Dialog/Dialog.stories.js +6 -34
- package/dist/components/Form/Form.js +15 -4
- package/dist/esm/bundle.css +7 -36
- package/dist/esm/bundle.js +1 -1
- package/dist/esm/bundle.js.map +1 -1
- package/dist/esm/types/components/AlertDialog/AlertDialog.stories.d.ts +3 -0
- package/dist/esm/types/components/Dialog/Dialog.stories.d.ts +4 -1
- package/dist/esm/types/components/Form/Form.d.ts +1 -1
- package/dist/esm/types/patterns/confirm-dialog/ConfirmDialog.d.ts +24 -0
- package/dist/esm/types/patterns/confirm-dialog/ConfirmDialog.stories.d.ts +53 -0
- package/dist/esm/types/patterns/form-dialog/FormDialog.d.ts +39 -0
- package/dist/esm/types/patterns/form-dialog/FormDialog.stories.d.ts +62 -0
- package/dist/index.d.ts +1 -1
- package/dist/patterns/confirm-dialog/ConfirmDialog.js +44 -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/dist/src/theme/global.css +9 -40
- package/package.json +1 -1
- package/src/components/AlertDialog/AlertDialog.stories.tsx +69 -2
- package/src/components/AlertDialog/AlertDialog.tsx +13 -15
- package/src/components/Dialog/Dialog.stories.tsx +62 -99
- package/src/components/Dialog/Dialog.tsx +6 -12
- package/src/components/Form/Form.tsx +19 -4
- package/src/patterns/confirm-dialog/ConfirmDialog.stories.tsx +193 -0
- package/src/patterns/confirm-dialog/ConfirmDialog.tsx +153 -0
- package/src/patterns/form-dialog/FormDialog.stories.tsx +437 -0
- package/src/patterns/form-dialog/FormDialog.tsx +137 -0
|
@@ -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
|
|
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-
|
|
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-
|
|
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-
|
|
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" }), "
|
|
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-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
99
|
-
render: () => {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
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"]);
|
package/dist/esm/bundle.css
CHANGED
|
@@ -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
|
|