@pravalabs/ui 0.0.0-stage → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +142 -2
- package/dist/Accordion-CVRdRha1.js +107 -0
- package/dist/Alert-Bxv6CGPj.js +54 -0
- package/dist/Avatar-DUw9xBQ-.js +49 -0
- package/dist/Badge-cupXlWce.js +37 -0
- package/dist/Button-vjrnnaM_.js +65 -0
- package/dist/Card-BJNdpGjM.js +44 -0
- package/dist/Checkbox-BQtcnwwC.js +60 -0
- package/dist/Container-DO8bd1tv.js +19 -0
- package/dist/Dialog-D3-sT_1Z.js +147 -0
- package/dist/Drawer-BRzJmvQx.js +21 -0
- package/dist/DropdownMenu-CFa2vgXi.js +137 -0
- package/dist/FormField-CoC946w9.js +61 -0
- package/dist/Grid-vTrChm2w.js +31 -0
- package/dist/Input-B97l8Dj0.js +82 -0
- package/dist/Label-DYOFzyEM.js +25 -0
- package/dist/Popover-C9Vgtm3q.js +81 -0
- package/dist/PravaProvider-0znpKV4G.js +59 -0
- package/dist/Progress-_Hz8dxM4.js +51 -0
- package/dist/RadioGroup-CvdV80Pg.js +90 -0
- package/dist/Select-_urp2aA_.js +451 -0
- package/dist/Separator-MnFbL0eH.js +23 -0
- package/dist/Skeleton-CyjiU8o1.js +25 -0
- package/dist/Spinner-Da7h4BDn.js +77 -0
- package/dist/Stack-DNtmh6BN.js +30 -0
- package/dist/Switch-Cp-wriw6.js +50 -0
- package/dist/Tabs-C0SRJSv1.js +158 -0
- package/dist/Textarea-D0fNA7sQ.js +69 -0
- package/dist/Toast-7qJXHzEb.js +110 -0
- package/dist/Tooltip-CyW8YfU9.js +57 -0
- package/dist/accordion.js +8 -0
- package/dist/alert.js +7 -0
- package/dist/avatar.js +7 -0
- package/dist/badge.js +7 -0
- package/dist/button.js +7 -0
- package/dist/card.js +10 -0
- package/dist/checkbox.js +8 -0
- package/dist/components/accordion/Accordion.d.ts +42 -0
- package/dist/components/accordion/index.d.ts +2 -0
- package/dist/components/alert/Alert.d.ts +35 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/avatar/Avatar.d.ts +16 -0
- package/dist/components/avatar/index.d.ts +2 -0
- package/dist/components/badge/Badge.d.ts +22 -0
- package/dist/components/badge/index.d.ts +2 -0
- package/dist/components/button/Button.d.ts +50 -0
- package/dist/components/button/index.d.ts +2 -0
- package/dist/components/card/Card.d.ts +49 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/checkbox/Checkbox.d.ts +23 -0
- package/dist/components/checkbox/index.d.ts +2 -0
- package/dist/components/container/Container.d.ts +22 -0
- package/dist/components/container/index.d.ts +2 -0
- package/dist/components/dialog/Dialog.d.ts +89 -0
- package/dist/components/dialog/index.d.ts +2 -0
- package/dist/components/drawer/Drawer.d.ts +46 -0
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/dropdown-menu/DropdownMenu.d.ts +59 -0
- package/dist/components/dropdown-menu/index.d.ts +2 -0
- package/dist/components/field/field.d.ts +87 -0
- package/dist/components/form-field/FormField.d.ts +41 -0
- package/dist/components/form-field/index.d.ts +2 -0
- package/dist/components/grid/Grid.d.ts +36 -0
- package/dist/components/grid/index.d.ts +2 -0
- package/dist/components/input/Input.d.ts +35 -0
- package/dist/components/input/index.d.ts +2 -0
- package/dist/components/label/Label.d.ts +15 -0
- package/dist/components/label/index.d.ts +2 -0
- package/dist/components/popover/Popover.d.ts +35 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/progress/Progress.d.ts +15 -0
- package/dist/components/progress/index.d.ts +2 -0
- package/dist/components/provider/PravaProvider.d.ts +69 -0
- package/dist/components/provider/index.d.ts +2 -0
- package/dist/components/radio-group/RadioGroup.d.ts +58 -0
- package/dist/components/radio-group/index.d.ts +2 -0
- package/dist/components/select/Select.d.ts +76 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/separator/Separator.d.ts +9 -0
- package/dist/components/separator/index.d.ts +2 -0
- package/dist/components/skeleton/Skeleton.d.ts +7 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/spinner/Spinner.d.ts +15 -0
- package/dist/components/spinner/index.d.ts +2 -0
- package/dist/components/stack/Stack.d.ts +38 -0
- package/dist/components/stack/index.d.ts +2 -0
- package/dist/components/switch/Switch.d.ts +19 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/tabs/Tabs.d.ts +69 -0
- package/dist/components/tabs/index.d.ts +2 -0
- package/dist/components/textarea/Textarea.d.ts +26 -0
- package/dist/components/textarea/index.d.ts +2 -0
- package/dist/components/toast/Toast.d.ts +55 -0
- package/dist/components/toast/index.d.ts +2 -0
- package/dist/components/tooltip/Tooltip.d.ts +22 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/container.js +7 -0
- package/dist/dialog.js +8 -0
- package/dist/drawer.js +8 -0
- package/dist/dropdown-menu.js +8 -0
- package/dist/field-U1YinldE.js +152 -0
- package/dist/form-field.js +8 -0
- package/dist/grid.js +7 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +29 -0
- package/dist/input.js +8 -0
- package/dist/internal/overlay.d.ts +39 -0
- package/dist/internal/useControllable.d.ts +2 -0
- package/dist/label.js +8 -0
- package/dist/overlay-9zlvgpUZ.js +121 -0
- package/dist/popover.js +8 -0
- package/dist/progress.js +7 -0
- package/dist/provider.js +7 -0
- package/dist/radio-group.js +8 -0
- package/dist/select.js +8 -0
- package/dist/separator.js +7 -0
- package/dist/skeleton.js +7 -0
- package/dist/spinner.js +7 -0
- package/dist/stack.js +7 -0
- package/dist/styles/components/accordion.css +1 -0
- package/dist/styles/components/alert.css +1 -0
- package/dist/styles/components/avatar.css +1 -0
- package/dist/styles/components/badge.css +1 -0
- package/dist/styles/components/button.css +1 -0
- package/dist/styles/components/card.css +1 -0
- package/dist/styles/components/checkbox.css +1 -0
- package/dist/styles/components/container.css +1 -0
- package/dist/styles/components/dialog.css +1 -0
- package/dist/styles/components/drawer.css +1 -0
- package/dist/styles/components/dropdown-menu.css +1 -0
- package/dist/styles/components/field.css +1 -0
- package/dist/styles/components/floating.css +1 -0
- package/dist/styles/components/form-field.css +1 -0
- package/dist/styles/components/grid.css +1 -0
- package/dist/styles/components/input.css +1 -0
- package/dist/styles/components/label.css +1 -0
- package/dist/styles/components/popover.css +1 -0
- package/dist/styles/components/progress.css +1 -0
- package/dist/styles/components/provider.css +1 -0
- package/dist/styles/components/radio-group.css +1 -0
- package/dist/styles/components/select.css +1 -0
- package/dist/styles/components/separator.css +1 -0
- package/dist/styles/components/skeleton.css +1 -0
- package/dist/styles/components/spinner.css +1 -0
- package/dist/styles/components/stack.css +1 -0
- package/dist/styles/components/switch.css +1 -0
- package/dist/styles/components/tabs.css +1 -0
- package/dist/styles/components/textarea.css +1 -0
- package/dist/styles/components/toast.css +1 -0
- package/dist/styles/components/tooltip.css +1 -0
- package/dist/styles.css +1 -0
- package/dist/switch.js +8 -0
- package/dist/tabs.js +10 -0
- package/dist/textarea.js +8 -0
- package/dist/toast.js +9 -0
- package/dist/tokens.css +192 -0
- package/dist/tooltip.js +8 -0
- package/dist/useControllable-C2Te1pSd.js +14 -0
- package/package.json +223 -4
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type AlertProps = Omit<HTMLAttributes<HTMLDivElement>, "title"> & {
|
|
3
|
+
/** Semantic color and default icon. */
|
|
4
|
+
tone?: "neutral" | "info" | "success" | "warning" | "danger";
|
|
5
|
+
/** Short summary shown in bold above the message. */
|
|
6
|
+
title?: ReactNode;
|
|
7
|
+
/** Replaces the tone's icon; pass `null` to show none. */
|
|
8
|
+
icon?: ReactNode;
|
|
9
|
+
/** Controls for this message, such as a Button. They wrap below the text when space is tight. */
|
|
10
|
+
action?: ReactNode;
|
|
11
|
+
/** Shows a dismiss button and is called when it is pressed. Hiding the Alert stays with you. */
|
|
12
|
+
onDismiss?: () => void;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Contextual feedback that stays until the page removes it. `role="status"` is polite;
|
|
16
|
+
* pass `role="alert"` only when the message must interrupt.
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { Alert } from '@pravalabs/ui/alert';
|
|
20
|
+
*
|
|
21
|
+
* <Alert tone="warning" title="Storage almost full">Upgrade to keep uploading files.</Alert>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare const Alert: import('react').ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "title"> & {
|
|
25
|
+
/** Semantic color and default icon. */
|
|
26
|
+
tone?: "neutral" | "info" | "success" | "warning" | "danger";
|
|
27
|
+
/** Short summary shown in bold above the message. */
|
|
28
|
+
title?: ReactNode;
|
|
29
|
+
/** Replaces the tone's icon; pass `null` to show none. */
|
|
30
|
+
icon?: ReactNode;
|
|
31
|
+
/** Controls for this message, such as a Button. They wrap below the text when space is tight. */
|
|
32
|
+
action?: ReactNode;
|
|
33
|
+
/** Shows a dismiss button and is called when it is pressed. Hiding the Alert stays with you. */
|
|
34
|
+
onDismiss?: () => void;
|
|
35
|
+
} & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type AvatarProps = Omit<HTMLAttributes<HTMLSpanElement>, "children"> & {
|
|
3
|
+
/** Image URL. A failed or missing image displays the fallback. */
|
|
4
|
+
src?: string;
|
|
5
|
+
/** Person's first name, used to form initials and an accessible name. */
|
|
6
|
+
firstName?: string;
|
|
7
|
+
/** Person's last name, used to form initials and an accessible name. */
|
|
8
|
+
lastName?: string;
|
|
9
|
+
/** Text alternative for an entity avatar or custom accessible name. */
|
|
10
|
+
alt?: string;
|
|
11
|
+
/** Content shown when the image is missing or fails; defaults to the initials. */
|
|
12
|
+
fallback?: ReactNode;
|
|
13
|
+
/** Avatar dimensions. */
|
|
14
|
+
size?: "sm" | "md" | "lg";
|
|
15
|
+
};
|
|
16
|
+
export declare function Avatar({ src, firstName, lastName, alt, fallback, size, className, onError, ...props }: AvatarProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type BadgeProps = HTMLAttributes<HTMLSpanElement> & {
|
|
3
|
+
/** Visible badge text or count. Status meaning must be in this text, not only the tone. */
|
|
4
|
+
content: ReactNode;
|
|
5
|
+
/** Element the badge is anchored to. Omit to render a standalone status label. */
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
/** Semantic color. Defaults to `danger` when anchored (counts) and `neutral` when standalone. */
|
|
8
|
+
tone?: "neutral" | "primary" | "success" | "warning" | "danger" | "info";
|
|
9
|
+
size?: "sm" | "md";
|
|
10
|
+
/** Corner of the anchored element, in logical directions so it mirrors in RTL. */
|
|
11
|
+
placement?: "top-start" | "top-end" | "bottom-start" | "bottom-end";
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* A compact, non-interactive status or count, either anchored to an element or standalone.
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import { Badge } from '@pravalabs/ui/badge';
|
|
18
|
+
* <Badge content="3"><Button>Inbox</Button></Badge>
|
|
19
|
+
* <Badge tone="success" content="Active" />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function Badge({ tone, size, placement, content, className, children, ...props }: BadgeProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
type ButtonCommonProps = {
|
|
3
|
+
/** Selects the semantic visual treatment. */
|
|
4
|
+
variant?: "primary" | "secondary" | "outline" | "ghost" | "destructive";
|
|
5
|
+
/** Selects the button's compact, default, or spacious dimensions. */
|
|
6
|
+
size?: "sm" | "md" | "lg";
|
|
7
|
+
/** Shows a spinner and blocks activation while keeping the button focusable. */
|
|
8
|
+
loading?: boolean;
|
|
9
|
+
/** Disables the button's press, transition, and loading animations. */
|
|
10
|
+
disableAnimation?: boolean;
|
|
11
|
+
/** Adds a decorative icon before the label (left in LTR, right in RTL). */
|
|
12
|
+
startIcon?: ReactNode;
|
|
13
|
+
/** Adds a decorative icon after the label (right in LTR, left in RTL). */
|
|
14
|
+
endIcon?: ReactNode;
|
|
15
|
+
/** Stretches the button to the width of its container. */
|
|
16
|
+
fullWidth?: boolean;
|
|
17
|
+
/** Button label or content. */
|
|
18
|
+
children?: ReactNode;
|
|
19
|
+
};
|
|
20
|
+
type NativeButtonProps = ButtonCommonProps & Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type"> & {
|
|
21
|
+
href?: undefined;
|
|
22
|
+
};
|
|
23
|
+
/** Props for the Prava UI Button. Pass `href` to render a link styled as a button. */
|
|
24
|
+
export type ButtonProps = (NativeButtonProps & {
|
|
25
|
+
/** Selects the native button action. */
|
|
26
|
+
type?: "button" | "submit" | "reset";
|
|
27
|
+
}) | (NativeButtonProps & {
|
|
28
|
+
/** Selects icon-only presentation and requires an accessible name. */
|
|
29
|
+
type: "icon";
|
|
30
|
+
/** Names the icon-only button for assistive technology. */
|
|
31
|
+
"aria-label": string;
|
|
32
|
+
}) | (ButtonCommonProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "type"> & {
|
|
33
|
+
/** Renders an `<a>` with button styling. */
|
|
34
|
+
href: string;
|
|
35
|
+
/** Removes the link from navigation and the tab order. */
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
type?: undefined;
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Renders an accessible action button, or a link styled as one when `href` is set.
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* import { Button } from '@pravalabs/ui/button';
|
|
44
|
+
*
|
|
45
|
+
* <Button startIcon={<PlusIcon />}>New project</Button>
|
|
46
|
+
* <Button href="/billing" variant="secondary">View billing</Button>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function Button(allProps: ButtonProps): import("react").JSX.Element;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
/** Native root attributes for a Card. */
|
|
3
|
+
export type CardProps = HTMLAttributes<HTMLDivElement>;
|
|
4
|
+
/** Native header attributes for a Card. */
|
|
5
|
+
export type CardHeaderProps = HTMLAttributes<HTMLElement>;
|
|
6
|
+
/** Native content attributes for a Card. */
|
|
7
|
+
export type CardContentProps = HTMLAttributes<HTMLDivElement>;
|
|
8
|
+
/** Native footer attributes for a Card. */
|
|
9
|
+
export type CardFooterProps = HTMLAttributes<HTMLElement>;
|
|
10
|
+
/**
|
|
11
|
+
* Groups related content without adding click behavior or heading semantics.
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* import { Card, CardContent, CardHeader } from '@pravalabs/ui/card';
|
|
15
|
+
*
|
|
16
|
+
* <Card><CardHeader><h2>Account</h2></CardHeader><CardContent>Profile details</CardContent></Card>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function Card({ className, ...props }: CardProps): import("react").JSX.Element;
|
|
20
|
+
/**
|
|
21
|
+
* Optional top section for a Card; choose heading levels in the consuming page.
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import { Card, CardHeader } from '@pravalabs/ui/card';
|
|
25
|
+
*
|
|
26
|
+
* <Card><CardHeader><h2>Settings</h2></CardHeader></Card>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function CardHeader({ className, ...props }: CardHeaderProps): import("react").JSX.Element;
|
|
30
|
+
/**
|
|
31
|
+
* Main content section for a Card.
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* import { Card, CardContent } from '@pravalabs/ui/card';
|
|
35
|
+
*
|
|
36
|
+
* <Card><CardContent>Your account details appear here.</CardContent></Card>
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function CardContent({ className, ...props }: CardContentProps): import("react").JSX.Element;
|
|
40
|
+
/**
|
|
41
|
+
* Optional bottom section for Card actions or supporting content.
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* import { Card, CardFooter } from '@pravalabs/ui/card';
|
|
45
|
+
*
|
|
46
|
+
* <Card><CardFooter><button type="button">Save</button></CardFooter></Card>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function CardFooter({ className, ...props }: CardFooterProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { InputHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { FieldProps } from '../field/field';
|
|
3
|
+
export type CheckboxProps = Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "size"> & FieldProps & {
|
|
4
|
+
/** Visible label; clicking it toggles the checkbox. */
|
|
5
|
+
label?: ReactNode;
|
|
6
|
+
/** Shows the mixed state (for "select all"); exposed natively as `aria-checked="mixed"`. */
|
|
7
|
+
indeterminate?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* A native checkbox with a painted indicator, label, help text, and error message.
|
|
11
|
+
* `className` and `style` apply to the label row; everything else reaches the native input.
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* import { Checkbox } from '@pravalabs/ui/checkbox';
|
|
15
|
+
* <Checkbox label="Email me product updates" field={register('updates')} />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare const Checkbox: import('react').ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> & FieldProps & {
|
|
19
|
+
/** Visible label; clicking it toggles the checkbox. */
|
|
20
|
+
label?: ReactNode;
|
|
21
|
+
/** Shows the mixed state (for "select all"); exposed natively as `aria-checked="mixed"`. */
|
|
22
|
+
indeterminate?: boolean;
|
|
23
|
+
} & import('react').RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ElementType, HTMLAttributes } from 'react';
|
|
2
|
+
export type ContainerProps = HTMLAttributes<HTMLElement> & {
|
|
3
|
+
/** Maximum content width. `fluid` removes the limit but keeps the responsive padding. */
|
|
4
|
+
size?: "sm" | "md" | "lg" | "xl" | "fluid";
|
|
5
|
+
/** Element to render, such as `main` or `section`. */
|
|
6
|
+
as?: ElementType;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Centers content and keeps a responsive inline gutter. Set `--prava-container-max` for a custom width.
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { Container } from '@pravalabs/ui/container';
|
|
13
|
+
*
|
|
14
|
+
* <Container as="main" size="md">Page content</Container>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare const Container: import('react').ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
|
|
18
|
+
/** Maximum content width. `fluid` removes the limit but keeps the responsive padding. */
|
|
19
|
+
size?: "sm" | "md" | "lg" | "xl" | "fluid";
|
|
20
|
+
/** Element to render, such as `main` or `section`. */
|
|
21
|
+
as?: ElementType;
|
|
22
|
+
} & import('react').RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { DialogHTMLAttributes, ReactElement, ReactNode } from 'react';
|
|
2
|
+
export type DialogProps = Omit<DialogHTMLAttributes<HTMLDialogElement>, "open" | "title"> & {
|
|
3
|
+
/** Heading that names the dialog. */
|
|
4
|
+
title: ReactNode;
|
|
5
|
+
/** Supporting text announced with the title. */
|
|
6
|
+
description?: ReactNode;
|
|
7
|
+
/** Actions pinned below the scrolling content. */
|
|
8
|
+
footer?: ReactNode;
|
|
9
|
+
/** Focusable element that opens the dialog, such as a Button. Omit when you control `open`. */
|
|
10
|
+
trigger?: ReactElement;
|
|
11
|
+
/** Open state when controlled. */
|
|
12
|
+
open?: boolean;
|
|
13
|
+
/** Initial open state when uncontrolled. */
|
|
14
|
+
defaultOpen?: boolean;
|
|
15
|
+
/** Called with the next state when the dialog asks to open or close. */
|
|
16
|
+
onOpenChange?: (open: boolean) => void;
|
|
17
|
+
/** Blocks the page behind it and traps focus. `false` lets people keep working around it. */
|
|
18
|
+
modal?: boolean;
|
|
19
|
+
/** Lets Escape and a press outside close it. Turn off when a choice is required. */
|
|
20
|
+
dismissible?: boolean;
|
|
21
|
+
/** Removes the close button; give people another way out in `footer`. */
|
|
22
|
+
hideClose?: boolean;
|
|
23
|
+
/** Maximum width. It always stays inside the viewport. */
|
|
24
|
+
size?: "sm" | "md" | "lg";
|
|
25
|
+
/** Extra classes for inner slots; `className` goes on the dialog root. */
|
|
26
|
+
classNames?: {
|
|
27
|
+
header?: string;
|
|
28
|
+
title?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
body?: string;
|
|
31
|
+
footer?: string;
|
|
32
|
+
close?: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/** Makes its child close the surrounding Dialog or Drawer when pressed. */
|
|
36
|
+
export declare function DialogClose({ children }: {
|
|
37
|
+
children: ReactElement;
|
|
38
|
+
}): ReactElement<{
|
|
39
|
+
[x: string]: unknown;
|
|
40
|
+
}, string | import('react').JSXElementConstructor<any>>;
|
|
41
|
+
/**
|
|
42
|
+
* A native `<dialog>`: the browser provides the top layer, focus containment and focus restoration.
|
|
43
|
+
* Focus lands on the first focusable child; mark another with `data-autofocus`.
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* import { Dialog, DialogClose } from '@pravalabs/ui/dialog';
|
|
47
|
+
*
|
|
48
|
+
* <Dialog
|
|
49
|
+
* trigger={<Button>Delete project</Button>}
|
|
50
|
+
* title="Delete this project?"
|
|
51
|
+
* footer={<DialogClose><Button variant="outline">Cancel</Button></DialogClose>}
|
|
52
|
+
* >
|
|
53
|
+
* This can't be undone.
|
|
54
|
+
* </Dialog>
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare const Dialog: import('react').ForwardRefExoticComponent<Omit<DialogHTMLAttributes<HTMLDialogElement>, "title" | "open"> & {
|
|
58
|
+
/** Heading that names the dialog. */
|
|
59
|
+
title: ReactNode;
|
|
60
|
+
/** Supporting text announced with the title. */
|
|
61
|
+
description?: ReactNode;
|
|
62
|
+
/** Actions pinned below the scrolling content. */
|
|
63
|
+
footer?: ReactNode;
|
|
64
|
+
/** Focusable element that opens the dialog, such as a Button. Omit when you control `open`. */
|
|
65
|
+
trigger?: ReactElement;
|
|
66
|
+
/** Open state when controlled. */
|
|
67
|
+
open?: boolean;
|
|
68
|
+
/** Initial open state when uncontrolled. */
|
|
69
|
+
defaultOpen?: boolean;
|
|
70
|
+
/** Called with the next state when the dialog asks to open or close. */
|
|
71
|
+
onOpenChange?: (open: boolean) => void;
|
|
72
|
+
/** Blocks the page behind it and traps focus. `false` lets people keep working around it. */
|
|
73
|
+
modal?: boolean;
|
|
74
|
+
/** Lets Escape and a press outside close it. Turn off when a choice is required. */
|
|
75
|
+
dismissible?: boolean;
|
|
76
|
+
/** Removes the close button; give people another way out in `footer`. */
|
|
77
|
+
hideClose?: boolean;
|
|
78
|
+
/** Maximum width. It always stays inside the viewport. */
|
|
79
|
+
size?: "sm" | "md" | "lg";
|
|
80
|
+
/** Extra classes for inner slots; `className` goes on the dialog root. */
|
|
81
|
+
classNames?: {
|
|
82
|
+
header?: string;
|
|
83
|
+
title?: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
body?: string;
|
|
86
|
+
footer?: string;
|
|
87
|
+
close?: string;
|
|
88
|
+
};
|
|
89
|
+
} & import('react').RefAttributes<HTMLDialogElement>>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { DialogClose, DialogProps } from '../dialog';
|
|
2
|
+
export type DrawerProps = DialogProps & {
|
|
3
|
+
/** Edge it slides from. `start` and `end` follow the text direction. */
|
|
4
|
+
placement?: "start" | "end" | "top" | "bottom";
|
|
5
|
+
};
|
|
6
|
+
/** Makes its child close the surrounding Drawer when pressed. */
|
|
7
|
+
export declare const DrawerClose: typeof DialogClose;
|
|
8
|
+
/**
|
|
9
|
+
* A Dialog anchored to a screen edge, with the same props, focus, and dismissal rules.
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { Drawer, DrawerClose } from '@pravalabs/ui/drawer';
|
|
13
|
+
*
|
|
14
|
+
* <Drawer
|
|
15
|
+
* trigger={<Button>Filters</Button>}
|
|
16
|
+
* title="Filters"
|
|
17
|
+
* footer={<DrawerClose><Button>Apply</Button></DrawerClose>}
|
|
18
|
+
* >
|
|
19
|
+
* Filter fields
|
|
20
|
+
* </Drawer>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare const Drawer: import('react').ForwardRefExoticComponent<Omit<import('react').DialogHTMLAttributes<HTMLDialogElement>, "title" | "open"> & {
|
|
24
|
+
title: import('react').ReactNode;
|
|
25
|
+
description?: import('react').ReactNode;
|
|
26
|
+
footer?: import('react').ReactNode;
|
|
27
|
+
trigger?: import('react').ReactElement;
|
|
28
|
+
open?: boolean;
|
|
29
|
+
defaultOpen?: boolean;
|
|
30
|
+
onOpenChange?: (open: boolean) => void;
|
|
31
|
+
modal?: boolean;
|
|
32
|
+
dismissible?: boolean;
|
|
33
|
+
hideClose?: boolean;
|
|
34
|
+
size?: "sm" | "md" | "lg";
|
|
35
|
+
classNames?: {
|
|
36
|
+
header?: string;
|
|
37
|
+
title?: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
body?: string;
|
|
40
|
+
footer?: string;
|
|
41
|
+
close?: string;
|
|
42
|
+
};
|
|
43
|
+
} & {
|
|
44
|
+
/** Edge it slides from. `start` and `end` follow the text direction. */
|
|
45
|
+
placement?: "start" | "end" | "top" | "bottom";
|
|
46
|
+
} & import('react').RefAttributes<HTMLDialogElement>>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { FloatingAlign, FloatingPlacement } from '../../internal/overlay';
|
|
3
|
+
export type DropdownMenuAction = {
|
|
4
|
+
/** What people see; pass translated text or a node. */
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
/** Runs when the item is chosen, after the menu closes and focus returns to the trigger. */
|
|
7
|
+
onSelect?: () => void;
|
|
8
|
+
/** Renders the item as a link. */
|
|
9
|
+
href?: string;
|
|
10
|
+
/** Decorative icon before the label. */
|
|
11
|
+
icon?: ReactNode;
|
|
12
|
+
/** Stays reachable by keyboard so people can discover it, but can't be chosen. */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** `danger` marks a destructive action. */
|
|
15
|
+
tone?: "default" | "danger";
|
|
16
|
+
};
|
|
17
|
+
export type DropdownMenuSeparator = {
|
|
18
|
+
separator: true;
|
|
19
|
+
};
|
|
20
|
+
export type DropdownMenuGroup = {
|
|
21
|
+
/** Group heading; pass translated text or a node. */
|
|
22
|
+
label: ReactNode;
|
|
23
|
+
items: readonly DropdownMenuAction[];
|
|
24
|
+
};
|
|
25
|
+
export type DropdownMenuItem = DropdownMenuAction | DropdownMenuSeparator | DropdownMenuGroup;
|
|
26
|
+
export type DropdownMenuProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
27
|
+
/** Focusable element that opens the menu, such as a Button. */
|
|
28
|
+
trigger: ReactElement;
|
|
29
|
+
/** Actions, `{ separator: true }` dividers, and `{ label, items }` groups. */
|
|
30
|
+
items: readonly DropdownMenuItem[];
|
|
31
|
+
/** Preferred side. It flips when there's no room; `start` and `end` follow the text direction. */
|
|
32
|
+
placement?: FloatingPlacement;
|
|
33
|
+
/** Alignment against the trigger along that side. */
|
|
34
|
+
align?: FloatingAlign;
|
|
35
|
+
/** Open state when controlled. */
|
|
36
|
+
open?: boolean;
|
|
37
|
+
/** Initial open state when uncontrolled. */
|
|
38
|
+
defaultOpen?: boolean;
|
|
39
|
+
/** Called with the next state when it asks to open or close. */
|
|
40
|
+
onOpenChange?: (open: boolean) => void;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* A list of actions opened from a trigger, following the WAI-ARIA menu button pattern.
|
|
44
|
+
* For choosing a value, use Select.
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* import { DropdownMenu } from '@pravalabs/ui/dropdown-menu';
|
|
48
|
+
*
|
|
49
|
+
* <DropdownMenu
|
|
50
|
+
* trigger={<Button variant="outline">Actions</Button>}
|
|
51
|
+
* items={[
|
|
52
|
+
* { label: 'Rename', onSelect: rename },
|
|
53
|
+
* { separator: true },
|
|
54
|
+
* { label: 'Delete', tone: 'danger', onSelect: remove },
|
|
55
|
+
* ]}
|
|
56
|
+
* />
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function DropdownMenu({ trigger, items, placement, align, open: openProp, defaultOpen, onOpenChange, className, id: idProp, ...props }: DropdownMenuProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { AriaAttributes, ChangeEvent, FocusEvent, ForwardedRef, FormEvent, InputHTMLAttributes, ReactNode, Ref } from 'react';
|
|
2
|
+
import { BuiltInMessages } from '../provider/PravaProvider';
|
|
3
|
+
export type FieldControl = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
|
4
|
+
/**
|
|
5
|
+
* A form library's connection to a control, typed by shape so Prava has no form-library dependency.
|
|
6
|
+
* Matches both react-hook-form's `register()` result and `Controller`'s `field`.
|
|
7
|
+
*/
|
|
8
|
+
export type FieldBinding<E extends FieldControl = HTMLInputElement> = {
|
|
9
|
+
name?: string;
|
|
10
|
+
value?: unknown;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
onChange?: (event: ChangeEvent<E>) => unknown;
|
|
13
|
+
onBlur?: (event: FocusEvent<E>) => unknown;
|
|
14
|
+
ref?: Ref<E>;
|
|
15
|
+
};
|
|
16
|
+
/** Props every Prava form control shares. */
|
|
17
|
+
export type FieldProps<E extends FieldControl = HTMLInputElement> = {
|
|
18
|
+
/**
|
|
19
|
+
* Connects the control to a form library: `field={register("email")}`, or `field={field}` inside
|
|
20
|
+
* react-hook-form's `Controller`. The control's own props win, and its `onChange`/`onBlur` still run.
|
|
21
|
+
*/
|
|
22
|
+
field?: FieldBinding<E>;
|
|
23
|
+
/** Help text shown below the control and linked with `aria-describedby`. */
|
|
24
|
+
description?: ReactNode;
|
|
25
|
+
/**
|
|
26
|
+
* Error message shown below the control; marks it invalid and replaces built-in validation text.
|
|
27
|
+
* Pass `errors.name?.message` from react-hook-form, or `true` to mark invalid without text.
|
|
28
|
+
*/
|
|
29
|
+
error?: ReactNode;
|
|
30
|
+
/** Marks the control invalid without a message. */
|
|
31
|
+
invalid?: boolean;
|
|
32
|
+
};
|
|
33
|
+
export declare const FieldContext: import('react').Context<boolean>;
|
|
34
|
+
export declare const isMessage: (node: ReactNode) => boolean;
|
|
35
|
+
export declare const setRef: <T>(ref: Ref<T> | undefined, value: T | null) => void;
|
|
36
|
+
/** Merges a `field` binding into a control's props and ref. Choice controls map its value to `checked`. */
|
|
37
|
+
export declare function bindField<E extends FieldControl, P extends {
|
|
38
|
+
field?: FieldBinding<E>;
|
|
39
|
+
onChange?: (event: ChangeEvent<E>) => void;
|
|
40
|
+
onBlur?: (event: FocusEvent<E>) => void;
|
|
41
|
+
}>({ field, ...props }: P, forwardedRef: ForwardedRef<E>, valueProp?: "value" | "checked"): Omit<P, "field"> & {
|
|
42
|
+
ref: Ref<E>;
|
|
43
|
+
};
|
|
44
|
+
/** Replaces `{name}` placeholders in a message; numbers are formatted for the locale. */
|
|
45
|
+
export declare const fillMessage: (template: string, params: Record<string, string | number>, locale: string) => string;
|
|
46
|
+
/**
|
|
47
|
+
* Calls `onWrite` after code assigns a DOM property directly, which fires no event; react-hook-form's
|
|
48
|
+
* `reset` and `setValue` do this. React tracks input values with the same instance-level accessor.
|
|
49
|
+
*/
|
|
50
|
+
export declare function onPropertyWrite<E extends object>(el: E, prop: keyof E & string, onWrite: () => void): void;
|
|
51
|
+
/** Maps a failed native constraint to the provider's localized message. */
|
|
52
|
+
export declare function validationMessage(el: FieldControl, messages: BuiltInMessages, locale: string): string | undefined;
|
|
53
|
+
type UseFieldOptions<E extends FieldControl> = Omit<FieldProps<E>, "field"> & {
|
|
54
|
+
id?: string;
|
|
55
|
+
"aria-describedby"?: string;
|
|
56
|
+
"aria-invalid"?: AriaAttributes["aria-invalid"];
|
|
57
|
+
onBlur?: (event: FocusEvent<E>) => void;
|
|
58
|
+
onChange?: (event: ChangeEvent<E>) => void;
|
|
59
|
+
onInvalid?: (event: FormEvent<E>) => void;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Shared ids, ARIA, messages, and localized native validation for every form control.
|
|
63
|
+
* Native messages appear after the user edits and leaves the control, or on submit, and clear
|
|
64
|
+
* as soon as the value is valid. `<form noValidate>` hands validation to the app (for example react-hook-form).
|
|
65
|
+
*/
|
|
66
|
+
export declare function useField<E extends FieldControl>({ id, description, error, invalid, onBlur, onChange, onInvalid, ...aria }: UseFieldOptions<E>): {
|
|
67
|
+
id: string;
|
|
68
|
+
controlProps: {
|
|
69
|
+
id: string;
|
|
70
|
+
"aria-invalid": true | undefined;
|
|
71
|
+
"aria-describedby": string | undefined;
|
|
72
|
+
onBlur: (event: FocusEvent<E>) => void;
|
|
73
|
+
onChange: (event: ChangeEvent<E>) => void;
|
|
74
|
+
onInvalid: (event: FormEvent<E>) => void;
|
|
75
|
+
};
|
|
76
|
+
messages: import("react").JSX.Element;
|
|
77
|
+
};
|
|
78
|
+
export type ChoiceProps = Omit<InputHTMLAttributes<HTMLInputElement>, "type"> & {
|
|
79
|
+
kind: "checkbox" | "radio" | "switch";
|
|
80
|
+
label?: ReactNode;
|
|
81
|
+
};
|
|
82
|
+
/** The shared native input + painted indicator behind Checkbox, Switch, and RadioGroup options. */
|
|
83
|
+
export declare const Choice: import('react').ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, "type"> & {
|
|
84
|
+
kind: "checkbox" | "radio" | "switch";
|
|
85
|
+
label?: ReactNode;
|
|
86
|
+
} & import('react').RefAttributes<HTMLInputElement>>;
|
|
87
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AriaAttributes, ChangeEventHandler, FocusEventHandler, FormEventHandler, HTMLAttributes, ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { FieldControl } from '../field/field';
|
|
3
|
+
type AssociatedControlProps = {
|
|
4
|
+
id?: string;
|
|
5
|
+
type?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
"data-size"?: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
"aria-describedby"?: string;
|
|
10
|
+
"aria-invalid"?: AriaAttributes["aria-invalid"];
|
|
11
|
+
"aria-required"?: AriaAttributes["aria-required"];
|
|
12
|
+
onBlur?: FocusEventHandler<FieldControl>;
|
|
13
|
+
onChange?: ChangeEventHandler<FieldControl>;
|
|
14
|
+
onInvalid?: FormEventHandler<FieldControl>;
|
|
15
|
+
};
|
|
16
|
+
export type FormFieldProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
17
|
+
/** Accessible label rendered above the control. */
|
|
18
|
+
label: ReactNode;
|
|
19
|
+
/** A single native or Prava form control to associate with this field. Native text inputs, textareas, and selects get Prava's control styling. */
|
|
20
|
+
control: ReactElement<AssociatedControlProps>;
|
|
21
|
+
/** Optional explanatory text associated with the control. */
|
|
22
|
+
description?: ReactNode;
|
|
23
|
+
/** Validation message associated with the control; replaces built-in validation text. */
|
|
24
|
+
error?: ReactNode;
|
|
25
|
+
/** Marks the control required and adds the readable cue to the label. */
|
|
26
|
+
required?: boolean;
|
|
27
|
+
/** Stable control ID; generated when omitted. */
|
|
28
|
+
id?: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Composes a label, any control, help text, and error with stable accessible associations.
|
|
32
|
+
* Native and Prava controls both get localized validation messages here.
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* import { FormField } from '@pravalabs/ui/form-field';
|
|
36
|
+
* import { Input } from '@pravalabs/ui/input';
|
|
37
|
+
* <FormField label="Email" required error={errors.email?.message} control={<Input type="email" field={register('email')} />} />
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function FormField({ label, control, description, error, required, id, className, ...props }: FormFieldProps): import("react").JSX.Element;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ElementType, HTMLAttributes } from 'react';
|
|
2
|
+
export type GridProps = HTMLAttributes<HTMLElement> & {
|
|
3
|
+
/**
|
|
4
|
+
* Most columns to show. Columns still drop when each would be narrower than `minColumnWidth`,
|
|
5
|
+
* down to one. Omit to fit as many `minColumnWidth` columns as the space allows.
|
|
6
|
+
*/
|
|
7
|
+
columns?: number;
|
|
8
|
+
/** Narrowest a column may get, as a CSS length. Defaults to 16rem, or 10rem with `columns`. */
|
|
9
|
+
minColumnWidth?: string;
|
|
10
|
+
/** Space between cells, in steps of 4px. */
|
|
11
|
+
gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12;
|
|
12
|
+
/** Element to render, such as `ul` or `section`. */
|
|
13
|
+
as?: ElementType;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Responsive CSS grid: fills the width, and collapses to one column on its own when space is narrow.
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { Grid } from '@pravalabs/ui/grid';
|
|
20
|
+
*
|
|
21
|
+
* <Grid columns={3} gap={4}><Card /><Card /><Card /></Grid>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare const Grid: import('react').ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
|
|
25
|
+
/**
|
|
26
|
+
* Most columns to show. Columns still drop when each would be narrower than `minColumnWidth`,
|
|
27
|
+
* down to one. Omit to fit as many `minColumnWidth` columns as the space allows.
|
|
28
|
+
*/
|
|
29
|
+
columns?: number;
|
|
30
|
+
/** Narrowest a column may get, as a CSS length. Defaults to 16rem, or 10rem with `columns`. */
|
|
31
|
+
minColumnWidth?: string;
|
|
32
|
+
/** Space between cells, in steps of 4px. */
|
|
33
|
+
gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12;
|
|
34
|
+
/** Element to render, such as `ul` or `section`. */
|
|
35
|
+
as?: ElementType;
|
|
36
|
+
} & import('react').RefAttributes<HTMLElement>>;
|