@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,268 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { createContext, forwardRef, useContext, useMemo } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Drawer } from "@base-ui/react/drawer";
|
|
5
|
+
//#region src/components/Drawer/Drawer.tsx
|
|
6
|
+
const sideToSwipeDirection = {
|
|
7
|
+
top: "up",
|
|
8
|
+
right: "right",
|
|
9
|
+
bottom: "down",
|
|
10
|
+
left: "left"
|
|
11
|
+
};
|
|
12
|
+
const DrawerSideContext = createContext({
|
|
13
|
+
side: "right",
|
|
14
|
+
hasSnapPoints: false
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* Groups all parts of the drawer and owns its state. Renders no DOM.
|
|
18
|
+
*
|
|
19
|
+
* Wraps Base UI's `Drawer.Root`, deriving `swipeDirection` from `side` (pass
|
|
20
|
+
* `swipeDirection` yourself only to decouple them). Every other root feature
|
|
21
|
+
* passes through: `open`/`defaultOpen`/`onOpenChange(open, details)`,
|
|
22
|
+
* `snapPoints` with `snapPoint`/`defaultSnapPoint`/`onSnapPointChange`,
|
|
23
|
+
* `modal` (`true` | `false` | `"trap-focus"`), `disablePointerDismissal`,
|
|
24
|
+
* `onOpenChangeComplete`, `actionsRef`, and detached triggers via
|
|
25
|
+
* `createDrawerHandle()` payloads.
|
|
26
|
+
*/
|
|
27
|
+
function Drawer$1({ side = "right", swipeDirection, ...rest }) {
|
|
28
|
+
const hasSnapPoints = (rest.snapPoints?.length ?? 0) > 0;
|
|
29
|
+
const context = useMemo(() => ({
|
|
30
|
+
side,
|
|
31
|
+
hasSnapPoints
|
|
32
|
+
}), [side, hasSnapPoints]);
|
|
33
|
+
return /* @__PURE__ */ jsx(DrawerSideContext.Provider, {
|
|
34
|
+
value: context,
|
|
35
|
+
children: /* @__PURE__ */ jsx(Drawer.Root, {
|
|
36
|
+
swipeDirection: swipeDirection ?? sideToSwipeDirection[side],
|
|
37
|
+
...rest
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
Drawer$1.displayName = "Drawer";
|
|
42
|
+
/**
|
|
43
|
+
* Opens the drawer. Renders an unstyled `<button>` and exposes
|
|
44
|
+
* `data-popup-open` while its drawer is open — compose it with Button for
|
|
45
|
+
* the usual look: `<DrawerTrigger render={<Button>Open</Button>} />`.
|
|
46
|
+
*/
|
|
47
|
+
const DrawerTrigger = forwardRef((props, ref) => /* @__PURE__ */ jsx(Drawer.Trigger, {
|
|
48
|
+
ref,
|
|
49
|
+
...props
|
|
50
|
+
}));
|
|
51
|
+
DrawerTrigger.displayName = "DrawerTrigger";
|
|
52
|
+
/**
|
|
53
|
+
* Closes the drawer. Renders an unstyled `<button>` — compose it with
|
|
54
|
+
* Button for footer actions:
|
|
55
|
+
* `<DrawerClose render={<Button variant="outline">Cancel</Button>} />`.
|
|
56
|
+
*/
|
|
57
|
+
const DrawerClose = forwardRef((props, ref) => /* @__PURE__ */ jsx(Drawer.Close, {
|
|
58
|
+
ref,
|
|
59
|
+
...props
|
|
60
|
+
}));
|
|
61
|
+
DrawerClose.displayName = "DrawerClose";
|
|
62
|
+
const backdropClasses = "fixed inset-0 z-50 min-h-dvh bg-overlay supports-[-webkit-touch-callout:none]:absolute opacity-[calc(1_-_var(--drawer-swipe-progress,0))] motion-safe:transition-opacity motion-safe:duration-[450ms] motion-safe:ease-[cubic-bezier(0.32,0.72,0,1)] data-swiping:duration-0 data-ending-style:duration-[calc(var(--drawer-swipe-strength,1)*400ms)] data-starting-style:opacity-0 data-ending-style:opacity-0";
|
|
63
|
+
const viewportBaseClasses = "pointer-events-none fixed inset-0 z-50 flex";
|
|
64
|
+
const viewportSideClasses = {
|
|
65
|
+
top: "items-start justify-center",
|
|
66
|
+
right: "justify-end",
|
|
67
|
+
bottom: "items-end justify-center",
|
|
68
|
+
left: "justify-start"
|
|
69
|
+
};
|
|
70
|
+
const popupBaseClasses = "pointer-events-auto relative flex flex-col border-border bg-background font-sans text-foreground shadow-lg outline-none touch-none will-change-transform data-closed:pointer-events-none scale-[calc(1_-_0.05*var(--nested-drawers,0))] before:pointer-events-none before:absolute before:bg-inherit after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:bg-slate-950/5 after:opacity-0 data-nested-drawer-open:after:opacity-100 motion-safe:transition-[transform,scale] motion-safe:duration-[450ms] motion-safe:ease-[cubic-bezier(0.32,0.72,0,1)] motion-safe:after:transition-opacity motion-safe:after:duration-[450ms] data-swiping:select-none data-swiping:duration-0 data-ending-style:duration-[calc(var(--drawer-swipe-strength,1)*400ms)]";
|
|
71
|
+
const popupSideClasses = {
|
|
72
|
+
top: "w-full origin-top rounded-b-md border-b before:inset-x-0 before:bottom-full before:h-12 [transform:translateY(calc(var(--drawer-snap-point-offset,0px)_+_var(--drawer-swipe-movement-y,0px)))] data-starting-style:[transform:translateY(calc(-100%_-_2px))] data-ending-style:[transform:translateY(calc(-100%_-_2px))]",
|
|
73
|
+
right: "h-full origin-right border-l before:inset-y-0 before:left-full before:w-12 [transform:translateX(var(--drawer-swipe-movement-x,0px))] data-starting-style:[transform:translateX(calc(100%_+_2px))] data-ending-style:[transform:translateX(calc(100%_+_2px))]",
|
|
74
|
+
bottom: "w-full origin-bottom rounded-t-md border-t before:inset-x-0 before:top-full before:h-12 [transform:translateY(calc(var(--drawer-snap-point-offset,0px)_+_var(--drawer-swipe-movement-y,0px)))] data-starting-style:[transform:translateY(calc(100%_+_2px))] data-ending-style:[transform:translateY(calc(100%_+_2px))]",
|
|
75
|
+
left: "h-full origin-left border-r before:inset-y-0 before:right-full before:w-12 [transform:translateX(var(--drawer-swipe-movement-x,0px))] data-starting-style:[transform:translateX(calc(-100%_-_2px))] data-ending-style:[transform:translateX(calc(-100%_-_2px))]"
|
|
76
|
+
};
|
|
77
|
+
const horizontalSizeClasses = {
|
|
78
|
+
sm: "w-80 max-w-[calc(100vw_-_3rem)]",
|
|
79
|
+
md: "w-96 max-w-[calc(100vw_-_3rem)]",
|
|
80
|
+
lg: "w-[32rem] max-w-[calc(100vw_-_3rem)]",
|
|
81
|
+
full: "w-screen border-none shadow-none"
|
|
82
|
+
};
|
|
83
|
+
const verticalSizeClasses = {
|
|
84
|
+
sm: "max-h-[40dvh]",
|
|
85
|
+
md: "max-h-[75dvh]",
|
|
86
|
+
lg: "max-h-[90dvh]",
|
|
87
|
+
full: "h-dvh rounded-none border-none shadow-none"
|
|
88
|
+
};
|
|
89
|
+
const snapPointPaddingClasses = "[padding-bottom:max(0px,calc(var(--drawer-snap-point-offset,0px)_+_var(--drawer-swipe-movement-y,0px)))]";
|
|
90
|
+
const contentClasses = "flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto overscroll-contain touch-auto p-6";
|
|
91
|
+
const contentBottomSafeAreaClasses = "pb-[calc(1.5rem_+_env(safe-area-inset-bottom,0px))]";
|
|
92
|
+
const closeClearanceClasses = "[&>[data-drawer-header]]:pr-8 [&>[data-drawer-title]]:pr-8";
|
|
93
|
+
const cornerCloseClasses = "absolute top-4 right-4 inline-flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md text-muted-foreground transition-colors duration-150 hover:bg-muted hover:text-foreground active:bg-slate-200 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring";
|
|
94
|
+
const handleBaseClasses = "shrink-0 rounded-full bg-slate-300";
|
|
95
|
+
const handleSideClasses = {
|
|
96
|
+
top: "order-last mx-auto mb-3 h-1 w-10",
|
|
97
|
+
right: "absolute top-1/2 left-2 h-10 w-1 -translate-y-1/2",
|
|
98
|
+
bottom: "mx-auto mt-3 h-1 w-10",
|
|
99
|
+
left: "absolute top-1/2 right-2 h-10 w-1 -translate-y-1/2"
|
|
100
|
+
};
|
|
101
|
+
function XIcon(props) {
|
|
102
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
103
|
+
viewBox: "0 0 16 16",
|
|
104
|
+
fill: "none",
|
|
105
|
+
stroke: "currentColor",
|
|
106
|
+
strokeWidth: 1.5,
|
|
107
|
+
strokeLinecap: "round",
|
|
108
|
+
"aria-hidden": "true",
|
|
109
|
+
className: "size-4",
|
|
110
|
+
...props,
|
|
111
|
+
children: /* @__PURE__ */ jsx("path", { d: "m3.5 3.5 9 9m-9 0 9-9" })
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Class list for the drawer surface itself. Useful when composing Base UI's
|
|
116
|
+
* drawer parts directly (custom viewports, snap-point layouts) while keeping
|
|
117
|
+
* the ArcFusion look.
|
|
118
|
+
*/
|
|
119
|
+
function drawerPopupVariants({ side = "right", size = "md", className } = {}) {
|
|
120
|
+
const sizeClasses = side === "left" || side === "right" ? horizontalSizeClasses : verticalSizeClasses;
|
|
121
|
+
return cn(popupBaseClasses, popupSideClasses[side], sizeClasses[size], className);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The drawer surface. Bundles Base UI's Portal, Backdrop, Viewport, Popup,
|
|
125
|
+
* and Content parts into one styled component positioned on the root's
|
|
126
|
+
* `side`; `initialFocus`/`finalFocus` and every other Base UI popup prop
|
|
127
|
+
* pass straight through. Children render inside the scrollable content
|
|
128
|
+
* region while the handle and corner close stay pinned to the frame.
|
|
129
|
+
*/
|
|
130
|
+
const DrawerPopup = forwardRef(({ size = "md", showCloseButton = true, closeLabel = "Close", showHandle = false, showBackdrop = true, keepMounted = false, virtualKeyboard = false, container, className, children, ...rest }, ref) => {
|
|
131
|
+
const { side, hasSnapPoints } = useContext(DrawerSideContext);
|
|
132
|
+
const portal = /* @__PURE__ */ jsxs(Drawer.Portal, {
|
|
133
|
+
keepMounted,
|
|
134
|
+
container,
|
|
135
|
+
children: [showBackdrop && /* @__PURE__ */ jsx(Drawer.Backdrop, { className: backdropClasses }), /* @__PURE__ */ jsx(Drawer.Viewport, {
|
|
136
|
+
className: cn(viewportBaseClasses, viewportSideClasses[side]),
|
|
137
|
+
children: /* @__PURE__ */ jsxs(Drawer.Popup, {
|
|
138
|
+
ref,
|
|
139
|
+
className: cn(drawerPopupVariants({
|
|
140
|
+
side,
|
|
141
|
+
size
|
|
142
|
+
}), hasSnapPoints && side === "bottom" && snapPointPaddingClasses, className),
|
|
143
|
+
...rest,
|
|
144
|
+
children: [
|
|
145
|
+
showHandle && /* @__PURE__ */ jsx("span", {
|
|
146
|
+
"aria-hidden": "true",
|
|
147
|
+
className: cn(handleBaseClasses, handleSideClasses[side])
|
|
148
|
+
}),
|
|
149
|
+
/* @__PURE__ */ jsx(Drawer.Content, {
|
|
150
|
+
className: cn(contentClasses, side === "bottom" && contentBottomSafeAreaClasses, showCloseButton && closeClearanceClasses),
|
|
151
|
+
children
|
|
152
|
+
}),
|
|
153
|
+
showCloseButton && /* @__PURE__ */ jsx(Drawer.Close, {
|
|
154
|
+
"aria-label": closeLabel,
|
|
155
|
+
className: cornerCloseClasses,
|
|
156
|
+
children: /* @__PURE__ */ jsx(XIcon, {})
|
|
157
|
+
})
|
|
158
|
+
]
|
|
159
|
+
})
|
|
160
|
+
})]
|
|
161
|
+
});
|
|
162
|
+
return virtualKeyboard ? /* @__PURE__ */ jsx(Drawer.VirtualKeyboardProvider, { children: portal }) : portal;
|
|
163
|
+
});
|
|
164
|
+
DrawerPopup.displayName = "DrawerPopup";
|
|
165
|
+
/** Groups the title and description with standard spacing at the top of the drawer. */
|
|
166
|
+
const DrawerHeader = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx("div", {
|
|
167
|
+
ref,
|
|
168
|
+
"data-drawer-header": "",
|
|
169
|
+
className: cn("flex flex-col gap-1.5", className),
|
|
170
|
+
...rest
|
|
171
|
+
}));
|
|
172
|
+
DrawerHeader.displayName = "DrawerHeader";
|
|
173
|
+
/**
|
|
174
|
+
* Action row: right-aligned on desktop, stacked with the primary action on
|
|
175
|
+
* top on small screens. As a direct child of the popup it pins to the
|
|
176
|
+
* drawer's bottom edge when the content is shorter than a full-height panel.
|
|
177
|
+
*/
|
|
178
|
+
const DrawerFooter = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx("div", {
|
|
179
|
+
ref,
|
|
180
|
+
className: cn("mt-auto flex flex-col-reverse gap-2 sm:flex-row sm:items-center sm:justify-end", className),
|
|
181
|
+
...rest
|
|
182
|
+
}));
|
|
183
|
+
DrawerFooter.displayName = "DrawerFooter";
|
|
184
|
+
/**
|
|
185
|
+
* Labels the drawer — Base UI wires it to the popup's `aria-labelledby`.
|
|
186
|
+
* Renders an `<h2>`; every drawer should have one (or an `aria-label` on
|
|
187
|
+
* the popup) so the panel announces meaningfully.
|
|
188
|
+
*/
|
|
189
|
+
const DrawerTitle = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx(Drawer.Title, {
|
|
190
|
+
ref,
|
|
191
|
+
"data-drawer-title": "",
|
|
192
|
+
className: cn("font-heading text-xl font-semibold text-foreground", className),
|
|
193
|
+
...rest
|
|
194
|
+
}));
|
|
195
|
+
DrawerTitle.displayName = "DrawerTitle";
|
|
196
|
+
/** Supporting copy announced when the drawer opens — wired to `aria-describedby`. */
|
|
197
|
+
const DrawerDescription = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx(Drawer.Description, {
|
|
198
|
+
ref,
|
|
199
|
+
className: cn("font-sans text-sm text-muted-foreground", className),
|
|
200
|
+
...rest
|
|
201
|
+
}));
|
|
202
|
+
DrawerDescription.displayName = "DrawerDescription";
|
|
203
|
+
const swipeAreaSideClasses = {
|
|
204
|
+
top: "inset-x-0 top-0 h-6",
|
|
205
|
+
right: "inset-y-0 right-0 w-6",
|
|
206
|
+
bottom: "inset-x-0 bottom-0 h-6",
|
|
207
|
+
left: "inset-y-0 left-0 w-6"
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* Invisible strip along the drawer's edge that opens it with a swipe-in
|
|
211
|
+
* gesture (mobile-navigation pattern). Positions itself on the root's
|
|
212
|
+
* `side` with a 24px hit area — pass `className` to widen it or add a
|
|
213
|
+
* visible affordance as children. Keep a regular `DrawerTrigger` too:
|
|
214
|
+
* edge swipes are invisible to most users and unavailable to keyboards.
|
|
215
|
+
*/
|
|
216
|
+
const DrawerSwipeArea = forwardRef(({ className, ...rest }, ref) => {
|
|
217
|
+
const { side } = useContext(DrawerSideContext);
|
|
218
|
+
return /* @__PURE__ */ jsx(Drawer.SwipeArea, {
|
|
219
|
+
ref,
|
|
220
|
+
className: cn("fixed z-40", swipeAreaSideClasses[side], className),
|
|
221
|
+
...rest
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
DrawerSwipeArea.displayName = "DrawerSwipeArea";
|
|
225
|
+
/**
|
|
226
|
+
* Shares drawer state across the app shell so `DrawerIndent` /
|
|
227
|
+
* `DrawerIndentBackground` can react to any drawer opening. Renders no DOM —
|
|
228
|
+
* wrap it around the app root only when using the indent effect.
|
|
229
|
+
*/
|
|
230
|
+
const DrawerProvider = Drawer.Provider;
|
|
231
|
+
/**
|
|
232
|
+
* Keyboard-aware focus and scroll handling for bottom sheets that contain
|
|
233
|
+
* form fields. Prefer the `virtualKeyboard` prop on `DrawerPopup`; this raw
|
|
234
|
+
* part exists for custom compositions and MUST render inside a `Drawer`
|
|
235
|
+
* (it reads the root's context), wrapping the drawer's parts. Exposes
|
|
236
|
+
* `--drawer-keyboard-inset` on the viewport. Renders no DOM.
|
|
237
|
+
*/
|
|
238
|
+
const DrawerVirtualKeyboardProvider = Drawer.VirtualKeyboardProvider;
|
|
239
|
+
/**
|
|
240
|
+
* Creates a handle that connects detached `DrawerTrigger`s (or imperative
|
|
241
|
+
* `open`/`close` calls) to a `Drawer` rendered elsewhere — e.g. opening a
|
|
242
|
+
* drawer from a menu item. Pass it to both as the `handle` prop.
|
|
243
|
+
*/
|
|
244
|
+
const createDrawerHandle = Drawer.createHandle;
|
|
245
|
+
/**
|
|
246
|
+
* Wrapper for the app's main UI inside a `DrawerProvider`; gets
|
|
247
|
+
* `data-active` while any drawer is open. Unstyled on purpose — the app
|
|
248
|
+
* shell owns the effect, e.g.
|
|
249
|
+
* `className="motion-safe:transition-transform data-active:scale-[0.98]"`
|
|
250
|
+
* for the iOS-style recede.
|
|
251
|
+
*/
|
|
252
|
+
const DrawerIndent = forwardRef((props, ref) => /* @__PURE__ */ jsx(Drawer.Indent, {
|
|
253
|
+
ref,
|
|
254
|
+
...props
|
|
255
|
+
}));
|
|
256
|
+
DrawerIndent.displayName = "DrawerIndent";
|
|
257
|
+
/**
|
|
258
|
+
* Backdrop layer rendered behind `DrawerIndent` (place it just before) so
|
|
259
|
+
* the receded app has something to sit on — style it with `data-active`
|
|
260
|
+
* like the indent itself. Unstyled on purpose.
|
|
261
|
+
*/
|
|
262
|
+
const DrawerIndentBackground = forwardRef((props, ref) => /* @__PURE__ */ jsx(Drawer.IndentBackground, {
|
|
263
|
+
ref,
|
|
264
|
+
...props
|
|
265
|
+
}));
|
|
266
|
+
DrawerIndentBackground.displayName = "DrawerIndentBackground";
|
|
267
|
+
//#endregion
|
|
268
|
+
export { Drawer$1 as Drawer, DrawerClose, DrawerDescription, DrawerFooter, DrawerHeader, DrawerIndent, DrawerIndentBackground, DrawerPopup, DrawerProvider, DrawerSwipeArea, DrawerTitle, DrawerTrigger, DrawerVirtualKeyboardProvider, createDrawerHandle, drawerPopupVariants };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Drawer, DrawerClose, DrawerCloseProps, DrawerDescription, DrawerDescriptionProps, DrawerFooter, DrawerFooterProps, DrawerHeader, DrawerHeaderProps, DrawerIndent, DrawerIndentBackground, DrawerIndentBackgroundProps, DrawerIndentProps, DrawerPopup, DrawerPopupProps, DrawerPopupVariantsOptions, DrawerProps, DrawerProvider, DrawerSide, DrawerSize, DrawerSwipeArea, DrawerSwipeAreaProps, DrawerTitle, DrawerTitleProps, DrawerTrigger, DrawerTriggerProps, DrawerVirtualKeyboardProvider, createDrawerHandle, drawerPopupVariants } from "./Drawer.js";
|
|
2
|
+
export { Drawer, DrawerClose, type DrawerCloseProps, DrawerDescription, type DrawerDescriptionProps, DrawerFooter, type DrawerFooterProps, DrawerHeader, type DrawerHeaderProps, DrawerIndent, DrawerIndentBackground, type DrawerIndentBackgroundProps, type DrawerIndentProps, DrawerPopup, type DrawerPopupProps, type DrawerPopupVariantsOptions, type DrawerProps, DrawerProvider, type DrawerSide, type DrawerSize, DrawerSwipeArea, type DrawerSwipeAreaProps, DrawerTitle, type DrawerTitleProps, DrawerTrigger, type DrawerTriggerProps, DrawerVirtualKeyboardProvider, createDrawerHandle, drawerPopupVariants };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Drawer, DrawerClose, DrawerDescription, DrawerFooter, DrawerHeader, DrawerIndent, DrawerIndentBackground, DrawerPopup, DrawerProvider, DrawerSwipeArea, DrawerTitle, DrawerTrigger, DrawerVirtualKeyboardProvider, createDrawerHandle, drawerPopupVariants } from "./Drawer.js";
|
|
2
|
+
export { Drawer, DrawerClose, DrawerDescription, DrawerFooter, DrawerHeader, DrawerIndent, DrawerIndentBackground, DrawerPopup, DrawerProvider, DrawerSwipeArea, DrawerTitle, DrawerTrigger, DrawerVirtualKeyboardProvider, createDrawerHandle, drawerPopupVariants };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactNode, Ref } from "react";
|
|
2
|
+
import { Field } from "@base-ui/react/field";
|
|
3
|
+
import { Control, FieldPath, FieldValues } from "react-hook-form";
|
|
4
|
+
//#region src/components/Field/Field.d.ts
|
|
5
|
+
type FieldOrientation = "vertical" | "horizontal";
|
|
6
|
+
type BaseFieldRootProps = ComponentPropsWithoutRef<typeof Field.Root>;
|
|
7
|
+
interface FieldProps<TFieldValues extends FieldValues = FieldValues> extends Omit<BaseFieldRootProps, "className" | "name"> {
|
|
8
|
+
/**
|
|
9
|
+
* Identifies the field: the submitted name in native forms, the registered
|
|
10
|
+
* path when connected to React Hook Form. With an explicit `control`, the
|
|
11
|
+
* name is type-checked against the form's values.
|
|
12
|
+
*/
|
|
13
|
+
name?: FieldPath<TFieldValues>;
|
|
14
|
+
/**
|
|
15
|
+
* React Hook Form `control` for connecting this field explicitly. Inside a
|
|
16
|
+
* `<Form form={…}>` it is read from context instead, so most fields only
|
|
17
|
+
* need `name`. A field with a `name` and a reachable control is
|
|
18
|
+
* "connected": it subscribes to that field's state via `useController`,
|
|
19
|
+
* shows `FieldError` messages automatically, and wires the `Input` inside
|
|
20
|
+
* it (value, change/blur handlers, focus ref) with no extra props.
|
|
21
|
+
*/
|
|
22
|
+
control?: Control<TFieldValues>;
|
|
23
|
+
/**
|
|
24
|
+
* Marks the field as required: the label gains a decorative asterisk and
|
|
25
|
+
* the control is announced as required (`aria-required` when connected —
|
|
26
|
+
* the schema owns actual enforcement — or the native `required` attribute
|
|
27
|
+
* in static fields).
|
|
28
|
+
*/
|
|
29
|
+
required?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* `vertical` (default) stacks label, control, and supporting text.
|
|
32
|
+
* `horizontal` puts the label in a leading column, baseline-aligned with
|
|
33
|
+
* the control — for dense, label-left form layouts. Checkbox/switch rows
|
|
34
|
+
* are a different pattern: wrap the control with `FieldLabel` instead.
|
|
35
|
+
*/
|
|
36
|
+
orientation?: FieldOrientation;
|
|
37
|
+
className?: string;
|
|
38
|
+
}
|
|
39
|
+
interface FieldComponent {
|
|
40
|
+
<TFieldValues extends FieldValues = FieldValues>(props: FieldProps<TFieldValues> & {
|
|
41
|
+
ref?: Ref<HTMLDivElement>;
|
|
42
|
+
}): ReactNode;
|
|
43
|
+
displayName?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Labelling + validation wrapper for a single form control, built on Base UI's
|
|
47
|
+
* Field. It associates `FieldLabel`, `FieldDescription`, and `FieldError`
|
|
48
|
+
* with the control automatically (ids, `aria-describedby`) and exposes state
|
|
49
|
+
* data-attributes (`data-invalid`, `data-touched`, `data-dirty`,
|
|
50
|
+
* `data-filled`, `data-focused`) on every part for styling.
|
|
51
|
+
*
|
|
52
|
+
* Give it a `name` inside `<Form form={…}>` (or pass `control`) to connect it
|
|
53
|
+
* to React Hook Form — validation state then flows in from the form and the
|
|
54
|
+
* `Input` inside is wired automatically. Without a form library it works as a
|
|
55
|
+
* native field: constraint attributes plus the `validate`/`validationMode`
|
|
56
|
+
* props drive `FieldError` via its `match` prop.
|
|
57
|
+
*/
|
|
58
|
+
declare const Field$1: FieldComponent;
|
|
59
|
+
interface FieldLabelVariantsOptions {
|
|
60
|
+
className?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Class list for an element styled as a field label — for labelling controls
|
|
64
|
+
* that live outside a `Field` (e.g. a filter Select in a toolbar) so every
|
|
65
|
+
* label in the product shares one look.
|
|
66
|
+
*/
|
|
67
|
+
declare function fieldLabelVariants({ className }?: FieldLabelVariantsOptions): string;
|
|
68
|
+
interface FieldLabelProps extends Omit<ComponentPropsWithoutRef<typeof Field.Label>, "className"> {
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Visible label, automatically associated with the field's control — clicking
|
|
73
|
+
* it focuses the control. When the `Field` is `required`, a decorative
|
|
74
|
+
* asterisk (hidden from assistive technology, which hears the control's
|
|
75
|
+
* required state instead) is appended. For checkbox/radio/switch rows, wrap
|
|
76
|
+
* the control instead: `<FieldLabel><Switch /> Notifications</FieldLabel>`.
|
|
77
|
+
* When the control is button-based (Select, Combobox triggers), pass
|
|
78
|
+
* `nativeLabel={false}` — the label then renders as a `<div>` wired via
|
|
79
|
+
* `aria-labelledby`, so hovering or clicking it doesn't act on the button.
|
|
80
|
+
*/
|
|
81
|
+
declare const FieldLabel: import("react").ForwardRefExoticComponent<FieldLabelProps & import("react").RefAttributes<HTMLLabelElement>>;
|
|
82
|
+
interface FieldDescriptionProps extends Omit<ComponentPropsWithoutRef<typeof Field.Description>, "className"> {
|
|
83
|
+
className?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Persistent supporting copy for the field, announced via `aria-describedby`.
|
|
87
|
+
* It stays visible while an error shows — the hint is exactly what the user
|
|
88
|
+
* needs to fix the problem. Order it in the children wherever the design
|
|
89
|
+
* calls for (before or after the control); the association is automatic.
|
|
90
|
+
*/
|
|
91
|
+
declare const FieldDescription: import("react").ForwardRefExoticComponent<FieldDescriptionProps & import("react").RefAttributes<HTMLParagraphElement>>;
|
|
92
|
+
interface FieldErrorProps extends Omit<ComponentPropsWithoutRef<typeof Field.Error>, "className"> {
|
|
93
|
+
className?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Validation message for the field, wired into `aria-describedby` and
|
|
97
|
+
* announced on appearance (`role="alert"`). In a connected field it renders
|
|
98
|
+
* the form error automatically — the message (or a list when
|
|
99
|
+
* `criteriaMode: "all"` reports several), shown exactly while the field is
|
|
100
|
+
* invalid; `children` replace the message text. In static fields it follows
|
|
101
|
+
* Base UI's native behavior: `match` picks a ValidityState condition (e.g.
|
|
102
|
+
* `match="valueMissing"`) and `children` provide the message.
|
|
103
|
+
*/
|
|
104
|
+
declare const FieldError: import("react").ForwardRefExoticComponent<FieldErrorProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
105
|
+
interface FieldItemProps extends Omit<ComponentPropsWithoutRef<typeof Field.Item>, "className"> {
|
|
106
|
+
className?: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Groups one option of a checkbox or radio group with its own label and
|
|
110
|
+
* description — inside it, `FieldLabel`/`FieldDescription` attach to that
|
|
111
|
+
* option's control instead of the whole field. Compose with `Fieldset`
|
|
112
|
+
* (legend = the group's name) per option.
|
|
113
|
+
*/
|
|
114
|
+
declare const FieldItem: import("react").ForwardRefExoticComponent<FieldItemProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
115
|
+
type FieldValidityProps = ComponentPropsWithoutRef<typeof Field.Validity>;
|
|
116
|
+
/**
|
|
117
|
+
* Render-prop over the field's native ValidityState — for custom validity UI
|
|
118
|
+
* such as inline requirement checklists. Renders no element of its own.
|
|
119
|
+
* Base UI's `Field.Validity`, re-exported unchanged.
|
|
120
|
+
*/
|
|
121
|
+
declare const FieldValidity: import("react").FC<import("@base-ui/react").FieldValidityProps>;
|
|
122
|
+
//#endregion
|
|
123
|
+
export { Field$1 as Field, FieldDescription, FieldDescriptionProps, FieldError, FieldErrorProps, FieldItem, FieldItemProps, FieldLabel, FieldLabelProps, FieldLabelVariantsOptions, FieldOrientation, FieldProps, FieldValidity, FieldValidityProps, fieldLabelVariants };
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { FieldContext } from "./FieldContext.js";
|
|
3
|
+
import { forwardRef, useContext, useMemo } from "react";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Field } from "@base-ui/react/field";
|
|
6
|
+
import { useController, useFormContext } from "react-hook-form";
|
|
7
|
+
//#region src/components/Field/Field.tsx
|
|
8
|
+
const orientationClasses = {
|
|
9
|
+
vertical: "flex min-w-0 flex-col items-stretch gap-1.5",
|
|
10
|
+
horizontal: "grid min-w-0 grid-cols-[auto_minmax(0,1fr)] items-baseline gap-x-3 gap-y-1.5"
|
|
11
|
+
};
|
|
12
|
+
function orientationAttribute(orientation) {
|
|
13
|
+
return { "data-orientation": orientation };
|
|
14
|
+
}
|
|
15
|
+
const EMPTY_MESSAGES = [];
|
|
16
|
+
function StaticField({ forwardedRef, control: _control, required = false, orientation = "vertical", invalid, className, ...rest }) {
|
|
17
|
+
const contextValue = useMemo(() => ({
|
|
18
|
+
required,
|
|
19
|
+
invalid: invalid ?? false,
|
|
20
|
+
control: null,
|
|
21
|
+
errorMessage: null,
|
|
22
|
+
errorMessages: EMPTY_MESSAGES
|
|
23
|
+
}), [required, invalid]);
|
|
24
|
+
return /* @__PURE__ */ jsx(FieldContext.Provider, {
|
|
25
|
+
value: contextValue,
|
|
26
|
+
children: /* @__PURE__ */ jsx(Field.Root, {
|
|
27
|
+
ref: forwardedRef,
|
|
28
|
+
invalid,
|
|
29
|
+
className: cn(orientationClasses[orientation], className),
|
|
30
|
+
...orientationAttribute(orientation),
|
|
31
|
+
...rest
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function ConnectedField({ forwardedRef, control, name, required = false, orientation = "vertical", disabled, invalid, touched, dirty, className, ...rest }) {
|
|
36
|
+
const { field, fieldState } = useController({
|
|
37
|
+
name,
|
|
38
|
+
control
|
|
39
|
+
});
|
|
40
|
+
const resolvedInvalid = invalid ?? Boolean(fieldState.error);
|
|
41
|
+
const errorMessage = fieldState.error?.message ?? null;
|
|
42
|
+
const errorMessages = useMemo(() => {
|
|
43
|
+
const error = fieldState.error;
|
|
44
|
+
if (!error) return EMPTY_MESSAGES;
|
|
45
|
+
const messages = /* @__PURE__ */ new Set();
|
|
46
|
+
if (error.message) messages.add(error.message);
|
|
47
|
+
if (error.types) {
|
|
48
|
+
for (const typeMessage of Object.values(error.types)) if (typeof typeMessage === "string") messages.add(typeMessage);
|
|
49
|
+
else if (Array.isArray(typeMessage)) {
|
|
50
|
+
for (const message of typeMessage) if (typeof message === "string") messages.add(message);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return [...messages];
|
|
54
|
+
}, [fieldState.error]);
|
|
55
|
+
const contextValue = useMemo(() => ({
|
|
56
|
+
required,
|
|
57
|
+
invalid: resolvedInvalid,
|
|
58
|
+
control: {
|
|
59
|
+
name: field.name,
|
|
60
|
+
value: field.value,
|
|
61
|
+
disabled: field.disabled || disabled || void 0,
|
|
62
|
+
onChange: field.onChange,
|
|
63
|
+
onBlur: field.onBlur,
|
|
64
|
+
ref: field.ref
|
|
65
|
+
},
|
|
66
|
+
errorMessage,
|
|
67
|
+
errorMessages
|
|
68
|
+
}), [
|
|
69
|
+
required,
|
|
70
|
+
resolvedInvalid,
|
|
71
|
+
field.name,
|
|
72
|
+
field.value,
|
|
73
|
+
field.disabled,
|
|
74
|
+
field.onChange,
|
|
75
|
+
field.onBlur,
|
|
76
|
+
field.ref,
|
|
77
|
+
disabled,
|
|
78
|
+
errorMessage,
|
|
79
|
+
errorMessages
|
|
80
|
+
]);
|
|
81
|
+
return /* @__PURE__ */ jsx(FieldContext.Provider, {
|
|
82
|
+
value: contextValue,
|
|
83
|
+
children: /* @__PURE__ */ jsx(Field.Root, {
|
|
84
|
+
ref: forwardedRef,
|
|
85
|
+
name: field.name,
|
|
86
|
+
invalid: resolvedInvalid,
|
|
87
|
+
touched: touched ?? fieldState.isTouched,
|
|
88
|
+
dirty: dirty ?? fieldState.isDirty,
|
|
89
|
+
disabled,
|
|
90
|
+
className: cn(orientationClasses[orientation], className),
|
|
91
|
+
...orientationAttribute(orientation),
|
|
92
|
+
...rest
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const FieldImpl = forwardRef((props, ref) => {
|
|
97
|
+
const formContext = useFormContext();
|
|
98
|
+
return props.name != null && (props.control ?? formContext) != null ? /* @__PURE__ */ jsx(ConnectedField, {
|
|
99
|
+
...props,
|
|
100
|
+
forwardedRef: ref
|
|
101
|
+
}) : /* @__PURE__ */ jsx(StaticField, {
|
|
102
|
+
...props,
|
|
103
|
+
forwardedRef: ref
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
FieldImpl.displayName = "Field";
|
|
107
|
+
/**
|
|
108
|
+
* Labelling + validation wrapper for a single form control, built on Base UI's
|
|
109
|
+
* Field. It associates `FieldLabel`, `FieldDescription`, and `FieldError`
|
|
110
|
+
* with the control automatically (ids, `aria-describedby`) and exposes state
|
|
111
|
+
* data-attributes (`data-invalid`, `data-touched`, `data-dirty`,
|
|
112
|
+
* `data-filled`, `data-focused`) on every part for styling.
|
|
113
|
+
*
|
|
114
|
+
* Give it a `name` inside `<Form form={…}>` (or pass `control`) to connect it
|
|
115
|
+
* to React Hook Form — validation state then flows in from the form and the
|
|
116
|
+
* `Input` inside is wired automatically. Without a form library it works as a
|
|
117
|
+
* native field: constraint attributes plus the `validate`/`validationMode`
|
|
118
|
+
* props drive `FieldError` via its `match` prop.
|
|
119
|
+
*/
|
|
120
|
+
const Field$1 = FieldImpl;
|
|
121
|
+
Field$1.displayName = "Field";
|
|
122
|
+
const labelClasses = "font-sans text-sm font-medium text-foreground data-disabled:opacity-50";
|
|
123
|
+
/**
|
|
124
|
+
* Class list for an element styled as a field label — for labelling controls
|
|
125
|
+
* that live outside a `Field` (e.g. a filter Select in a toolbar) so every
|
|
126
|
+
* label in the product shares one look.
|
|
127
|
+
*/
|
|
128
|
+
function fieldLabelVariants({ className } = {}) {
|
|
129
|
+
return cn(labelClasses, className);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Visible label, automatically associated with the field's control — clicking
|
|
133
|
+
* it focuses the control. When the `Field` is `required`, a decorative
|
|
134
|
+
* asterisk (hidden from assistive technology, which hears the control's
|
|
135
|
+
* required state instead) is appended. For checkbox/radio/switch rows, wrap
|
|
136
|
+
* the control instead: `<FieldLabel><Switch /> Notifications</FieldLabel>`.
|
|
137
|
+
* When the control is button-based (Select, Combobox triggers), pass
|
|
138
|
+
* `nativeLabel={false}` — the label then renders as a `<div>` wired via
|
|
139
|
+
* `aria-labelledby`, so hovering or clicking it doesn't act on the button.
|
|
140
|
+
*/
|
|
141
|
+
const FieldLabel = forwardRef(({ className, children, nativeLabel, render, ...rest }, ref) => {
|
|
142
|
+
const context = useContext(FieldContext);
|
|
143
|
+
return /* @__PURE__ */ jsxs(Field.Label, {
|
|
144
|
+
ref,
|
|
145
|
+
nativeLabel,
|
|
146
|
+
render: render ?? (nativeLabel === false ? /* @__PURE__ */ jsx("div", {}) : void 0),
|
|
147
|
+
className: cn(labelClasses, className),
|
|
148
|
+
...rest,
|
|
149
|
+
children: [children, context?.required ? /* @__PURE__ */ jsx("span", {
|
|
150
|
+
"aria-hidden": "true",
|
|
151
|
+
className: "ms-0.5 text-destructive",
|
|
152
|
+
children: "*"
|
|
153
|
+
}) : null]
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
FieldLabel.displayName = "FieldLabel";
|
|
157
|
+
const descriptionClasses = "col-start-2 font-sans text-xs text-muted-foreground data-disabled:opacity-50";
|
|
158
|
+
/**
|
|
159
|
+
* Persistent supporting copy for the field, announced via `aria-describedby`.
|
|
160
|
+
* It stays visible while an error shows — the hint is exactly what the user
|
|
161
|
+
* needs to fix the problem. Order it in the children wherever the design
|
|
162
|
+
* calls for (before or after the control); the association is automatic.
|
|
163
|
+
*/
|
|
164
|
+
const FieldDescription = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx(Field.Description, {
|
|
165
|
+
ref,
|
|
166
|
+
className: cn(descriptionClasses, className),
|
|
167
|
+
...rest
|
|
168
|
+
}));
|
|
169
|
+
FieldDescription.displayName = "FieldDescription";
|
|
170
|
+
const errorClasses = "col-start-2 flex items-start gap-1.5 font-sans text-xs font-medium text-error-700 motion-safe:transition-opacity motion-safe:duration-150 motion-safe:data-starting-style:opacity-0";
|
|
171
|
+
function ErrorIcon() {
|
|
172
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
173
|
+
viewBox: "0 0 24 24",
|
|
174
|
+
fill: "none",
|
|
175
|
+
stroke: "currentColor",
|
|
176
|
+
strokeWidth: 2,
|
|
177
|
+
strokeLinecap: "round",
|
|
178
|
+
"aria-hidden": "true",
|
|
179
|
+
className: "mt-px size-3.5 shrink-0",
|
|
180
|
+
children: [
|
|
181
|
+
/* @__PURE__ */ jsx("circle", {
|
|
182
|
+
cx: "12",
|
|
183
|
+
cy: "12",
|
|
184
|
+
r: "10"
|
|
185
|
+
}),
|
|
186
|
+
/* @__PURE__ */ jsx("path", { d: "M12 8v4" }),
|
|
187
|
+
/* @__PURE__ */ jsx("path", { d: "M12 16h.01" })
|
|
188
|
+
]
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Validation message for the field, wired into `aria-describedby` and
|
|
193
|
+
* announced on appearance (`role="alert"`). In a connected field it renders
|
|
194
|
+
* the form error automatically — the message (or a list when
|
|
195
|
+
* `criteriaMode: "all"` reports several), shown exactly while the field is
|
|
196
|
+
* invalid; `children` replace the message text. In static fields it follows
|
|
197
|
+
* Base UI's native behavior: `match` picks a ValidityState condition (e.g.
|
|
198
|
+
* `match="valueMissing"`) and `children` provide the message.
|
|
199
|
+
*/
|
|
200
|
+
const FieldError = forwardRef(({ className, children, match, ...rest }, ref) => {
|
|
201
|
+
const context = useContext(FieldContext);
|
|
202
|
+
const connected = context?.control != null;
|
|
203
|
+
const connectedMessage = connected && context ? context.errorMessages.length > 1 ? /* @__PURE__ */ jsx("ul", {
|
|
204
|
+
className: "flex list-disc flex-col gap-0.5 ps-4",
|
|
205
|
+
children: context.errorMessages.map((message) => /* @__PURE__ */ jsx("li", { children: message }, message))
|
|
206
|
+
}) : context.errorMessage : void 0;
|
|
207
|
+
const content = children ?? connectedMessage;
|
|
208
|
+
const resolvedMatch = match ?? (connected && context ? context.invalid && content != null : void 0);
|
|
209
|
+
return /* @__PURE__ */ jsx(Field.Error, {
|
|
210
|
+
ref,
|
|
211
|
+
role: "alert",
|
|
212
|
+
match: resolvedMatch,
|
|
213
|
+
className: cn(errorClasses, className),
|
|
214
|
+
...rest,
|
|
215
|
+
children: content != null ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ErrorIcon, {}), /* @__PURE__ */ jsx("span", {
|
|
216
|
+
className: "min-w-0",
|
|
217
|
+
children: content
|
|
218
|
+
})] }) : void 0
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
FieldError.displayName = "FieldError";
|
|
222
|
+
/**
|
|
223
|
+
* Groups one option of a checkbox or radio group with its own label and
|
|
224
|
+
* description — inside it, `FieldLabel`/`FieldDescription` attach to that
|
|
225
|
+
* option's control instead of the whole field. Compose with `Fieldset`
|
|
226
|
+
* (legend = the group's name) per option.
|
|
227
|
+
*/
|
|
228
|
+
const FieldItem = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx(Field.Item, {
|
|
229
|
+
ref,
|
|
230
|
+
className: cn("flex min-w-0 flex-col gap-1", className),
|
|
231
|
+
...rest
|
|
232
|
+
}));
|
|
233
|
+
FieldItem.displayName = "FieldItem";
|
|
234
|
+
/**
|
|
235
|
+
* Render-prop over the field's native ValidityState — for custom validity UI
|
|
236
|
+
* such as inline requirement checklists. Renders no element of its own.
|
|
237
|
+
* Base UI's `Field.Validity`, re-exported unchanged.
|
|
238
|
+
*/
|
|
239
|
+
const FieldValidity = Field.Validity;
|
|
240
|
+
//#endregion
|
|
241
|
+
export { Field$1 as Field, FieldDescription, FieldError, FieldItem, FieldLabel, FieldValidity, fieldLabelVariants };
|