sonahang-ui 1.0.0
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 +125 -0
- package/dist/components/Accordion/Accordion.d.ts +36 -0
- package/dist/components/Accordion/AccordionItem.d.ts +15 -0
- package/dist/components/Accordion/accordion.context.d.ts +18 -0
- package/dist/components/Accordion/index.d.ts +5 -0
- package/dist/components/Alert/Alert.d.ts +24 -0
- package/dist/components/Alert/alert.tokens.d.ts +2 -0
- package/dist/components/Alert/index.d.ts +4 -0
- package/dist/components/Avatar/Avatar.d.ts +17 -0
- package/dist/components/Avatar/AvatarGroup.d.ts +12 -0
- package/dist/components/Avatar/avatar.context.d.ts +7 -0
- package/dist/components/Avatar/avatar.tokens.d.ts +2 -0
- package/dist/components/Avatar/getInitials.d.ts +6 -0
- package/dist/components/Avatar/index.d.ts +6 -0
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +19 -0
- package/dist/components/Breadcrumb/BreadcrumbItem.d.ts +25 -0
- package/dist/components/Breadcrumb/breadcrumb.context.d.ts +10 -0
- package/dist/components/Breadcrumb/index.d.ts +4 -0
- package/dist/components/Button/Button.d.ts +20 -0
- package/dist/components/Button/button.tokens.d.ts +4 -0
- package/dist/components/Button/buttonClassNames.d.ts +17 -0
- package/dist/components/Button/index.d.ts +6 -0
- package/dist/components/Checkbox/Checkbox.d.ts +24 -0
- package/dist/components/Checkbox/CheckboxGroup.d.ts +28 -0
- package/dist/components/Checkbox/checkbox.context.d.ts +17 -0
- package/dist/components/Checkbox/index.d.ts +4 -0
- package/dist/components/Chip/Chip.d.ts +21 -0
- package/dist/components/Chip/chip.tokens.d.ts +4 -0
- package/dist/components/Chip/index.d.ts +4 -0
- package/dist/components/CodeBlock/CodeBlock.d.ts +41 -0
- package/dist/components/CodeBlock/dedentCode.d.ts +12 -0
- package/dist/components/CodeBlock/index.d.ts +3 -0
- package/dist/components/Dialog/Dialog.d.ts +70 -0
- package/dist/components/Dialog/dialog.tokens.d.ts +8 -0
- package/dist/components/Dialog/index.d.ts +4 -0
- package/dist/components/Drawer/Drawer.d.ts +72 -0
- package/dist/components/Drawer/drawer.tokens.d.ts +10 -0
- package/dist/components/Drawer/index.d.ts +4 -0
- package/dist/components/Dropdown/Dropdown.d.ts +24 -0
- package/dist/components/Dropdown/DropdownItem.d.ts +16 -0
- package/dist/components/Dropdown/DropdownMenu.d.ts +13 -0
- package/dist/components/Dropdown/DropdownSeparator.d.ts +10 -0
- package/dist/components/Dropdown/DropdownTrigger.d.ts +8 -0
- package/dist/components/Dropdown/dropdown.context.d.ts +24 -0
- package/dist/components/Dropdown/index.d.ts +11 -0
- package/dist/components/EmptyState/EmptyState.d.ts +47 -0
- package/dist/components/EmptyState/index.d.ts +2 -0
- package/dist/components/FileDrop/FileDrop.d.ts +41 -0
- package/dist/components/FileDrop/index.d.ts +3 -0
- package/dist/components/FileDrop/isFileAccepted.d.ts +11 -0
- package/dist/components/Input/Input.d.ts +20 -0
- package/dist/components/Input/index.d.ts +2 -0
- package/dist/components/InputOtp/InputOtp.d.ts +39 -0
- package/dist/components/InputOtp/index.d.ts +4 -0
- package/dist/components/InputOtp/sanitizeOtpValue.d.ts +20 -0
- package/dist/components/MinMaxSlider/MinMaxSlider.d.ts +41 -0
- package/dist/components/MinMaxSlider/index.d.ts +2 -0
- package/dist/components/Pagination/Pagination.d.ts +41 -0
- package/dist/components/Pagination/getPaginationRange.d.ts +25 -0
- package/dist/components/Pagination/index.d.ts +4 -0
- package/dist/components/ProgressBar/ProgressBar.d.ts +34 -0
- package/dist/components/ProgressBar/index.d.ts +4 -0
- package/dist/components/ProgressBar/progressBar.tokens.d.ts +2 -0
- package/dist/components/Radio/Radio.d.ts +18 -0
- package/dist/components/Radio/RadioGroup.d.ts +28 -0
- package/dist/components/Radio/index.d.ts +4 -0
- package/dist/components/Radio/radio.context.d.ts +17 -0
- package/dist/components/RangeSlider/RangeSlider.d.ts +36 -0
- package/dist/components/RangeSlider/index.d.ts +2 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +39 -0
- package/dist/components/SegmentedControl/index.d.ts +2 -0
- package/dist/components/Select/Select.d.ts +39 -0
- package/dist/components/Select/index.d.ts +2 -0
- package/dist/components/Skeleton/Skeleton.d.ts +24 -0
- package/dist/components/Skeleton/index.d.ts +4 -0
- package/dist/components/Skeleton/skeleton.tokens.d.ts +4 -0
- package/dist/components/Spinner/Spinner.d.ts +22 -0
- package/dist/components/Spinner/index.d.ts +4 -0
- package/dist/components/Spinner/spinner.tokens.d.ts +2 -0
- package/dist/components/Stepper/Step.d.ts +20 -0
- package/dist/components/Stepper/Stepper.d.ts +25 -0
- package/dist/components/Stepper/index.d.ts +5 -0
- package/dist/components/Stepper/stepper.context.d.ts +14 -0
- package/dist/components/Switch/Switch.d.ts +22 -0
- package/dist/components/Switch/SwitchGroup.d.ts +30 -0
- package/dist/components/Switch/index.d.ts +4 -0
- package/dist/components/Switch/switch.context.d.ts +19 -0
- package/dist/components/Tabs/Tab.d.ts +10 -0
- package/dist/components/Tabs/TabList.d.ts +20 -0
- package/dist/components/Tabs/TabPanel.d.ts +16 -0
- package/dist/components/Tabs/Tabs.d.ts +22 -0
- package/dist/components/Tabs/index.d.ts +9 -0
- package/dist/components/Tabs/tabs.context.d.ts +24 -0
- package/dist/components/Tag/Tag.d.ts +10 -0
- package/dist/components/Tag/index.d.ts +4 -0
- package/dist/components/Tag/tag.tokens.d.ts +2 -0
- package/dist/components/Text/Text.d.ts +19 -0
- package/dist/components/Text/index.d.ts +4 -0
- package/dist/components/Text/text.tokens.d.ts +8 -0
- package/dist/components/Textarea/Textarea.d.ts +19 -0
- package/dist/components/Textarea/index.d.ts +2 -0
- package/dist/components/Tooltip/Tooltip.d.ts +44 -0
- package/dist/components/Tooltip/index.d.ts +4 -0
- package/dist/components/Tooltip/resolveTooltipPlacement.d.ts +39 -0
- package/dist/index.d.ts +82 -0
- package/dist/internal/bodyScrollLock.d.ts +2 -0
- package/dist/internal/portalInto.d.ts +7 -0
- package/dist/internal/useModalSurface.d.ts +27 -0
- package/dist/sonahang-ui.cjs +7 -0
- package/dist/sonahang-ui.cjs.map +1 -0
- package/dist/sonahang-ui.css +2 -0
- package/dist/sonahang-ui.js +2578 -0
- package/dist/sonahang-ui.js.map +1 -0
- package/dist/tokens/colors.d.ts +167 -0
- package/package.json +101 -0
- package/style.css.d.ts +17 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { DialogHTMLAttributes, ReactNode, RefObject } from "react";
|
|
2
|
+
import type { DialogRole, DialogSize } from "./dialog.tokens";
|
|
3
|
+
import "./Dialog.css";
|
|
4
|
+
export type DialogProps = {
|
|
5
|
+
/**
|
|
6
|
+
* Whether the dialog is showing.
|
|
7
|
+
*
|
|
8
|
+
* Controlled only, deliberately: a modal has no trigger of its own, so it's
|
|
9
|
+
* always opened from somewhere else in the app. An uncontrolled dialog could
|
|
10
|
+
* never be opened.
|
|
11
|
+
*/
|
|
12
|
+
open: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Called when the dialog asks to close — the close button, the backdrop, or
|
|
15
|
+
* Escape. Nothing closes on its own; this has to set `open` to false.
|
|
16
|
+
*/
|
|
17
|
+
onClose: () => void;
|
|
18
|
+
/** Accessible name, rendered as the heading. */
|
|
19
|
+
title: ReactNode;
|
|
20
|
+
/** Optional supporting line under the title. */
|
|
21
|
+
description?: ReactNode;
|
|
22
|
+
/** Body content. Scrolls when it outgrows the dialog. */
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
/** Action row pinned below the body — usually buttons. */
|
|
25
|
+
footer?: ReactNode;
|
|
26
|
+
/** Width of the dialog. Defaults to `md`. */
|
|
27
|
+
size?: DialogSize;
|
|
28
|
+
/** Defaults to `dialog`. Use `alertdialog` for a decision that can't wait. */
|
|
29
|
+
role?: DialogRole;
|
|
30
|
+
/** Whether Escape closes the dialog. Defaults to true. */
|
|
31
|
+
closeOnEscape?: boolean;
|
|
32
|
+
/** Whether clicking the backdrop closes the dialog. Defaults to true. */
|
|
33
|
+
closeOnBackdropClick?: boolean;
|
|
34
|
+
/** Whether to render the × in the header. Defaults to true. */
|
|
35
|
+
showClose?: boolean;
|
|
36
|
+
/** Accessible name for the × button. Defaults to "Close". */
|
|
37
|
+
closeLabel?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Element to focus when the dialog opens. Without it the browser focuses the
|
|
40
|
+
* first focusable thing inside, or anything carrying `autoFocus`.
|
|
41
|
+
*/
|
|
42
|
+
initialFocus?: RefObject<HTMLElement | null>;
|
|
43
|
+
/** Whether to freeze page scrolling while open. Defaults to true. */
|
|
44
|
+
lockScroll?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Renders the dialog elsewhere in the DOM — `true` for `document.body`, or
|
|
47
|
+
* an element to render into. Off by default.
|
|
48
|
+
*
|
|
49
|
+
* Not needed for stacking or clipping: `showModal()` puts the dialog in the
|
|
50
|
+
* top layer, which sits above the whole document whatever the `z-index` and
|
|
51
|
+
* `overflow` of its ancestors. Reach for this when the dialog's *position in
|
|
52
|
+
* the DOM* is the problem — nested inside a `<form>` whose submission its
|
|
53
|
+
* buttons would trigger, inside an element with a native click listener, or
|
|
54
|
+
* under an ancestor that may become `inert` or unmount beneath it.
|
|
55
|
+
*
|
|
56
|
+
* It does not change event propagation in React: a portal moves the DOM
|
|
57
|
+
* node, not the React tree, so a parent component's `onClick` still fires.
|
|
58
|
+
*/
|
|
59
|
+
portal?: boolean | HTMLElement;
|
|
60
|
+
className?: string;
|
|
61
|
+
} & Omit<DialogHTMLAttributes<HTMLDialogElement>, "className" | "title" | "role" | "open" | "onClose" | "onCancel">;
|
|
62
|
+
/**
|
|
63
|
+
* Modal dialog built on the native `<dialog>` element.
|
|
64
|
+
*
|
|
65
|
+
* `showModal()` puts it in the top layer, which is what makes it immune to
|
|
66
|
+
* `z-index` and `overflow: hidden` on anything around it, and brings the focus
|
|
67
|
+
* trap, the inert background and the backdrop with it. None of that is
|
|
68
|
+
* reimplemented here.
|
|
69
|
+
*/
|
|
70
|
+
export declare function Dialog({ open, onClose, title, description, children, footer, size, role, closeOnEscape, closeOnBackdropClick, showClose, closeLabel, initialFocus, lockScroll, portal, className, ...props }: DialogProps): ReactNode;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const dialogSizes: readonly ["sm", "md", "lg", "fullscreen"];
|
|
2
|
+
export type DialogSize = (typeof dialogSizes)[number];
|
|
3
|
+
/**
|
|
4
|
+
* `alertdialog` tells assistive tech the content is urgent and needs a
|
|
5
|
+
* response — reserve it for confirmations and destructive warnings.
|
|
6
|
+
*/
|
|
7
|
+
export declare const dialogRoles: readonly ["dialog", "alertdialog"];
|
|
8
|
+
export type DialogRole = (typeof dialogRoles)[number];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { DialogHTMLAttributes, ReactNode, RefObject } from "react";
|
|
2
|
+
import type { DrawerSide, DrawerSize } from "./drawer.tokens";
|
|
3
|
+
import "./Drawer.css";
|
|
4
|
+
export type DrawerProps = {
|
|
5
|
+
/**
|
|
6
|
+
* Whether the drawer is showing.
|
|
7
|
+
*
|
|
8
|
+
* Controlled only, like `Dialog`: a modal surface has no trigger of its own,
|
|
9
|
+
* so an uncontrolled one could never be opened.
|
|
10
|
+
*/
|
|
11
|
+
open: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Called when the drawer asks to close — the close button, the scrim, or
|
|
14
|
+
* Escape. Nothing closes on its own; this has to set `open` to false.
|
|
15
|
+
*/
|
|
16
|
+
onClose: () => void;
|
|
17
|
+
/** Accessible name, rendered as the heading. */
|
|
18
|
+
title: ReactNode;
|
|
19
|
+
/** Optional supporting line under the title. */
|
|
20
|
+
description?: ReactNode;
|
|
21
|
+
/** Body content. Scrolls when it outgrows the drawer. */
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
/** Action row pinned below the body — usually buttons. */
|
|
24
|
+
footer?: ReactNode;
|
|
25
|
+
/** Edge to anchor to and slide in from. Defaults to `right`. */
|
|
26
|
+
side?: DrawerSide;
|
|
27
|
+
/** Extent along the drawer's own axis. Defaults to `md`. */
|
|
28
|
+
size?: DrawerSize;
|
|
29
|
+
/** Whether Escape closes the drawer. Defaults to true. */
|
|
30
|
+
closeOnEscape?: boolean;
|
|
31
|
+
/** Whether clicking the scrim closes the drawer. Defaults to true. */
|
|
32
|
+
closeOnBackdropClick?: boolean;
|
|
33
|
+
/** Whether to render the × in the header. Defaults to true. */
|
|
34
|
+
showClose?: boolean;
|
|
35
|
+
/** Accessible name for the × button. Defaults to "Close". */
|
|
36
|
+
closeLabel?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Element to focus when the drawer opens. Without it the browser focuses the
|
|
39
|
+
* first focusable thing inside, or anything carrying `autoFocus`.
|
|
40
|
+
*/
|
|
41
|
+
initialFocus?: RefObject<HTMLElement | null>;
|
|
42
|
+
/** Whether to freeze page scrolling while open. Defaults to true. */
|
|
43
|
+
lockScroll?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Renders the drawer elsewhere in the DOM — `true` for `document.body`, or
|
|
46
|
+
* an element to render into. Off by default.
|
|
47
|
+
*
|
|
48
|
+
* Not needed for stacking or clipping: `showModal()` puts the drawer in the
|
|
49
|
+
* top layer, above the whole document whatever the `z-index` and `overflow`
|
|
50
|
+
* of its ancestors. Reach for this when the drawer's *position in the DOM*
|
|
51
|
+
* is the problem — nested inside a `<form>` whose submission its buttons
|
|
52
|
+
* would trigger, inside an element with a native click listener, or under an
|
|
53
|
+
* ancestor that may become `inert` or unmount beneath it.
|
|
54
|
+
*
|
|
55
|
+
* It does not change event propagation in React: a portal moves the DOM
|
|
56
|
+
* node, not the React tree, so a parent component's `onClick` still fires.
|
|
57
|
+
*/
|
|
58
|
+
portal?: boolean | HTMLElement;
|
|
59
|
+
className?: string;
|
|
60
|
+
} & Omit<DialogHTMLAttributes<HTMLDialogElement>, "className" | "title" | "role" | "open" | "onClose" | "onCancel">;
|
|
61
|
+
/**
|
|
62
|
+
* Panel that slides in from an edge of the viewport, over the page.
|
|
63
|
+
*
|
|
64
|
+
* Shares every behaviour with `Dialog` — both are a modal native `<dialog>`,
|
|
65
|
+
* so both get the top layer, the focus trap, the inert background and the
|
|
66
|
+
* scrim from the browser rather than from code here. The difference is purely
|
|
67
|
+
* geometric: a drawer is pinned to one edge and fills its cross axis.
|
|
68
|
+
*
|
|
69
|
+
* There's deliberately no `alertdialog` option. A decision urgent enough for
|
|
70
|
+
* that role shouldn't arrive as a panel sliding in from the side.
|
|
71
|
+
*/
|
|
72
|
+
export declare function Drawer({ open, onClose, title, description, children, footer, side, size, closeOnEscape, closeOnBackdropClick, showClose, closeLabel, initialFocus, lockScroll, portal, className, ...props }: DrawerProps): ReactNode;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Edge the drawer is anchored to and slides in from. */
|
|
2
|
+
export declare const drawerSides: readonly ["left", "right", "top", "bottom"];
|
|
3
|
+
export type DrawerSide = (typeof drawerSides)[number];
|
|
4
|
+
/**
|
|
5
|
+
* Extent along the drawer's own axis — width for `left`/`right`, height for
|
|
6
|
+
* `top`/`bottom`. Always capped at the viewport, so `sm` on a narrow phone is
|
|
7
|
+
* simply full-bleed rather than overflowing.
|
|
8
|
+
*/
|
|
9
|
+
export declare const drawerSizes: readonly ["sm", "md", "lg", "full"];
|
|
10
|
+
export type DrawerSize = (typeof drawerSizes)[number];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import type { DropdownAlign, DropdownPlacement } from "./dropdown.context";
|
|
3
|
+
import "./Dropdown.css";
|
|
4
|
+
export type DropdownProps = {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
/** Open state — makes the component controlled. */
|
|
7
|
+
open?: boolean;
|
|
8
|
+
/** Initial open state when uncontrolled. Defaults to closed. */
|
|
9
|
+
defaultOpen?: boolean;
|
|
10
|
+
/** Fired whenever the menu opens or closes. */
|
|
11
|
+
onOpenChange?: (open: boolean) => void;
|
|
12
|
+
/** Which side of the trigger the menu sits on. Defaults to `bottom`. */
|
|
13
|
+
placement?: DropdownPlacement;
|
|
14
|
+
/** Which edge the menu lines up with. Defaults to `start`. */
|
|
15
|
+
align?: DropdownAlign;
|
|
16
|
+
className?: string;
|
|
17
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "className">;
|
|
18
|
+
/**
|
|
19
|
+
* Root of a menu-button dropdown: a trigger and a popup of commands.
|
|
20
|
+
*
|
|
21
|
+
* This is the *action* menu pattern (`role="menu"`), not a value picker —
|
|
22
|
+
* use `Select` for choosing a value. Nothing here is a form control.
|
|
23
|
+
*/
|
|
24
|
+
export declare function Dropdown({ children, open: controlledOpen, defaultOpen, onOpenChange, placement, align, className, ...props }: DropdownProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import "./Dropdown.css";
|
|
3
|
+
export type DropdownItemProps = {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
/** Runs when the item is chosen. The menu closes afterwards. */
|
|
6
|
+
onSelect?: () => void;
|
|
7
|
+
/** Keeps the menu open after choosing — for items that toggle something. */
|
|
8
|
+
closeOnSelect?: boolean;
|
|
9
|
+
/** Icon rendered before the label. */
|
|
10
|
+
icon?: ReactNode;
|
|
11
|
+
/** Styles the item as a destructive action. */
|
|
12
|
+
destructive?: boolean;
|
|
13
|
+
className?: string;
|
|
14
|
+
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, "className" | "onSelect">;
|
|
15
|
+
/** A single command in the menu. */
|
|
16
|
+
export declare function DropdownItem({ children, onSelect, closeOnSelect, icon, destructive, className, onClick, ...props }: DropdownItemProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import "./Dropdown.css";
|
|
3
|
+
export type DropdownMenuProps = {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "className">;
|
|
7
|
+
/**
|
|
8
|
+
* The popup list of commands.
|
|
9
|
+
*
|
|
10
|
+
* Unmounted while closed rather than hidden, so there's nothing focusable or
|
|
11
|
+
* announceable left behind, and owns the roving focus the menu pattern needs.
|
|
12
|
+
*/
|
|
13
|
+
export declare function DropdownMenu({ children, className, onKeyDown, ...props }: DropdownMenuProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { HTMLAttributes } from "react";
|
|
2
|
+
import "./Dropdown.css";
|
|
3
|
+
export type DropdownSeparatorProps = {
|
|
4
|
+
className?: string;
|
|
5
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "className">;
|
|
6
|
+
/**
|
|
7
|
+
* Divider between groups of commands. Carries `role="separator"` rather than
|
|
8
|
+
* `aria-hidden`, so the grouping is conveyed to assistive tech too.
|
|
9
|
+
*/
|
|
10
|
+
export declare function DropdownSeparator({ className, ...props }: DropdownSeparatorProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import "./Dropdown.css";
|
|
3
|
+
export type DropdownTriggerProps = {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, "className">;
|
|
7
|
+
/** Button that opens the menu. */
|
|
8
|
+
export declare function DropdownTrigger({ children, className, onClick, onKeyDown, ...props }: DropdownTriggerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RefObject } from "react";
|
|
2
|
+
/** Where focus should land when the menu opens, or null to leave it alone. */
|
|
3
|
+
export type DropdownFocusTarget = "first" | "last" | null;
|
|
4
|
+
export type DropdownPlacement = "bottom" | "top";
|
|
5
|
+
export type DropdownAlign = "start" | "end";
|
|
6
|
+
export type DropdownContextValue = {
|
|
7
|
+
isOpen: boolean;
|
|
8
|
+
/** Opens the menu, optionally moving focus to an end of the list. */
|
|
9
|
+
open: (focus?: DropdownFocusTarget) => void;
|
|
10
|
+
/** Closes the menu. Returns focus to the trigger unless told not to. */
|
|
11
|
+
close: (options?: {
|
|
12
|
+
restoreFocus?: boolean;
|
|
13
|
+
}) => void;
|
|
14
|
+
/** Set while the menu is opening, consumed once by the menu on mount. */
|
|
15
|
+
focusOnOpen: DropdownFocusTarget;
|
|
16
|
+
triggerId: string;
|
|
17
|
+
menuId: string;
|
|
18
|
+
triggerRef: RefObject<HTMLButtonElement | null>;
|
|
19
|
+
placement: DropdownPlacement;
|
|
20
|
+
align: DropdownAlign;
|
|
21
|
+
};
|
|
22
|
+
export declare const DropdownContext: import("react").Context<DropdownContextValue | undefined>;
|
|
23
|
+
/** Reads the surrounding `Dropdown`, failing loudly rather than silently. */
|
|
24
|
+
export declare function useDropdownContext(component: string): DropdownContextValue;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { Dropdown } from "./Dropdown";
|
|
2
|
+
export type { DropdownProps } from "./Dropdown";
|
|
3
|
+
export { DropdownTrigger } from "./DropdownTrigger";
|
|
4
|
+
export type { DropdownTriggerProps } from "./DropdownTrigger";
|
|
5
|
+
export { DropdownMenu } from "./DropdownMenu";
|
|
6
|
+
export type { DropdownMenuProps } from "./DropdownMenu";
|
|
7
|
+
export { DropdownItem } from "./DropdownItem";
|
|
8
|
+
export type { DropdownItemProps } from "./DropdownItem";
|
|
9
|
+
export { DropdownSeparator } from "./DropdownSeparator";
|
|
10
|
+
export type { DropdownSeparatorProps } from "./DropdownSeparator";
|
|
11
|
+
export type { DropdownPlacement, DropdownAlign } from "./dropdown.context";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import type { ButtonVariant } from "../Button";
|
|
3
|
+
import "./EmptyState.css";
|
|
4
|
+
export type EmptyStateHeadingLevel = 2 | 3 | 4 | 5 | 6;
|
|
5
|
+
/**
|
|
6
|
+
* A call to action.
|
|
7
|
+
*
|
|
8
|
+
* `href` makes it a link and `onClick` makes it a button — the two are the
|
|
9
|
+
* same offer to the user but very different elements, and picking the wrong
|
|
10
|
+
* one costs middle-click, right-click and keyboard behaviour.
|
|
11
|
+
*/
|
|
12
|
+
export type EmptyStateAction = {
|
|
13
|
+
label: ReactNode;
|
|
14
|
+
/** Renders an `<a>`. Without it the action is a `<button>`. */
|
|
15
|
+
href?: string;
|
|
16
|
+
onClick?: () => void;
|
|
17
|
+
/** Icon rendered before the label. */
|
|
18
|
+
icon?: ReactNode;
|
|
19
|
+
/** Overrides the default styling — `primary` for the main action. */
|
|
20
|
+
variant?: ButtonVariant;
|
|
21
|
+
target?: string;
|
|
22
|
+
rel?: string;
|
|
23
|
+
};
|
|
24
|
+
export type EmptyStateProps = {
|
|
25
|
+
/** What isn't here. Rendered as a heading. */
|
|
26
|
+
title: ReactNode;
|
|
27
|
+
/** A line under the title, usually explaining what to do about it. */
|
|
28
|
+
description?: ReactNode;
|
|
29
|
+
/**
|
|
30
|
+
* Replaces the default mark, or removes it entirely with `false`. Sized by
|
|
31
|
+
* the component, so a bare `<svg>` is fine.
|
|
32
|
+
*/
|
|
33
|
+
icon?: ReactNode | false;
|
|
34
|
+
/** The main call to action. */
|
|
35
|
+
action?: EmptyStateAction;
|
|
36
|
+
/** A quieter second option beside it. */
|
|
37
|
+
secondaryAction?: EmptyStateAction;
|
|
38
|
+
/** Heading rank for the title. Defaults to `3`. */
|
|
39
|
+
headingLevel?: EmptyStateHeadingLevel;
|
|
40
|
+
/** `sm` for an empty state inside a card or panel. Defaults to `md`. */
|
|
41
|
+
size?: "sm" | "md";
|
|
42
|
+
/** Anything extra, rendered below the actions. */
|
|
43
|
+
children?: ReactNode;
|
|
44
|
+
className?: string;
|
|
45
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "className" | "title" | "children">;
|
|
46
|
+
/** Placeholder for a space with nothing in it yet, or nothing left in it. */
|
|
47
|
+
export declare function EmptyState({ title, description, icon, action, secondaryAction, headingLevel, size, children, className, ...props }: EmptyStateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import "./FileDrop.css";
|
|
3
|
+
export type FileDropProps = {
|
|
4
|
+
/** Visible label for the field. */
|
|
5
|
+
label?: ReactNode;
|
|
6
|
+
/** Hint shown below the drop zone. Replaced by `error` when that's set. */
|
|
7
|
+
helperText?: ReactNode;
|
|
8
|
+
/** Validation message. Its presence also marks the field invalid. */
|
|
9
|
+
error?: ReactNode;
|
|
10
|
+
/** Prompt inside the drop zone. */
|
|
11
|
+
placeholder?: ReactNode;
|
|
12
|
+
/** Allowed types, same syntax as the `accept` attribute: ".pdf,image/*". */
|
|
13
|
+
accept?: string;
|
|
14
|
+
/** Allow picking more than one file. */
|
|
15
|
+
multiple?: boolean;
|
|
16
|
+
/** Selected files — makes the component controlled. */
|
|
17
|
+
value?: File[];
|
|
18
|
+
/** Initial files when uncontrolled. */
|
|
19
|
+
defaultValue?: File[];
|
|
20
|
+
/** Fired with the full list of selected files. */
|
|
21
|
+
onChange?: (files: File[]) => void;
|
|
22
|
+
/** Fired with files rejected by `accept`, so they're never dropped silently. */
|
|
23
|
+
onReject?: (files: File[]) => void;
|
|
24
|
+
/** Hides the list of selected files. */
|
|
25
|
+
hideFileList?: boolean;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
name?: string;
|
|
28
|
+
/** Accessible name when there's no visible `label`. */
|
|
29
|
+
"aria-label"?: string;
|
|
30
|
+
/** Class for the wrapper. Use `inputClassName` for the file input. */
|
|
31
|
+
className?: string;
|
|
32
|
+
inputClassName?: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* File picker that accepts both a click and a drag-and-drop.
|
|
36
|
+
*
|
|
37
|
+
* A real `<input type="file">` wrapped in a `<label>`, so clicking anywhere in
|
|
38
|
+
* the zone opens the picker and the control stays keyboard-operable without
|
|
39
|
+
* any JavaScript. The zone itself is painted alongside it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function FileDrop({ label, helperText, error, placeholder, accept, multiple, value, defaultValue, onChange, onReject, hideFileList, disabled, name, "aria-label": ariaLabel, className, inputClassName, }: FileDropProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matches a file against an `accept` string (the same syntax as the `accept`
|
|
3
|
+
* attribute: ".pdf,image/*,text/csv").
|
|
4
|
+
*
|
|
5
|
+
* The browser applies `accept` to the file picker, but **not** to drag-and-drop
|
|
6
|
+
* — dropped files arrive unfiltered — so this runs on both paths to keep them
|
|
7
|
+
* behaving the same.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isFileAccepted(file: File, accept?: string): boolean;
|
|
10
|
+
/** "1.4 MB" — for listing the files a user has picked. */
|
|
11
|
+
export declare function formatFileSize(bytes: number): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { InputHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import "./Input.css";
|
|
3
|
+
export type InputProps = {
|
|
4
|
+
/** Visible label, associated with the input via `htmlFor`/`id`. */
|
|
5
|
+
label?: ReactNode;
|
|
6
|
+
/** Hint shown below the input. Replaced by `error` when that's set. */
|
|
7
|
+
helperText?: ReactNode;
|
|
8
|
+
/** Validation message. Its presence also marks the input invalid. */
|
|
9
|
+
error?: ReactNode;
|
|
10
|
+
/** Decorative icon rendered inside the field. See `iconPosition`. */
|
|
11
|
+
icon?: ReactNode;
|
|
12
|
+
/** Which side `icon` sits on. Defaults to `left`. */
|
|
13
|
+
iconPosition?: "left" | "right";
|
|
14
|
+
/** Class for the wrapper element. Use `inputClassName` for the input itself. */
|
|
15
|
+
className?: string;
|
|
16
|
+
/** Class for the underlying `<input>`. */
|
|
17
|
+
inputClassName?: string;
|
|
18
|
+
} & Omit<InputHTMLAttributes<HTMLInputElement>, "className">;
|
|
19
|
+
/** Text input with an associated label, helper text, error state, and optional icon. */
|
|
20
|
+
export declare function Input({ label, helperText, error, icon, iconPosition, className, inputClassName, id, required, disabled, "aria-describedby": ariaDescribedBy, ...props }: InputProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { InputHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import type { OtpType } from "./sanitizeOtpValue";
|
|
3
|
+
import "./InputOtp.css";
|
|
4
|
+
export type InputOtpProps = {
|
|
5
|
+
/** Number of characters in the code. Defaults to 6. */
|
|
6
|
+
length?: number;
|
|
7
|
+
/** The code — makes the component controlled. */
|
|
8
|
+
value?: string;
|
|
9
|
+
/** Starting code when uncontrolled. */
|
|
10
|
+
defaultValue?: string;
|
|
11
|
+
/** Fired with the whole code whenever it changes. */
|
|
12
|
+
onChange?: (value: string) => void;
|
|
13
|
+
/** Fired once, when the last character lands. */
|
|
14
|
+
onComplete?: (value: string) => void;
|
|
15
|
+
/** Which characters are accepted. Defaults to `numeric`. */
|
|
16
|
+
type?: OtpType;
|
|
17
|
+
/** Hides the characters behind dots, for codes that are secrets. */
|
|
18
|
+
mask?: boolean;
|
|
19
|
+
/** Draws a separator every N characters — 3 gives `123 456`. */
|
|
20
|
+
groupSize?: number;
|
|
21
|
+
/** Visible label, associated with the field via `htmlFor`/`id`. */
|
|
22
|
+
label?: ReactNode;
|
|
23
|
+
/** Hint shown below the field. Replaced by `error` when that's set. */
|
|
24
|
+
helperText?: ReactNode;
|
|
25
|
+
/** Validation message. Its presence also marks the field invalid. */
|
|
26
|
+
error?: ReactNode;
|
|
27
|
+
/** Class for the wrapper element. */
|
|
28
|
+
className?: string;
|
|
29
|
+
} & Omit<InputHTMLAttributes<HTMLInputElement>, "className" | "value" | "defaultValue" | "onChange" | "type" | "maxLength" | "size">;
|
|
30
|
+
/**
|
|
31
|
+
* One-time-code field: a row of boxes backed by a single text input.
|
|
32
|
+
*
|
|
33
|
+
* The boxes are presentation. The value lives in one real `<input>` covering
|
|
34
|
+
* them, which is what makes `autocomplete="one-time-code"`, pasting, undo,
|
|
35
|
+
* password managers and screen-reader labelling work without being rebuilt —
|
|
36
|
+
* a row of six separate inputs is six unlabelled fields to assistive tech, and
|
|
37
|
+
* reimplements a text field along the way.
|
|
38
|
+
*/
|
|
39
|
+
export declare function InputOtp({ length, value: controlledValue, defaultValue, onChange, onComplete, type, mask, groupSize, label, helperText, error, className, id, required, disabled, "aria-describedby": ariaDescribedBy, onFocus, onBlur, onSelect, onClick, ...props }: InputOtpProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const otpTypes: readonly ["numeric", "alphanumeric"];
|
|
2
|
+
export type OtpType = (typeof otpTypes)[number];
|
|
3
|
+
export type SanitizeOtpValueOptions = {
|
|
4
|
+
/** Number of characters the code holds. */
|
|
5
|
+
length: number;
|
|
6
|
+
/** Which characters survive. Defaults to `numeric`. */
|
|
7
|
+
type?: OtpType;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Keeps only the characters an OTP field accepts, capped at its length.
|
|
11
|
+
*
|
|
12
|
+
* Runs over everything that reaches the field — typing, pasting, and the
|
|
13
|
+
* controlled `value` — so a pasted "123-456", a code copied with trailing
|
|
14
|
+
* whitespace, and a stray letter all land as the same clean string.
|
|
15
|
+
*
|
|
16
|
+
* Case is preserved for `alphanumeric`: upper-casing here would quietly
|
|
17
|
+
* change what the user submits, and whether a code is case-sensitive is the
|
|
18
|
+
* server's business, not this component's.
|
|
19
|
+
*/
|
|
20
|
+
export declare function sanitizeOtpValue(raw: string, { length, type }: SanitizeOtpValueOptions): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import "./MinMaxSlider.css";
|
|
3
|
+
export type MinMaxValue = [number, number];
|
|
4
|
+
export type MinMaxSliderProps = {
|
|
5
|
+
/** Visible label for the pair. Provide this or `aria-label`. */
|
|
6
|
+
label?: ReactNode;
|
|
7
|
+
/** Hint shown below the slider. Replaced by `error` when that's set. */
|
|
8
|
+
helperText?: ReactNode;
|
|
9
|
+
/** Validation message. Its presence also marks the slider invalid. */
|
|
10
|
+
error?: ReactNode;
|
|
11
|
+
/** Current `[from, to]` — makes the slider controlled. */
|
|
12
|
+
value?: MinMaxValue;
|
|
13
|
+
/** Initial `[from, to]` when uncontrolled. Defaults to `[min, max]`. */
|
|
14
|
+
defaultValue?: MinMaxValue;
|
|
15
|
+
/** Fired with the new `[from, to]`. */
|
|
16
|
+
onChange?: (value: MinMaxValue) => void;
|
|
17
|
+
min?: number;
|
|
18
|
+
max?: number;
|
|
19
|
+
step?: number;
|
|
20
|
+
/** Smallest allowed distance between the two thumbs. Defaults to `0`. */
|
|
21
|
+
minGap?: number;
|
|
22
|
+
/** Shows the current range beside the label. */
|
|
23
|
+
showValue?: boolean;
|
|
24
|
+
/** Formats each end for display and for `aria-valuetext`. */
|
|
25
|
+
formatValue?: (value: number) => string;
|
|
26
|
+
/** Base field name. The thumbs submit as `${name}-min` and `${name}-max`. */
|
|
27
|
+
name?: string;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/** Accessible name when there's no visible `label`. */
|
|
30
|
+
"aria-label"?: string;
|
|
31
|
+
className?: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Two-thumb slider for picking a from–to range.
|
|
35
|
+
*
|
|
36
|
+
* Built from two overlaid native `<input type="range">` elements rather than a
|
|
37
|
+
* custom widget, so each thumb keeps real `role="slider"` semantics, keyboard
|
|
38
|
+
* stepping, and value announcements. The visible track and fill are decorative
|
|
39
|
+
* spans; the inputs' own tracks are transparent.
|
|
40
|
+
*/
|
|
41
|
+
export declare function MinMaxSlider({ label, helperText, error, value, defaultValue, onChange, min, max, step, minGap, showValue, formatValue, name, disabled, "aria-label": ariaLabel, className, }: MinMaxSliderProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { HTMLAttributes } from "react";
|
|
2
|
+
import "./Pagination.css";
|
|
3
|
+
export type PaginationProps = {
|
|
4
|
+
/** Total number of pages. */
|
|
5
|
+
count: number;
|
|
6
|
+
/** Current page, 1-indexed — makes the component controlled. */
|
|
7
|
+
page?: number;
|
|
8
|
+
/** Initial page when uncontrolled. Defaults to `1`. */
|
|
9
|
+
defaultPage?: number;
|
|
10
|
+
/** Fired with the newly selected page. */
|
|
11
|
+
onChange?: (page: number) => void;
|
|
12
|
+
/** Pages to show either side of the current one. Defaults to `1`. */
|
|
13
|
+
siblingCount?: number;
|
|
14
|
+
/** Pages to always show at each end. Defaults to `1`. */
|
|
15
|
+
boundaryCount?: number;
|
|
16
|
+
/** Adds jump-to-first and jump-to-last buttons. */
|
|
17
|
+
showFirstLast?: boolean;
|
|
18
|
+
/** Hides the previous/next buttons. */
|
|
19
|
+
hidePrevNext?: boolean;
|
|
20
|
+
/** Disables every control. */
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
/** Labels for the navigation buttons and each page. */
|
|
23
|
+
labels?: {
|
|
24
|
+
first?: string;
|
|
25
|
+
previous?: string;
|
|
26
|
+
next?: string;
|
|
27
|
+
last?: string;
|
|
28
|
+
page?: (page: number) => string;
|
|
29
|
+
};
|
|
30
|
+
/** Accessible name for the landmark. Defaults to "Pagination". */
|
|
31
|
+
"aria-label"?: string;
|
|
32
|
+
className?: string;
|
|
33
|
+
} & Omit<HTMLAttributes<HTMLElement>, "className" | "onChange">;
|
|
34
|
+
/**
|
|
35
|
+
* Page navigation.
|
|
36
|
+
*
|
|
37
|
+
* A `nav` landmark around a list of page buttons, with runs of hidden pages
|
|
38
|
+
* collapsed into gaps. The gaps are inert text, not buttons — there's nothing
|
|
39
|
+
* to activate, so they stay out of the tab order and the accessibility tree.
|
|
40
|
+
*/
|
|
41
|
+
export declare function Pagination({ count, page, defaultPage, onChange, siblingCount, boundaryCount, showFirstLast, hidePrevNext, disabled, labels, "aria-label": ariaLabel, className, ...props }: PaginationProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** A page number, or a gap standing in for pages that were left out. */
|
|
2
|
+
export type PaginationItem = number | "ellipsis";
|
|
3
|
+
export type PaginationRangeOptions = {
|
|
4
|
+
/** Current page, 1-indexed. */
|
|
5
|
+
page: number;
|
|
6
|
+
/** Total number of pages. */
|
|
7
|
+
count: number;
|
|
8
|
+
/** Pages to show either side of the current one. */
|
|
9
|
+
siblingCount?: number;
|
|
10
|
+
/** Pages to always show at each end. */
|
|
11
|
+
boundaryCount?: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Builds the visible page list, collapsing runs of hidden pages into gaps.
|
|
15
|
+
*
|
|
16
|
+
* The width is deliberately stable — a given `siblingCount`/`boundaryCount`
|
|
17
|
+
* yields the same number of slots regardless of the current page, so the
|
|
18
|
+
* control doesn't resize as you page through. That's why the sibling window
|
|
19
|
+
* is clamped rather than simply centred on the current page.
|
|
20
|
+
*
|
|
21
|
+
* A gap is only used when it actually saves space: standing in for a single
|
|
22
|
+
* hidden page would take as much room as the page itself, so that page is
|
|
23
|
+
* shown instead.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getPaginationRange({ page, count, siblingCount, boundaryCount, }: PaginationRangeOptions): PaginationItem[];
|