@arcfusionz/arc-primitive-ui 0.1.0 → 0.2.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/dist/components/AILoader/AILoader.d.ts +32 -0
- package/dist/components/AILoader/AILoader.js +157 -0
- package/dist/components/AILoader/index.d.ts +2 -0
- package/dist/components/AILoader/index.js +2 -0
- package/dist/components/Accordion/Accordion.d.ts +96 -0
- package/dist/components/Accordion/Accordion.js +149 -0
- package/dist/components/Accordion/index.d.ts +2 -0
- package/dist/components/Accordion/index.js +2 -0
- package/dist/components/Avatar/Avatar.d.ts +152 -0
- package/dist/components/Avatar/Avatar.js +216 -0
- package/dist/components/Avatar/index.d.ts +2 -0
- package/dist/components/Avatar/index.js +2 -0
- package/dist/components/Badge/Badge.d.ts +87 -0
- package/dist/components/Badge/Badge.js +118 -0
- package/dist/components/Badge/index.d.ts +2 -0
- package/dist/components/Badge/index.js +2 -0
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +109 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +182 -0
- package/dist/components/Breadcrumb/index.d.ts +2 -0
- package/dist/components/Breadcrumb/index.js +2 -0
- package/dist/components/Button/Button.d.ts +57 -0
- package/dist/components/Button/Button.js +177 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/Button/index.js +2 -0
- package/dist/components/Calendar/Calendar.d.ts +140 -0
- package/dist/components/Calendar/Calendar.js +468 -0
- package/dist/components/Calendar/index.d.ts +2 -0
- package/dist/components/Calendar/index.js +2 -0
- package/dist/components/Checkbox/Checkbox.d.ts +60 -0
- package/dist/components/Checkbox/Checkbox.js +129 -0
- package/dist/components/Checkbox/index.d.ts +2 -0
- package/dist/components/Checkbox/index.js +2 -0
- package/dist/components/Combobox/Combobox.d.ts +251 -0
- package/dist/components/Combobox/Combobox.js +354 -0
- package/dist/components/Combobox/index.d.ts +2 -0
- package/dist/components/Combobox/index.js +2 -0
- package/dist/components/ContextMenu/ContextMenu.d.ts +129 -0
- package/dist/components/ContextMenu/ContextMenu.js +93 -0
- package/dist/components/ContextMenu/index.d.ts +2 -0
- package/dist/components/ContextMenu/index.js +2 -0
- package/dist/components/DatePicker/DatePicker.d.ts +109 -0
- package/dist/components/DatePicker/DatePicker.js +145 -0
- package/dist/components/DatePicker/index.d.ts +2 -0
- package/dist/components/DatePicker/index.js +2 -0
- package/dist/components/DateRangePicker/DateRangePicker.d.ts +107 -0
- package/dist/components/DateRangePicker/DateRangePicker.js +161 -0
- package/dist/components/DateRangePicker/index.d.ts +2 -0
- package/dist/components/DateRangePicker/index.js +2 -0
- package/dist/components/Dialog/Dialog.d.ts +112 -0
- package/dist/components/Dialog/Dialog.js +141 -0
- package/dist/components/Dialog/index.d.ts +2 -0
- package/dist/components/Dialog/index.js +2 -0
- package/dist/components/Drawer/Drawer.d.ts +188 -0
- package/dist/components/Drawer/Drawer.js +268 -0
- package/dist/components/Drawer/index.d.ts +2 -0
- package/dist/components/Drawer/index.js +2 -0
- package/dist/components/Field/Field.d.ts +123 -0
- package/dist/components/Field/Field.js +241 -0
- package/dist/components/Field/FieldContext.d.ts +43 -0
- package/dist/components/Field/FieldContext.js +28 -0
- package/dist/components/Field/index.d.ts +3 -0
- package/dist/components/Field/index.js +3 -0
- package/dist/components/Fieldset/Fieldset.d.ts +43 -0
- package/dist/components/Fieldset/Fieldset.js +48 -0
- package/dist/components/Fieldset/index.d.ts +2 -0
- package/dist/components/Fieldset/index.js +2 -0
- package/dist/components/Form/Form.d.ts +54 -0
- package/dist/components/Form/Form.js +57 -0
- package/dist/components/Form/index.d.ts +2 -0
- package/dist/components/Form/index.js +2 -0
- package/dist/components/Input/Input.d.ts +64 -0
- package/dist/components/Input/Input.js +111 -0
- package/dist/components/Input/index.d.ts +2 -0
- package/dist/components/Input/index.js +2 -0
- package/dist/components/Menu/Menu.d.ts +212 -0
- package/dist/components/Menu/Menu.js +255 -0
- package/dist/components/Menu/index.d.ts +2 -0
- package/dist/components/Menu/index.js +2 -0
- package/dist/components/Popover/Popover.d.ts +122 -0
- package/dist/components/Popover/Popover.js +116 -0
- package/dist/components/Popover/index.d.ts +2 -0
- package/dist/components/Popover/index.js +2 -0
- package/dist/components/Progress/Progress.d.ts +87 -0
- package/dist/components/Progress/Progress.js +73 -0
- package/dist/components/Progress/index.d.ts +2 -0
- package/dist/components/Progress/index.js +2 -0
- package/dist/components/Radio/Radio.d.ts +65 -0
- package/dist/components/Radio/Radio.js +93 -0
- package/dist/components/Radio/index.d.ts +2 -0
- package/dist/components/Radio/index.js +2 -0
- package/dist/components/Select/Select.d.ts +136 -0
- package/dist/components/Select/Select.js +219 -0
- package/dist/components/Select/index.d.ts +2 -0
- package/dist/components/Select/index.js +2 -0
- package/dist/components/Skeleton/Skeleton.d.ts +39 -0
- package/dist/components/Skeleton/Skeleton.js +44 -0
- package/dist/components/Skeleton/index.d.ts +2 -0
- package/dist/components/Skeleton/index.js +2 -0
- package/dist/components/Stepper/Stepper.d.ts +161 -0
- package/dist/components/Stepper/Stepper.js +344 -0
- package/dist/components/Stepper/index.d.ts +2 -0
- package/dist/components/Stepper/index.js +2 -0
- package/dist/components/Switch/Switch.d.ts +56 -0
- package/dist/components/Switch/Switch.js +87 -0
- package/dist/components/Switch/index.d.ts +2 -0
- package/dist/components/Switch/index.js +2 -0
- package/dist/components/Table/Table.d.ts +116 -0
- package/dist/components/Table/Table.js +143 -0
- package/dist/components/Table/index.d.ts +2 -0
- package/dist/components/Table/index.js +2 -0
- package/dist/components/Tabs/Tabs.d.ts +116 -0
- package/dist/components/Tabs/Tabs.js +158 -0
- package/dist/components/Tabs/index.d.ts +2 -0
- package/dist/components/Tabs/index.js +2 -0
- package/dist/components/Timeline/Timeline.d.ts +137 -0
- package/dist/components/Timeline/Timeline.js +243 -0
- package/dist/components/Timeline/index.d.ts +2 -0
- package/dist/components/Timeline/index.js +2 -0
- package/dist/components/Toast/Toast.d.ts +135 -0
- package/dist/components/Toast/Toast.js +314 -0
- package/dist/components/Toast/index.d.ts +2 -0
- package/dist/components/Toast/index.js +2 -0
- package/dist/components/Tooltip/Tooltip.d.ts +104 -0
- package/dist/components/Tooltip/Tooltip.js +95 -0
- package/dist/components/Tooltip/index.d.ts +2 -0
- package/dist/components/Tooltip/index.js +2 -0
- package/dist/components/Typography/Typography.d.ts +38 -0
- package/dist/components/Typography/Typography.js +53 -0
- package/dist/components/Typography/index.d.ts +2 -0
- package/dist/components/Typography/index.js +2 -0
- package/dist/index.d.ts +66 -3398
- package/dist/index.js +34 -5343
- package/dist/lib/cn.d.ts +6 -0
- package/dist/lib/cn.js +9 -0
- package/package.json +6 -2
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
//#region src/components/Breadcrumb/Breadcrumb.tsx
|
|
6
|
+
function ChevronRightIcon(props) {
|
|
7
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
8
|
+
viewBox: "0 0 24 24",
|
|
9
|
+
fill: "none",
|
|
10
|
+
stroke: "currentColor",
|
|
11
|
+
strokeWidth: 2,
|
|
12
|
+
strokeLinecap: "round",
|
|
13
|
+
strokeLinejoin: "round",
|
|
14
|
+
...props,
|
|
15
|
+
children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function EllipsisIcon(props) {
|
|
19
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
20
|
+
viewBox: "0 0 24 24",
|
|
21
|
+
fill: "none",
|
|
22
|
+
stroke: "currentColor",
|
|
23
|
+
strokeWidth: 2,
|
|
24
|
+
strokeLinecap: "round",
|
|
25
|
+
strokeLinejoin: "round",
|
|
26
|
+
...props,
|
|
27
|
+
children: [
|
|
28
|
+
/* @__PURE__ */ jsx("circle", {
|
|
29
|
+
cx: "12",
|
|
30
|
+
cy: "12",
|
|
31
|
+
r: "1"
|
|
32
|
+
}),
|
|
33
|
+
/* @__PURE__ */ jsx("circle", {
|
|
34
|
+
cx: "19",
|
|
35
|
+
cy: "12",
|
|
36
|
+
r: "1"
|
|
37
|
+
}),
|
|
38
|
+
/* @__PURE__ */ jsx("circle", {
|
|
39
|
+
cx: "5",
|
|
40
|
+
cy: "12",
|
|
41
|
+
r: "1"
|
|
42
|
+
})
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const listClasses = "flex flex-wrap items-center gap-1.5 break-words font-sans text-sm text-muted-foreground sm:gap-2.5";
|
|
47
|
+
const itemClasses = "inline-flex items-center gap-1.5";
|
|
48
|
+
const linkClasses = "inline-flex items-center gap-1.5 rounded-md transition-colors duration-150 hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring aria-[current=page]:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5";
|
|
49
|
+
const pageClasses = "font-normal text-foreground";
|
|
50
|
+
const separatorClasses = "select-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5";
|
|
51
|
+
const ellipsisClasses = "inline-flex items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4";
|
|
52
|
+
/**
|
|
53
|
+
* Navigation landmark that holds the trail. It defaults to
|
|
54
|
+
* `aria-label="Breadcrumb"`; pass a localized `aria-label` (or
|
|
55
|
+
* `aria-labelledby`) when the page language isn't English.
|
|
56
|
+
*/
|
|
57
|
+
const Breadcrumb = forwardRef(({ render, className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...rest }, ref) => useRender({
|
|
58
|
+
defaultTagName: "nav",
|
|
59
|
+
render,
|
|
60
|
+
ref,
|
|
61
|
+
props: {
|
|
62
|
+
"aria-label": ariaLabel ?? (ariaLabelledBy == null ? "Breadcrumb" : void 0),
|
|
63
|
+
"aria-labelledby": ariaLabelledBy,
|
|
64
|
+
...rest,
|
|
65
|
+
className
|
|
66
|
+
}
|
|
67
|
+
}));
|
|
68
|
+
Breadcrumb.displayName = "Breadcrumb";
|
|
69
|
+
/**
|
|
70
|
+
* Ordered list of crumbs. It wraps onto new lines on narrow viewports; cap
|
|
71
|
+
* individual crumbs with a truncation `className` instead of letting the
|
|
72
|
+
* whole trail overflow.
|
|
73
|
+
*/
|
|
74
|
+
const BreadcrumbList = forwardRef(({ render, className, ...rest }, ref) => useRender({
|
|
75
|
+
defaultTagName: "ol",
|
|
76
|
+
render,
|
|
77
|
+
ref,
|
|
78
|
+
props: {
|
|
79
|
+
...rest,
|
|
80
|
+
className: cn(listClasses, className)
|
|
81
|
+
}
|
|
82
|
+
}));
|
|
83
|
+
BreadcrumbList.displayName = "BreadcrumbList";
|
|
84
|
+
/** One entry in the trail: wraps a link, the current page, or a composed control. */
|
|
85
|
+
const BreadcrumbItem = forwardRef(({ render, className, ...rest }, ref) => useRender({
|
|
86
|
+
defaultTagName: "li",
|
|
87
|
+
render,
|
|
88
|
+
ref,
|
|
89
|
+
props: {
|
|
90
|
+
...rest,
|
|
91
|
+
className: cn(itemClasses, className)
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
BreadcrumbItem.displayName = "BreadcrumbItem";
|
|
95
|
+
/**
|
|
96
|
+
* Class list for an element styled as a breadcrumb link.
|
|
97
|
+
*
|
|
98
|
+
* Use it to give non-anchor crumbs the same resting/hover/focus treatment —
|
|
99
|
+
* e.g. a Menu trigger button that reveals collapsed levels:
|
|
100
|
+
*
|
|
101
|
+
* <MenuTrigger
|
|
102
|
+
* render={<button aria-label="Show hidden levels" className={breadcrumbLinkVariants()} />}
|
|
103
|
+
* >
|
|
104
|
+
* <BreadcrumbEllipsis />
|
|
105
|
+
* </MenuTrigger>
|
|
106
|
+
*/
|
|
107
|
+
function breadcrumbLinkVariants({ className } = {}) {
|
|
108
|
+
return cn(linkClasses, className);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Ancestor link in the trail. Inline text links are exempt from the WCAG
|
|
112
|
+
* 2.5.8 target-size floor, but keep the list's default gap so adjacent
|
|
113
|
+
* targets stay distinguishable on touch screens. For the APG variant where
|
|
114
|
+
* the current page stays a link, add `aria-current="page"` — the recipe
|
|
115
|
+
* restyles it to match `BreadcrumbPage`.
|
|
116
|
+
*/
|
|
117
|
+
const BreadcrumbLink = forwardRef(({ render, className, ...rest }, ref) => useRender({
|
|
118
|
+
defaultTagName: "a",
|
|
119
|
+
render,
|
|
120
|
+
ref,
|
|
121
|
+
props: {
|
|
122
|
+
...rest,
|
|
123
|
+
className: cn(linkClasses, className)
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
BreadcrumbLink.displayName = "BreadcrumbLink";
|
|
127
|
+
/**
|
|
128
|
+
* The current page, rendered as plain text with `aria-current="page"` — an
|
|
129
|
+
* honest `span`, not a disabled fake link. Use `BreadcrumbLink` with
|
|
130
|
+
* `aria-current="page"` instead when the current page must stay navigable.
|
|
131
|
+
*/
|
|
132
|
+
const BreadcrumbPage = forwardRef(({ render, className, ...rest }, ref) => useRender({
|
|
133
|
+
defaultTagName: "span",
|
|
134
|
+
render,
|
|
135
|
+
ref,
|
|
136
|
+
props: {
|
|
137
|
+
"aria-current": "page",
|
|
138
|
+
...rest,
|
|
139
|
+
className: cn(pageClasses, className)
|
|
140
|
+
}
|
|
141
|
+
}));
|
|
142
|
+
BreadcrumbPage.displayName = "BreadcrumbPage";
|
|
143
|
+
/**
|
|
144
|
+
* Visual divider between crumbs. It is `aria-hidden` with
|
|
145
|
+
* `role="presentation"`, so screen readers hear only the crumbs and the
|
|
146
|
+
* list's item count — never the glyphs.
|
|
147
|
+
*/
|
|
148
|
+
const BreadcrumbSeparator = forwardRef(({ render, className, children = /* @__PURE__ */ jsx(ChevronRightIcon, {}), ...rest }, ref) => useRender({
|
|
149
|
+
defaultTagName: "li",
|
|
150
|
+
render,
|
|
151
|
+
ref,
|
|
152
|
+
props: {
|
|
153
|
+
role: "presentation",
|
|
154
|
+
"aria-hidden": "true",
|
|
155
|
+
...rest,
|
|
156
|
+
children,
|
|
157
|
+
className: cn(separatorClasses, className)
|
|
158
|
+
}
|
|
159
|
+
}));
|
|
160
|
+
BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
|
|
161
|
+
/**
|
|
162
|
+
* Marker for collapsed levels in a deep trail. It is decorative
|
|
163
|
+
* (`aria-hidden`); when the hidden levels must stay reachable, wrap it in a
|
|
164
|
+
* labelled trigger — e.g. a Menu trigger styled with
|
|
165
|
+
* `breadcrumbLinkVariants()` — so the control, not the glyph, carries the
|
|
166
|
+
* accessible name.
|
|
167
|
+
*/
|
|
168
|
+
const BreadcrumbEllipsis = forwardRef(({ render, className, children = /* @__PURE__ */ jsx(EllipsisIcon, {}), ...rest }, ref) => useRender({
|
|
169
|
+
defaultTagName: "span",
|
|
170
|
+
render,
|
|
171
|
+
ref,
|
|
172
|
+
props: {
|
|
173
|
+
role: "presentation",
|
|
174
|
+
"aria-hidden": "true",
|
|
175
|
+
...rest,
|
|
176
|
+
children,
|
|
177
|
+
className: cn(ellipsisClasses, className)
|
|
178
|
+
}
|
|
179
|
+
}));
|
|
180
|
+
BreadcrumbEllipsis.displayName = "BreadcrumbEllipsis";
|
|
181
|
+
//#endregion
|
|
182
|
+
export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, breadcrumbLinkVariants };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Breadcrumb, BreadcrumbEllipsis, BreadcrumbEllipsisProps, BreadcrumbItem, BreadcrumbItemProps, BreadcrumbLink, BreadcrumbLinkProps, BreadcrumbLinkVariantsOptions, BreadcrumbList, BreadcrumbListProps, BreadcrumbPage, BreadcrumbPageProps, BreadcrumbProps, BreadcrumbSeparator, BreadcrumbSeparatorProps, breadcrumbLinkVariants } from "./Breadcrumb.js";
|
|
2
|
+
export { Breadcrumb, BreadcrumbEllipsis, type BreadcrumbEllipsisProps, BreadcrumbItem, type BreadcrumbItemProps, BreadcrumbLink, type BreadcrumbLinkProps, type BreadcrumbLinkVariantsOptions, BreadcrumbList, type BreadcrumbListProps, BreadcrumbPage, type BreadcrumbPageProps, type BreadcrumbProps, BreadcrumbSeparator, type BreadcrumbSeparatorProps, breadcrumbLinkVariants };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, breadcrumbLinkVariants } from "./Breadcrumb.js";
|
|
2
|
+
export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, breadcrumbLinkVariants };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
|
+
import { Button } from "@base-ui/react/button";
|
|
3
|
+
//#region src/components/Button/Button.d.ts
|
|
4
|
+
type ButtonVariant = "primary" | "secondary" | "outline" | "ghost" | "destructive" | "link";
|
|
5
|
+
type ButtonSize = "sm" | "md" | "lg";
|
|
6
|
+
interface ButtonVariantsOptions {
|
|
7
|
+
variant?: ButtonVariant;
|
|
8
|
+
size?: ButtonSize;
|
|
9
|
+
fullWidth?: boolean;
|
|
10
|
+
iconOnly?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Class list for an element styled as a Button.
|
|
15
|
+
*
|
|
16
|
+
* Links must keep link semantics — never render an `<a>` through Button
|
|
17
|
+
* (it would receive `role="button"`). Style the anchor directly instead:
|
|
18
|
+
*
|
|
19
|
+
* <a href="/docs" className={buttonVariants({ variant: "primary" })}>Docs</a>
|
|
20
|
+
*/
|
|
21
|
+
declare function buttonVariants({ variant, size, fullWidth, iconOnly, className }?: ButtonVariantsOptions): string;
|
|
22
|
+
interface ButtonBaseProps extends Omit<ComponentPropsWithoutRef<typeof Button>, "className"> {
|
|
23
|
+
/** Visual style of the button */
|
|
24
|
+
variant?: ButtonVariant;
|
|
25
|
+
/** Size of the button. `sm` (32px) meets the WCAG 2.5.8 AA target-size floor; prefer `md`/`lg` for touch-first surfaces. */
|
|
26
|
+
size?: ButtonSize;
|
|
27
|
+
/** Stretch to fill the container width */
|
|
28
|
+
fullWidth?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Show a progress indicator and block interaction while keeping the button
|
|
31
|
+
* focusable, so keyboard/screen-reader focus is not lost mid-action.
|
|
32
|
+
* The button keeps its width; the label is swapped for a centered spinner
|
|
33
|
+
* unless `loadingText` is set.
|
|
34
|
+
*/
|
|
35
|
+
loading?: boolean;
|
|
36
|
+
/** Visible label shown next to the spinner while `loading` (announced to screen readers). */
|
|
37
|
+
loadingText?: ReactNode;
|
|
38
|
+
/** Decorative icon before the label (hidden from assistive technology). */
|
|
39
|
+
startIcon?: ReactNode;
|
|
40
|
+
/** Decorative icon after the label (hidden from assistive technology). */
|
|
41
|
+
endIcon?: ReactNode;
|
|
42
|
+
className?: string;
|
|
43
|
+
}
|
|
44
|
+
/** Icon-only buttons have no visible label, so an accessible name is required. */
|
|
45
|
+
type ButtonIconOnlyProps = {
|
|
46
|
+
iconOnly: true;
|
|
47
|
+
"aria-label": string;
|
|
48
|
+
} | {
|
|
49
|
+
iconOnly: true;
|
|
50
|
+
"aria-labelledby": string;
|
|
51
|
+
} | {
|
|
52
|
+
iconOnly?: false;
|
|
53
|
+
};
|
|
54
|
+
type ButtonProps = ButtonBaseProps & ButtonIconOnlyProps;
|
|
55
|
+
declare const Button$1: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { Button$1 as Button, ButtonProps, ButtonSize, ButtonVariant, ButtonVariantsOptions, buttonVariants };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { forwardRef, useRef } from "react";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Button } from "@base-ui/react/button";
|
|
5
|
+
//#region src/components/Button/Button.tsx
|
|
6
|
+
const baseClasses = "relative inline-flex items-center justify-center whitespace-nowrap select-none rounded-md font-sans font-semibold transition-colors duration-150 cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50";
|
|
7
|
+
const variantClasses = {
|
|
8
|
+
primary: "bg-primary text-primary-foreground hover:bg-primary-700 active:bg-primary-800",
|
|
9
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-primary-300 active:bg-primary-400",
|
|
10
|
+
outline: "border border-border bg-transparent text-foreground hover:bg-muted active:bg-slate-200",
|
|
11
|
+
ghost: "bg-transparent text-primary hover:bg-primary-50 active:bg-primary-100",
|
|
12
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-error-700 active:bg-error-800",
|
|
13
|
+
link: "bg-transparent text-primary underline-offset-4 hover:underline active:text-primary-800"
|
|
14
|
+
};
|
|
15
|
+
const sizeClasses = {
|
|
16
|
+
sm: "h-8 gap-1.5 px-3 text-sm",
|
|
17
|
+
md: "h-10 gap-2 px-4 text-sm",
|
|
18
|
+
lg: "h-12 gap-2 px-6 text-base [&_svg:not([class*='size-'])]:size-5"
|
|
19
|
+
};
|
|
20
|
+
const iconOnlySizeClasses = {
|
|
21
|
+
sm: "w-8 px-0",
|
|
22
|
+
md: "w-10 px-0",
|
|
23
|
+
lg: "w-12 px-0"
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Class list for an element styled as a Button.
|
|
27
|
+
*
|
|
28
|
+
* Links must keep link semantics — never render an `<a>` through Button
|
|
29
|
+
* (it would receive `role="button"`). Style the anchor directly instead:
|
|
30
|
+
*
|
|
31
|
+
* <a href="/docs" className={buttonVariants({ variant: "primary" })}>Docs</a>
|
|
32
|
+
*/
|
|
33
|
+
function buttonVariants({ variant = "primary", size = "md", fullWidth = false, iconOnly = false, className } = {}) {
|
|
34
|
+
return cn(baseClasses, variantClasses[variant], sizeClasses[size], iconOnly && iconOnlySizeClasses[size], fullWidth && "w-full", className);
|
|
35
|
+
}
|
|
36
|
+
const loadingDataAttributes = { "data-loading": "" };
|
|
37
|
+
const RIPPLE_DURATION_MS = 550;
|
|
38
|
+
const RIPPLE_EASING = "cubic-bezier(0.4, 0, 0.2, 1)";
|
|
39
|
+
const RIPPLE_OPACITY = .12;
|
|
40
|
+
const RIPPLE_TOUCH_DELAY_MS = 80;
|
|
41
|
+
let reducedMotionQuery;
|
|
42
|
+
function prefersReducedMotion() {
|
|
43
|
+
reducedMotionQuery ??= window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
44
|
+
return reducedMotionQuery.matches;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Expand a ripple from the press point (or the center for keyboard presses).
|
|
48
|
+
*
|
|
49
|
+
* Built for cheap rendering: one geometry read followed by one style write
|
|
50
|
+
* (no interleaving that would force extra layouts), the circle is created at
|
|
51
|
+
* its final size so the Web Animation touches only compositor-friendly
|
|
52
|
+
* `transform`/`opacity`, and the node removes itself when the animation
|
|
53
|
+
* settles — WAAPI fires `finish` even for hidden elements, so unlike
|
|
54
|
+
* `animationend` this cannot leave orphaned nodes behind.
|
|
55
|
+
*/
|
|
56
|
+
function spawnRipple(container, clientX, clientY) {
|
|
57
|
+
const rect = container.getBoundingClientRect();
|
|
58
|
+
const x = clientX === void 0 ? rect.width / 2 : clientX - rect.left;
|
|
59
|
+
const y = clientY === void 0 ? rect.height / 2 : clientY - rect.top;
|
|
60
|
+
const radius = Math.hypot(Math.max(x, rect.width - x), Math.max(y, rect.height - y));
|
|
61
|
+
const span = document.createElement("span");
|
|
62
|
+
span.style.cssText = `position:absolute;left:${x - radius}px;top:${y - radius}px;width:${radius * 2}px;height:${radius * 2}px;border-radius:50%;background-color:currentColor;pointer-events:none;`;
|
|
63
|
+
container.appendChild(span);
|
|
64
|
+
const animation = span.animate([
|
|
65
|
+
{
|
|
66
|
+
transform: "scale(0)",
|
|
67
|
+
opacity: RIPPLE_OPACITY
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
transform: "scale(1)",
|
|
71
|
+
opacity: RIPPLE_OPACITY,
|
|
72
|
+
offset: .6
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
transform: "scale(1)",
|
|
76
|
+
opacity: 0
|
|
77
|
+
}
|
|
78
|
+
], {
|
|
79
|
+
duration: RIPPLE_DURATION_MS,
|
|
80
|
+
easing: RIPPLE_EASING
|
|
81
|
+
});
|
|
82
|
+
const cleanup = () => {
|
|
83
|
+
clearTimeout(fallback);
|
|
84
|
+
span.remove();
|
|
85
|
+
};
|
|
86
|
+
const fallback = setTimeout(cleanup, 650);
|
|
87
|
+
animation.onfinish = animation.oncancel = cleanup;
|
|
88
|
+
}
|
|
89
|
+
function Spinner() {
|
|
90
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
91
|
+
viewBox: "0 0 24 24",
|
|
92
|
+
fill: "none",
|
|
93
|
+
"aria-hidden": "true",
|
|
94
|
+
className: "animate-spin",
|
|
95
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
96
|
+
cx: "12",
|
|
97
|
+
cy: "12",
|
|
98
|
+
r: "10",
|
|
99
|
+
stroke: "currentColor",
|
|
100
|
+
strokeWidth: "4",
|
|
101
|
+
className: "opacity-25"
|
|
102
|
+
}), /* @__PURE__ */ jsx("path", {
|
|
103
|
+
fill: "currentColor",
|
|
104
|
+
className: "opacity-75",
|
|
105
|
+
d: "M4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 0 1 4 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
106
|
+
})]
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const Button$1 = forwardRef(({ variant = "primary", size = "md", fullWidth = false, iconOnly = false, loading = false, loadingText, startIcon, endIcon, disabled = false, focusableWhenDisabled = false, onPointerDown, onClick, className, children, ...rest }, ref) => {
|
|
110
|
+
const rippleContainerRef = useRef(null);
|
|
111
|
+
const handleRipplePointerDown = (event) => {
|
|
112
|
+
const container = rippleContainerRef.current;
|
|
113
|
+
if (container && !prefersReducedMotion()) {
|
|
114
|
+
const { clientX, clientY, currentTarget } = event;
|
|
115
|
+
if (event.pointerType === "touch") {
|
|
116
|
+
let timer;
|
|
117
|
+
const cancel = () => clearTimeout(timer);
|
|
118
|
+
timer = setTimeout(() => {
|
|
119
|
+
currentTarget.removeEventListener("pointercancel", cancel);
|
|
120
|
+
spawnRipple(container, clientX, clientY);
|
|
121
|
+
}, RIPPLE_TOUCH_DELAY_MS);
|
|
122
|
+
currentTarget.addEventListener("pointercancel", cancel, { once: true });
|
|
123
|
+
} else spawnRipple(container, clientX, clientY);
|
|
124
|
+
}
|
|
125
|
+
onPointerDown?.(event);
|
|
126
|
+
};
|
|
127
|
+
const handleRippleClick = (event) => {
|
|
128
|
+
if (event.detail === 0 && rippleContainerRef.current && !prefersReducedMotion()) spawnRipple(rippleContainerRef.current);
|
|
129
|
+
onClick?.(event);
|
|
130
|
+
};
|
|
131
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
132
|
+
startIcon != null && /* @__PURE__ */ jsx("span", {
|
|
133
|
+
"aria-hidden": "true",
|
|
134
|
+
className: "inline-flex items-center",
|
|
135
|
+
children: startIcon
|
|
136
|
+
}),
|
|
137
|
+
children,
|
|
138
|
+
endIcon != null && /* @__PURE__ */ jsx("span", {
|
|
139
|
+
"aria-hidden": "true",
|
|
140
|
+
className: "inline-flex items-center",
|
|
141
|
+
children: endIcon
|
|
142
|
+
})
|
|
143
|
+
] });
|
|
144
|
+
return /* @__PURE__ */ jsxs(Button, {
|
|
145
|
+
ref,
|
|
146
|
+
disabled: disabled || loading,
|
|
147
|
+
focusableWhenDisabled: focusableWhenDisabled || loading,
|
|
148
|
+
"aria-busy": loading || void 0,
|
|
149
|
+
onPointerDown: handleRipplePointerDown,
|
|
150
|
+
onClick: handleRippleClick,
|
|
151
|
+
className: cn(buttonVariants({
|
|
152
|
+
variant,
|
|
153
|
+
size,
|
|
154
|
+
fullWidth,
|
|
155
|
+
iconOnly
|
|
156
|
+
}), loading && "data-disabled:opacity-100", className),
|
|
157
|
+
...loading ? loadingDataAttributes : void 0,
|
|
158
|
+
...rest,
|
|
159
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
160
|
+
ref: rippleContainerRef,
|
|
161
|
+
"aria-hidden": "true",
|
|
162
|
+
className: "pointer-events-none absolute inset-0 overflow-hidden rounded-[inherit] [contain:strict]"
|
|
163
|
+
}), loading ? loadingText != null ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Spinner, {}), loadingText] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", {
|
|
164
|
+
className: "absolute inset-0 flex items-center justify-center",
|
|
165
|
+
children: [/* @__PURE__ */ jsx(Spinner, {}), /* @__PURE__ */ jsx("span", {
|
|
166
|
+
className: "sr-only",
|
|
167
|
+
children: "Loading.."
|
|
168
|
+
})]
|
|
169
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
170
|
+
className: "invisible contents",
|
|
171
|
+
children: content
|
|
172
|
+
})] }) : content]
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
Button$1.displayName = "Button";
|
|
176
|
+
//#endregion
|
|
177
|
+
export { Button$1 as Button, buttonVariants };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef } from "react";
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
+
//#region src/components/Calendar/Calendar.d.ts
|
|
4
|
+
type CalendarMode = "single" | "multiple" | "range";
|
|
5
|
+
/** Inclusive date range. `onValueChange` only ever emits complete ranges. */
|
|
6
|
+
interface CalendarDateRange {
|
|
7
|
+
start: Date;
|
|
8
|
+
end: Date;
|
|
9
|
+
}
|
|
10
|
+
/** State passed to the `render` callback (also exposed as root data-attributes). */
|
|
11
|
+
type CalendarState = {
|
|
12
|
+
mode: CalendarMode;
|
|
13
|
+
disabled: boolean;
|
|
14
|
+
readOnly: boolean;
|
|
15
|
+
};
|
|
16
|
+
interface CalendarBaseProps extends Omit<ComponentPropsWithoutRef<"div">, "className" | "children" | "defaultValue"> {
|
|
17
|
+
/**
|
|
18
|
+
* Month shown in the first grid (controlled). Any day of the month works;
|
|
19
|
+
* it is normalized to the first. Pair with `onMonthChange`.
|
|
20
|
+
*/
|
|
21
|
+
month?: Date;
|
|
22
|
+
/**
|
|
23
|
+
* Initial visible month (uncontrolled). Defaults to the month of the first
|
|
24
|
+
* selected date, else the current month.
|
|
25
|
+
*/
|
|
26
|
+
defaultMonth?: Date;
|
|
27
|
+
/** Called when the visible month changes (navigation buttons or keyboard paging). */
|
|
28
|
+
onMonthChange?: (month: Date) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Months rendered side by side (wraps on narrow containers). Navigation
|
|
31
|
+
* pages by this amount so months never repeat across a page turn.
|
|
32
|
+
* @default 1
|
|
33
|
+
*/
|
|
34
|
+
numberOfMonths?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Earliest selectable day. Days before it are hard-disabled: dimmed,
|
|
37
|
+
* skipped by keyboard focus, and the previous-month button disables at
|
|
38
|
+
* the boundary.
|
|
39
|
+
*/
|
|
40
|
+
minDate?: Date;
|
|
41
|
+
/** Latest selectable day — the `minDate` counterpart. */
|
|
42
|
+
maxDate?: Date;
|
|
43
|
+
/**
|
|
44
|
+
* Marks days as unavailable (e.g. sold out). Unlike `minDate`/`maxDate`,
|
|
45
|
+
* unavailable days stay keyboard-focusable and readable (WCAG 4.5:1) so
|
|
46
|
+
* screen-reader users can discover them — they just can't be selected.
|
|
47
|
+
* In `range` mode a pending selection is limited to the contiguous
|
|
48
|
+
* available run around its start date.
|
|
49
|
+
*/
|
|
50
|
+
isDateUnavailable?: (date: Date) => boolean;
|
|
51
|
+
/** Disable the whole calendar: selection and navigation. */
|
|
52
|
+
disabled?: boolean;
|
|
53
|
+
/** Keep the calendar navigable but ignore selection — for display-only surfaces. */
|
|
54
|
+
readOnly?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* BCP-47 tag (e.g. `"en-US"`, `"th-TH"`) for the caption, weekday names,
|
|
57
|
+
* day numerals, and day-cell accessible labels via `Intl.DateTimeFormat`.
|
|
58
|
+
* Defaults to the runtime locale. Rendering stays Gregorian, but locales
|
|
59
|
+
* with a different default calendar display accordingly (Thai → Buddhist-era
|
|
60
|
+
* years).
|
|
61
|
+
*/
|
|
62
|
+
locale?: string;
|
|
63
|
+
/**
|
|
64
|
+
* First day of the week: 0 = Sunday … 6 = Saturday. Defaults to the
|
|
65
|
+
* locale's week convention when the runtime exposes it, else Sunday.
|
|
66
|
+
*/
|
|
67
|
+
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
68
|
+
/**
|
|
69
|
+
* Show the leading/trailing days of adjacent months. They are inert
|
|
70
|
+
* (visual continuity only) and hidden from assistive technology.
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
showOutsideDays?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Always render six weeks per month so the calendar height never changes
|
|
76
|
+
* while paging — recommended inside popovers.
|
|
77
|
+
* @default false
|
|
78
|
+
*/
|
|
79
|
+
fixedWeeks?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* The day highlighted as "today" (`aria-current="date"`). Defaults to the
|
|
82
|
+
* current date; pin it in tests and visual baselines for determinism.
|
|
83
|
+
*/
|
|
84
|
+
today?: Date;
|
|
85
|
+
/** Move focus to the focus-target day (selected → today → first enabled) on mount. */
|
|
86
|
+
autoFocus?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Accessible label for the previous-month navigation button.
|
|
89
|
+
* @default "Previous month"
|
|
90
|
+
*/
|
|
91
|
+
previousMonthLabel?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Accessible label for the next-month navigation button.
|
|
94
|
+
* @default "Next month"
|
|
95
|
+
*/
|
|
96
|
+
nextMonthLabel?: string;
|
|
97
|
+
className?: string;
|
|
98
|
+
/** Replace the root element — Base UI's composition prop. */
|
|
99
|
+
render?: useRender.RenderProp<CalendarState>;
|
|
100
|
+
}
|
|
101
|
+
/** Selection props follow `mode`, so a mismatched value shape fails to compile. */
|
|
102
|
+
type CalendarModeProps = {
|
|
103
|
+
/** Selection behavior. `single` picks one date. @default "single" */
|
|
104
|
+
mode?: "single";
|
|
105
|
+
/** Selected date (controlled). `null` = empty. */
|
|
106
|
+
value?: Date | null;
|
|
107
|
+
/** Initial selected date (uncontrolled). */
|
|
108
|
+
defaultValue?: Date | null;
|
|
109
|
+
/** Called with the new date, or `null` when deselected via `allowDeselect`. */
|
|
110
|
+
onValueChange?: (value: Date | null) => void;
|
|
111
|
+
/**
|
|
112
|
+
* Let clicking the selected date clear it — for optional filters.
|
|
113
|
+
* @default false
|
|
114
|
+
*/
|
|
115
|
+
allowDeselect?: boolean;
|
|
116
|
+
} | {
|
|
117
|
+
/** `multiple` toggles any number of dates. */
|
|
118
|
+
mode: "multiple";
|
|
119
|
+
/** Selected dates (controlled), kept sorted ascending. */
|
|
120
|
+
value?: Date[];
|
|
121
|
+
/** Initial selected dates (uncontrolled). */
|
|
122
|
+
defaultValue?: Date[];
|
|
123
|
+
/** Called with the new sorted date list after every toggle. */
|
|
124
|
+
onValueChange?: (value: Date[]) => void;
|
|
125
|
+
allowDeselect?: never;
|
|
126
|
+
} | {
|
|
127
|
+
/** `range` picks a start and end with a live preview in between. */
|
|
128
|
+
mode: "range";
|
|
129
|
+
/** Selected range (controlled). `null` = empty. */
|
|
130
|
+
value?: CalendarDateRange | null;
|
|
131
|
+
/** Initial selected range (uncontrolled). */
|
|
132
|
+
defaultValue?: CalendarDateRange | null;
|
|
133
|
+
/** Called only with complete `{ start, end }` ranges (ends ordered, never inverted). */
|
|
134
|
+
onValueChange?: (value: CalendarDateRange | null) => void;
|
|
135
|
+
allowDeselect?: never;
|
|
136
|
+
};
|
|
137
|
+
type CalendarProps = CalendarBaseProps & CalendarModeProps;
|
|
138
|
+
declare const Calendar: import("react").ForwardRefExoticComponent<CalendarProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
139
|
+
//#endregion
|
|
140
|
+
export { Calendar, CalendarDateRange, CalendarMode, CalendarProps, CalendarState };
|