@ui-sdk/react 0.0.0-stage → 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +10 -2
- package/dist/accordion.d.ts +331 -0
- package/dist/accordion.js +25 -0
- package/dist/agent.d.ts +2 -0
- package/dist/agent.js +8 -0
- package/dist/alert-dialog.d.ts +56 -0
- package/dist/alert-dialog.js +45 -0
- package/dist/async-options.d.ts +22 -0
- package/dist/async-options.js +56 -0
- package/dist/autocomplete.d.ts +102 -0
- package/dist/autocomplete.js +195 -0
- package/dist/avatar.d.ts +301 -0
- package/dist/avatar.js +17 -0
- package/dist/button.d.ts +21 -0
- package/dist/button.js +45 -0
- package/dist/calendar-context.d.ts +10 -0
- package/dist/calendar-context.js +9 -0
- package/dist/calendar.d.ts +80 -0
- package/dist/calendar.js +257 -0
- package/dist/carousel.d.ts +52 -0
- package/dist/carousel.js +151 -0
- package/dist/checkbox.d.ts +24 -0
- package/dist/checkbox.js +98 -0
- package/dist/children.d.ts +38 -0
- package/dist/children.js +63 -0
- package/dist/collapsible.d.ts +302 -0
- package/dist/collapsible.js +19 -0
- package/dist/color-picker.d.ts +72 -0
- package/dist/color-picker.js +133 -0
- package/dist/color.d.ts +2 -0
- package/dist/color.js +22 -0
- package/dist/combobox.d.ts +152 -0
- package/dist/combobox.js +338 -0
- package/dist/command.d.ts +88 -0
- package/dist/command.js +233 -0
- package/dist/controller-target.d.ts +3 -0
- package/dist/controller-target.js +59 -0
- package/dist/date-input.d.ts +19 -0
- package/dist/date-input.js +58 -0
- package/dist/date-picker.d.ts +47 -0
- package/dist/date-picker.js +310 -0
- package/dist/date.d.ts +2 -0
- package/dist/date.js +60 -0
- package/dist/dialog-parts.d.ts +23 -0
- package/dist/dialog-parts.js +142 -0
- package/dist/dialog.d.ts +57 -0
- package/dist/dialog.js +32 -0
- package/dist/drawer.d.ts +70 -0
- package/dist/drawer.js +158 -0
- package/dist/editor-context.d.ts +4 -0
- package/dist/editor-context.js +9 -0
- package/dist/field-context.d.ts +47 -0
- package/dist/field-context.js +87 -0
- package/dist/field.d.ts +49 -0
- package/dist/field.js +169 -0
- package/dist/file-input.d.ts +46 -0
- package/dist/file-input.js +170 -0
- package/dist/form-inputs.d.ts +5 -0
- package/dist/form-inputs.js +22 -0
- package/dist/gesture.d.ts +1 -0
- package/dist/gesture.js +16 -0
- package/dist/history.d.ts +2 -0
- package/dist/history.js +12 -0
- package/dist/hover-card.d.ts +33 -0
- package/dist/hover-card.js +84 -0
- package/dist/image-cropper.d.ts +333 -0
- package/dist/image-cropper.js +37 -0
- package/dist/image.d.ts +2 -0
- package/dist/image.js +6 -0
- package/dist/input.d.ts +22 -0
- package/dist/input.js +51 -0
- package/dist/label.d.ts +294 -0
- package/dist/label.js +9 -0
- package/dist/list-items.d.ts +15 -0
- package/dist/list-items.js +39 -0
- package/dist/list-text.d.ts +4 -0
- package/dist/list-text.js +15 -0
- package/dist/listbox.d.ts +56 -0
- package/dist/listbox.js +122 -0
- package/dist/menu.d.ts +116 -0
- package/dist/menu.js +426 -0
- package/dist/menubar-context.d.ts +4 -0
- package/dist/menubar-context.js +7 -0
- package/dist/menubar.d.ts +11 -0
- package/dist/menubar.js +32 -0
- package/dist/meter.d.ts +312 -0
- package/dist/meter.js +30 -0
- package/dist/navigation-menu.d.ts +61 -0
- package/dist/navigation-menu.js +169 -0
- package/dist/number-input.d.ts +44 -0
- package/dist/number-input.js +185 -0
- package/dist/number.d.ts +2 -0
- package/dist/number.js +40 -0
- package/dist/observe.d.ts +2 -0
- package/dist/observe.js +8 -0
- package/dist/otp-input.d.ts +29 -0
- package/dist/otp-input.js +94 -0
- package/dist/overlays.d.ts +26 -0
- package/dist/overlays.js +82 -0
- package/dist/pagination.d.ts +336 -0
- package/dist/pagination.js +71 -0
- package/dist/password-input.d.ts +23 -0
- package/dist/password-input.js +65 -0
- package/dist/popover.d.ts +54 -0
- package/dist/popover.js +151 -0
- package/dist/popup.d.ts +41 -0
- package/dist/popup.js +180 -0
- package/dist/preferences.d.ts +35 -0
- package/dist/preferences.js +93 -0
- package/dist/primitive.d.ts +2 -0
- package/dist/primitive.js +14 -0
- package/dist/progress.d.ts +312 -0
- package/dist/progress.js +30 -0
- package/dist/radio.d.ts +22 -0
- package/dist/radio.js +86 -0
- package/dist/rating.d.ts +20 -0
- package/dist/rating.js +94 -0
- package/dist/render-element.d.ts +35 -0
- package/dist/render-element.js +103 -0
- package/dist/resizable.d.ts +302 -0
- package/dist/resizable.js +23 -0
- package/dist/scroll-area.d.ts +324 -0
- package/dist/scroll-area.js +49 -0
- package/dist/segmented-control.d.ts +24 -0
- package/dist/segmented-control.js +78 -0
- package/dist/segmented-input.d.ts +15 -0
- package/dist/segmented-input.js +48 -0
- package/dist/select.d.ts +125 -0
- package/dist/select.js +330 -0
- package/dist/separator.d.ts +290 -0
- package/dist/separator.js +9 -0
- package/dist/shortcuts.d.ts +32 -0
- package/dist/shortcuts.js +61 -0
- package/dist/slider.d.ts +38 -0
- package/dist/slider.js +163 -0
- package/dist/switch.d.ts +15 -0
- package/dist/switch.js +39 -0
- package/dist/tabs.d.ts +331 -0
- package/dist/tabs.js +28 -0
- package/dist/text-control.d.ts +22 -0
- package/dist/text-control.js +24 -0
- package/dist/text-match.d.ts +2 -0
- package/dist/text-match.js +8 -0
- package/dist/textarea.d.ts +10 -0
- package/dist/textarea.js +48 -0
- package/dist/time-input.d.ts +19 -0
- package/dist/time-input.js +63 -0
- package/dist/timeline.d.ts +327 -0
- package/dist/timeline.js +31 -0
- package/dist/toast-parts.d.ts +63 -0
- package/dist/toast-parts.js +144 -0
- package/dist/toast.d.ts +2 -0
- package/dist/toast.js +22 -0
- package/dist/toggle.d.ts +23 -0
- package/dist/toggle.js +76 -0
- package/dist/token-input.d.ts +35 -0
- package/dist/token-input.js +100 -0
- package/dist/toolbar-context.d.ts +6 -0
- package/dist/toolbar-context.js +16 -0
- package/dist/toolbar.d.ts +38 -0
- package/dist/toolbar.js +63 -0
- package/dist/tooltip.d.ts +39 -0
- package/dist/tooltip.js +108 -0
- package/dist/tree.d.ts +51 -0
- package/dist/tree.js +150 -0
- package/dist/trigger-menu.d.ts +83 -0
- package/dist/trigger-menu.js +167 -0
- package/dist/use-primitive.d.ts +178 -0
- package/dist/use-primitive.js +674 -0
- package/dist/waterfall.d.ts +80 -0
- package/dist/waterfall.js +108 -0
- package/docs/README.md +89 -0
- package/docs/agents.md +1523 -0
- package/docs/components/accordion.md +1391 -0
- package/docs/components/alert-dialog.md +850 -0
- package/docs/components/autocomplete.md +1963 -0
- package/docs/components/avatar.md +252 -0
- package/docs/components/button.md +444 -0
- package/docs/components/calendar.md +1687 -0
- package/docs/components/carousel.md +1244 -0
- package/docs/components/checkbox.md +1069 -0
- package/docs/components/collapsible.md +567 -0
- package/docs/components/color-picker.md +736 -0
- package/docs/components/combobox.md +3647 -0
- package/docs/components/command.md +1573 -0
- package/docs/components/date-input.md +608 -0
- package/docs/components/date-picker.md +1266 -0
- package/docs/components/dialog.md +1469 -0
- package/docs/components/drawer.md +1197 -0
- package/docs/components/field.md +549 -0
- package/docs/components/file-input.md +609 -0
- package/docs/components/hover-card.md +514 -0
- package/docs/components/image-cropper.md +579 -0
- package/docs/components/input.md +301 -0
- package/docs/components/label.md +217 -0
- package/docs/components/listbox.md +1130 -0
- package/docs/components/menu.md +1286 -0
- package/docs/components/menubar.md +455 -0
- package/docs/components/meter.md +304 -0
- package/docs/components/navigation-menu.md +1581 -0
- package/docs/components/number-input.md +1086 -0
- package/docs/components/otp-input.md +565 -0
- package/docs/components/pagination.md +648 -0
- package/docs/components/password-input.md +737 -0
- package/docs/components/popover.md +1552 -0
- package/docs/components/preferences.md +220 -0
- package/docs/components/progress.md +443 -0
- package/docs/components/radio.md +846 -0
- package/docs/components/rating.md +458 -0
- package/docs/components/resizable.md +982 -0
- package/docs/components/scroll-area.md +980 -0
- package/docs/components/segmented-control.md +465 -0
- package/docs/components/select.md +2133 -0
- package/docs/components/separator.md +243 -0
- package/docs/components/slider.md +1169 -0
- package/docs/components/switch.md +613 -0
- package/docs/components/tabs.md +1014 -0
- package/docs/components/textarea.md +318 -0
- package/docs/components/time-input.md +231 -0
- package/docs/components/timeline.md +677 -0
- package/docs/components/toast.md +1395 -0
- package/docs/components/toggle.md +541 -0
- package/docs/components/token-input.md +1007 -0
- package/docs/components/toolbar.md +787 -0
- package/docs/components/tooltip.md +884 -0
- package/docs/components/tree.md +1346 -0
- package/docs/components/trigger-menu.md +1257 -0
- package/docs/components/waterfall.md +754 -0
- package/docs/controllers.md +89 -0
- package/docs/core.md +8027 -0
- package/docs/custom-parts.md +120 -0
- package/docs/first-component.md +83 -0
- package/docs/forms.md +148 -0
- package/docs/hooks/async-options.md +366 -0
- package/docs/hooks/shortcuts.md +221 -0
- package/docs/installation.md +45 -0
- package/docs/introduction.md +32 -0
- package/docs/lists-and-menus.md +170 -0
- package/docs/llms.txt +1844 -0
- package/docs/parts-and-composition.md +93 -0
- package/docs/popups.md +117 -0
- package/docs/rendering.md +121 -0
- package/docs/server-rendering.md +253 -0
- package/docs/state-and-events.md +105 -0
- package/docs/styling-and-animation.md +176 -0
- package/package.json +333 -3
package/dist/drawer.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/drawer.tsx
|
|
3
|
+
import {
|
|
4
|
+
drawer
|
|
5
|
+
} from "@ui-sdk/core/drawer";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import {
|
|
8
|
+
Connected,
|
|
9
|
+
renderPopup,
|
|
10
|
+
sheetViewport,
|
|
11
|
+
useControllerEntry,
|
|
12
|
+
useOwnContainer,
|
|
13
|
+
usePopupContainer
|
|
14
|
+
} from "./popup.js";
|
|
15
|
+
import {
|
|
16
|
+
createParts,
|
|
17
|
+
HandleScope,
|
|
18
|
+
renderElement,
|
|
19
|
+
useHandle,
|
|
20
|
+
useNearest,
|
|
21
|
+
usePart,
|
|
22
|
+
usePrimitive
|
|
23
|
+
} from "./use-primitive.js";
|
|
24
|
+
import { createDrawerController, sheetPhysics } from "@ui-sdk/core/drawer";
|
|
25
|
+
import { jsx } from "react/jsx-runtime";
|
|
26
|
+
var parts = createParts(drawer, {
|
|
27
|
+
trigger: "button",
|
|
28
|
+
handle: "button",
|
|
29
|
+
title: "h2",
|
|
30
|
+
description: "p",
|
|
31
|
+
close: "button",
|
|
32
|
+
outlet: "div"
|
|
33
|
+
});
|
|
34
|
+
var ContainerContext = React.createContext(void 0);
|
|
35
|
+
var TriggerContext = React.createContext(null);
|
|
36
|
+
function Drawer({ children, container, ...options }) {
|
|
37
|
+
const handle = usePrimitive(drawer, options);
|
|
38
|
+
useControllerEntry(options.controller, handle);
|
|
39
|
+
return /* @__PURE__ */ jsx(HandleScope, { handle, children: /* @__PURE__ */ jsx(ContainerContext.Provider, { value: container, children }) });
|
|
40
|
+
}
|
|
41
|
+
function DrawerTrigger({ controller, ...props }) {
|
|
42
|
+
const {
|
|
43
|
+
disabled,
|
|
44
|
+
focusableWhenDisabled,
|
|
45
|
+
payload: _,
|
|
46
|
+
shortcut,
|
|
47
|
+
render,
|
|
48
|
+
...rest
|
|
49
|
+
} = props;
|
|
50
|
+
const unconnected = () => renderElement(
|
|
51
|
+
"button",
|
|
52
|
+
{
|
|
53
|
+
type: "button",
|
|
54
|
+
disabled: disabled && !focusableWhenDisabled,
|
|
55
|
+
"aria-disabled": disabled && focusableWhenDisabled || void 0,
|
|
56
|
+
...rest
|
|
57
|
+
},
|
|
58
|
+
render,
|
|
59
|
+
{
|
|
60
|
+
open: false,
|
|
61
|
+
disabled: !!disabled
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
return /* @__PURE__ */ jsx(TriggerContext.Provider, { value: { shortcut }, children: /* @__PURE__ */ jsx(
|
|
65
|
+
Connected,
|
|
66
|
+
{
|
|
67
|
+
primitive: drawer,
|
|
68
|
+
controller,
|
|
69
|
+
fallback: unconnected,
|
|
70
|
+
children: /* @__PURE__ */ jsx(parts.Trigger, { ...props })
|
|
71
|
+
}
|
|
72
|
+
) });
|
|
73
|
+
}
|
|
74
|
+
function DrawerBackdrop(props) {
|
|
75
|
+
const target = usePopupContainer(React.useContext(ContainerContext));
|
|
76
|
+
const element = usePart(drawer, "backdrop", {}, props);
|
|
77
|
+
return element && renderPopup(element, target);
|
|
78
|
+
}
|
|
79
|
+
function DrawerContent({
|
|
80
|
+
initialFocus,
|
|
81
|
+
finalFocus,
|
|
82
|
+
keepMounted,
|
|
83
|
+
container,
|
|
84
|
+
render,
|
|
85
|
+
...props
|
|
86
|
+
}) {
|
|
87
|
+
const handle = useHandle(drawer);
|
|
88
|
+
const target = usePopupContainer(useOwnContainer(container, ContainerContext));
|
|
89
|
+
const partProps = {
|
|
90
|
+
...props,
|
|
91
|
+
render: sheetViewport(handle, render)
|
|
92
|
+
};
|
|
93
|
+
const element = usePart(
|
|
94
|
+
handle,
|
|
95
|
+
"content",
|
|
96
|
+
{ initialFocus, finalFocus, keepMounted },
|
|
97
|
+
partProps
|
|
98
|
+
);
|
|
99
|
+
return element && renderPopup(element, target);
|
|
100
|
+
}
|
|
101
|
+
var DrawerHandle = parts.Handle;
|
|
102
|
+
var DrawerTitle = parts.Title;
|
|
103
|
+
var DrawerDescription = parts.Description;
|
|
104
|
+
var DrawerClose = parts.Close;
|
|
105
|
+
function DrawerShortcut(props) {
|
|
106
|
+
const trigger = React.useContext(TriggerContext);
|
|
107
|
+
if (useNearest(drawer)) {
|
|
108
|
+
return /* @__PURE__ */ jsx(ShortcutPart, { inherited: trigger?.shortcut, ...props });
|
|
109
|
+
}
|
|
110
|
+
if (trigger) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
throw new Error("Drawer parts must be used inside <Drawer>.");
|
|
114
|
+
}
|
|
115
|
+
var text = (state) => state.text;
|
|
116
|
+
function ShortcutPart({
|
|
117
|
+
inherited,
|
|
118
|
+
shortcut,
|
|
119
|
+
children = text,
|
|
120
|
+
...props
|
|
121
|
+
}) {
|
|
122
|
+
return usePart(
|
|
123
|
+
drawer,
|
|
124
|
+
"shortcut",
|
|
125
|
+
{ shortcut: shortcut ?? inherited },
|
|
126
|
+
{ ...props, children },
|
|
127
|
+
"span"
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
function DrawerOutlet({
|
|
131
|
+
controller,
|
|
132
|
+
...props
|
|
133
|
+
}) {
|
|
134
|
+
const { keyframes: _, render, ...rest } = props;
|
|
135
|
+
return /* @__PURE__ */ jsx(
|
|
136
|
+
Connected,
|
|
137
|
+
{
|
|
138
|
+
primitive: drawer,
|
|
139
|
+
controller,
|
|
140
|
+
fallback: () => renderElement("div", rest, render, { open: false }),
|
|
141
|
+
children: /* @__PURE__ */ jsx(parts.Outlet, { ...props })
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
Drawer,
|
|
147
|
+
DrawerBackdrop,
|
|
148
|
+
DrawerClose,
|
|
149
|
+
DrawerContent,
|
|
150
|
+
DrawerDescription,
|
|
151
|
+
DrawerHandle,
|
|
152
|
+
DrawerOutlet,
|
|
153
|
+
DrawerShortcut,
|
|
154
|
+
DrawerTitle,
|
|
155
|
+
DrawerTrigger,
|
|
156
|
+
createDrawerController,
|
|
157
|
+
sheetPhysics
|
|
158
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { field } from "@ui-sdk/core/field";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { type PartProps, type PrimitiveHandle, type RenderProp } from "./use-primitive.js";
|
|
4
|
+
type FieldContextValue = PrimitiveHandle<typeof field> & {
|
|
5
|
+
name?: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
};
|
|
8
|
+
declare const FieldContext: React.Context<FieldContextValue | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Controls inside a field take its name and disabled state, and its ids and
|
|
11
|
+
* validity through the field's control slot. Null outside a field. The control
|
|
12
|
+
* re-renders when the field changes, like when its label or errors appear.
|
|
13
|
+
* The control takes the field's id, so the label points at it from the
|
|
14
|
+
* server's HTML on, unless its own props give one. A control whose component
|
|
15
|
+
* makes the id it renders, like a select's trigger, passes those props as `own`.
|
|
16
|
+
* @stable
|
|
17
|
+
*/
|
|
18
|
+
declare function useFieldControl(own?: {
|
|
19
|
+
id?: string;
|
|
20
|
+
}): {
|
|
21
|
+
name: string | undefined;
|
|
22
|
+
disabled: boolean | undefined;
|
|
23
|
+
props: (props: Record<string, any>) => {
|
|
24
|
+
"aria-labelledby": any;
|
|
25
|
+
"data-slot": any;
|
|
26
|
+
};
|
|
27
|
+
} | null;
|
|
28
|
+
declare function useJoinField(field: FieldContextValue | null, own?: {
|
|
29
|
+
id?: string;
|
|
30
|
+
}): {
|
|
31
|
+
name: string | undefined;
|
|
32
|
+
disabled: boolean | undefined;
|
|
33
|
+
props: (props: Record<string, any>) => {
|
|
34
|
+
"aria-labelledby": any;
|
|
35
|
+
"data-slot": any;
|
|
36
|
+
};
|
|
37
|
+
} | null;
|
|
38
|
+
declare function ownDescription<Props extends Record<string, any>, Render>(props: Props, render: Render): readonly [Props, Render];
|
|
39
|
+
/**
|
|
40
|
+
* A control's `render`: its element, with the field's attributes for its
|
|
41
|
+
* control merged in when it's in a field, and then `after`, like the hidden
|
|
42
|
+
* native input of a checkbox.
|
|
43
|
+
*/
|
|
44
|
+
declare function controlRender<State>(field: ReturnType<typeof useFieldControl>, tag: string, render?: RenderProp<State>, after?: React.ReactNode): RenderProp<State> | ((props: Record<string, any>, state: State) => React.FunctionComponentElement<React.FragmentProps>) | undefined;
|
|
45
|
+
type ButtonControlProps<State> = Omit<PartProps<"button", State>, "value" | "name" | "form" | "defaultChecked" | "defaultValue" | "onChange" | "onSelect">;
|
|
46
|
+
declare function useFieldControlId(): string | undefined;
|
|
47
|
+
export { type ButtonControlProps, controlRender, FieldContext, type FieldContextValue, ownDescription, useFieldControl, useFieldControlId, useJoinField, };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/field-context.ts
|
|
3
|
+
import { fieldControlId, madeLabel, renderVersion } from "@ui-sdk/core/renderer";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import {
|
|
6
|
+
renderElement,
|
|
7
|
+
slotIn
|
|
8
|
+
} from "./use-primitive.js";
|
|
9
|
+
var FieldContext = React.createContext(null);
|
|
10
|
+
var noop = () => () => {
|
|
11
|
+
};
|
|
12
|
+
var zero = () => 0;
|
|
13
|
+
function useFieldControl(own) {
|
|
14
|
+
return useJoinField(React.useContext(FieldContext), own);
|
|
15
|
+
}
|
|
16
|
+
function useJoinField(field, own) {
|
|
17
|
+
const version = field ? () => renderVersion(field.instance) : zero;
|
|
18
|
+
React.useSyncExternalStore(
|
|
19
|
+
field ? field.instance.subscribe : noop,
|
|
20
|
+
version,
|
|
21
|
+
version
|
|
22
|
+
);
|
|
23
|
+
if (!field) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
name: field.name,
|
|
28
|
+
disabled: field.disabled,
|
|
29
|
+
// Merges the field's attributes for its control into the control's props,
|
|
30
|
+
// keeping the control's own description ahead of the field's. The field
|
|
31
|
+
// decides the id.
|
|
32
|
+
props: (props) => {
|
|
33
|
+
const label = props["aria-labelledby"];
|
|
34
|
+
const merged = slotIn(
|
|
35
|
+
field,
|
|
36
|
+
"control",
|
|
37
|
+
{ id: (own ?? props).id, describedBy: props["aria-describedby"] },
|
|
38
|
+
{
|
|
39
|
+
...props,
|
|
40
|
+
id: void 0,
|
|
41
|
+
"aria-labelledby": madeLabel(label) ? void 0 : label
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
return {
|
|
45
|
+
...merged,
|
|
46
|
+
"aria-labelledby": merged["aria-labelledby"] ?? label,
|
|
47
|
+
"data-slot": props["data-slot"]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function ownDescription(props, render) {
|
|
53
|
+
const own = React.isValidElement(render) ? render.props["aria-describedby"] : void 0;
|
|
54
|
+
if (own === void 0 || !React.isValidElement(render)) {
|
|
55
|
+
return [props, render];
|
|
56
|
+
}
|
|
57
|
+
const element = React.cloneElement(render, {
|
|
58
|
+
"aria-describedby": void 0
|
|
59
|
+
});
|
|
60
|
+
return [{ ...props, "aria-describedby": own }, element];
|
|
61
|
+
}
|
|
62
|
+
function controlRender(field, tag, render, after) {
|
|
63
|
+
if (!field && !after) {
|
|
64
|
+
return render;
|
|
65
|
+
}
|
|
66
|
+
return (props, state) => {
|
|
67
|
+
const [own, element] = field ? ownDescription(props, render) : [props, render];
|
|
68
|
+
return React.createElement(
|
|
69
|
+
React.Fragment,
|
|
70
|
+
null,
|
|
71
|
+
renderElement(tag, field ? field.props(own) : own, element, state),
|
|
72
|
+
after
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function useFieldControlId() {
|
|
77
|
+
const field = React.useContext(FieldContext);
|
|
78
|
+
return field ? fieldControlId(field.api.id) : void 0;
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
FieldContext,
|
|
82
|
+
controlRender,
|
|
83
|
+
ownDescription,
|
|
84
|
+
useFieldControl,
|
|
85
|
+
useFieldControlId,
|
|
86
|
+
useJoinField
|
|
87
|
+
};
|
package/dist/field.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type FieldDescriptionState, type FieldErrorProps, type FieldErrorState, type FieldOptions, type FieldSetOptions, type FieldSetState, type FieldState } from "@ui-sdk/core/field";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { type PartProps } from "./use-primitive.js";
|
|
4
|
+
/**
|
|
5
|
+
* Ties a form control to its label, description and error messages.
|
|
6
|
+
* @stable
|
|
7
|
+
*/
|
|
8
|
+
declare function Field({ name, disabled, invalid, debug, ...props }: FieldOptions & PartProps<"div", FieldState>): React.JSX.Element;
|
|
9
|
+
/**
|
|
10
|
+
* The field's label, which names its control. Outside a Field it's a plain
|
|
11
|
+
* <label>, which labels the control inside it, like a card around a whole Field.
|
|
12
|
+
* @stable
|
|
13
|
+
*/
|
|
14
|
+
declare function FieldLabel(props: PartProps<"label", FieldState>): React.JSX.Element;
|
|
15
|
+
/**
|
|
16
|
+
* Describes its Field. Right inside a FieldSet, outside any Field, it describes
|
|
17
|
+
* the group, so screen readers say it as focus enters the group.
|
|
18
|
+
* @stable
|
|
19
|
+
*/
|
|
20
|
+
declare function FieldDescription(props: PartProps<"p", FieldDescriptionState>): React.JSX.Element;
|
|
21
|
+
/**
|
|
22
|
+
* Shows while the field shows as invalid. Without children, it shows the
|
|
23
|
+
* browser's message for the current problem.
|
|
24
|
+
* @stable
|
|
25
|
+
*/
|
|
26
|
+
declare function FieldError({ match, children, ...props }: PartProps<"div", FieldErrorState> & FieldErrorProps): React.JSX.Element | null;
|
|
27
|
+
/**
|
|
28
|
+
* A native control: an <input> by default, or anything through `render`.
|
|
29
|
+
* @stable
|
|
30
|
+
*/
|
|
31
|
+
declare function FieldControl({ name, render, ...rest }: PartProps<"input", FieldState>): React.JSX.Element;
|
|
32
|
+
/**
|
|
33
|
+
* A native <fieldset>, so `disabled` disables every control inside it.
|
|
34
|
+
* @stable
|
|
35
|
+
*/
|
|
36
|
+
declare function FieldSet({ disabled, debug, ...props }: FieldSetOptions & Omit<PartProps<"fieldset", FieldSetState>, "disabled">): React.JSX.Element;
|
|
37
|
+
/**
|
|
38
|
+
* Names the field set. Keep it the set's first child, where a <legend> names it natively.
|
|
39
|
+
* @stable
|
|
40
|
+
*/
|
|
41
|
+
declare function FieldLegend(props: PartProps<"legend", FieldSetState>): React.JSX.Element | null;
|
|
42
|
+
/**
|
|
43
|
+
* Lays fields out. It has no role: a FieldSet is what names and disables a group.
|
|
44
|
+
* @stable
|
|
45
|
+
*/
|
|
46
|
+
declare function FieldGroup(props: PartProps<"div">): React.JSX.Element | null;
|
|
47
|
+
export { Field, FieldControl, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSet, };
|
|
48
|
+
export type { FieldApi, FieldDescriptionState, FieldErrorProps, FieldErrorState, FieldGroupPrimitive, FieldOptions, FieldPrimitive, FieldSetOptions, FieldSetPrimitive, FieldSetState, FieldState, ValidityKey, } from "@ui-sdk/core/field";
|
|
49
|
+
export { useFieldControl } from "./field-context.js";
|
package/dist/field.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/field.tsx
|
|
3
|
+
import {
|
|
4
|
+
fieldGroup,
|
|
5
|
+
field as fieldPrimitive,
|
|
6
|
+
fieldSet
|
|
7
|
+
} from "@ui-sdk/core/field";
|
|
8
|
+
import {
|
|
9
|
+
checkFieldOutside,
|
|
10
|
+
fieldOutsideAttrs,
|
|
11
|
+
fieldOutsideErrorShown,
|
|
12
|
+
fieldOutsideState
|
|
13
|
+
} from "@ui-sdk/core/renderer";
|
|
14
|
+
import * as React from "react";
|
|
15
|
+
import { FieldContext, ownDescription } from "./field-context.js";
|
|
16
|
+
import {
|
|
17
|
+
extendHandle,
|
|
18
|
+
mergeProps,
|
|
19
|
+
renderElement,
|
|
20
|
+
usePart,
|
|
21
|
+
usePrimitive
|
|
22
|
+
} from "./use-primitive.js";
|
|
23
|
+
import { useFieldControl } from "./field-context.js";
|
|
24
|
+
import { jsx } from "react/jsx-runtime";
|
|
25
|
+
var DescribedContext = React.createContext(null);
|
|
26
|
+
var outsideRefs = {
|
|
27
|
+
label: (el) => checkFieldOutside(
|
|
28
|
+
el,
|
|
29
|
+
"label",
|
|
30
|
+
"Put the control inside it, or point its `htmlFor` at the control."
|
|
31
|
+
),
|
|
32
|
+
control: (el) => checkFieldOutside(el, "control")
|
|
33
|
+
};
|
|
34
|
+
function outside(slot, tag, { render, ...props }) {
|
|
35
|
+
const ref = outsideRefs[slot];
|
|
36
|
+
return renderElement(
|
|
37
|
+
tag,
|
|
38
|
+
mergeProps(fieldOutsideAttrs(slot), props, { ref }),
|
|
39
|
+
render,
|
|
40
|
+
fieldOutsideState
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
function InField({
|
|
44
|
+
field,
|
|
45
|
+
slot,
|
|
46
|
+
part,
|
|
47
|
+
props,
|
|
48
|
+
tag
|
|
49
|
+
}) {
|
|
50
|
+
return usePart(field, slot, part, props, tag);
|
|
51
|
+
}
|
|
52
|
+
function Field({
|
|
53
|
+
name,
|
|
54
|
+
disabled,
|
|
55
|
+
invalid,
|
|
56
|
+
debug,
|
|
57
|
+
...props
|
|
58
|
+
}) {
|
|
59
|
+
const field = usePrimitive(fieldPrimitive, { name, disabled, invalid, debug });
|
|
60
|
+
const context = React.useMemo(
|
|
61
|
+
() => extendHandle(field, { name, disabled }),
|
|
62
|
+
[field, name, disabled]
|
|
63
|
+
);
|
|
64
|
+
return /* @__PURE__ */ jsx(FieldContext.Provider, { value: context, children: /* @__PURE__ */ jsx(DescribedContext.Provider, { value: field, children: usePart(field, "root", {}, props, "div") }) });
|
|
65
|
+
}
|
|
66
|
+
function FieldLabel(props) {
|
|
67
|
+
const field = React.useContext(FieldContext);
|
|
68
|
+
if (!field) {
|
|
69
|
+
return outside("label", "label", props);
|
|
70
|
+
}
|
|
71
|
+
return /* @__PURE__ */ jsx(
|
|
72
|
+
InField,
|
|
73
|
+
{
|
|
74
|
+
field,
|
|
75
|
+
slot: "label",
|
|
76
|
+
part: { id: props.id },
|
|
77
|
+
props,
|
|
78
|
+
tag: "label"
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
function FieldDescription(props) {
|
|
83
|
+
const described = React.useContext(DescribedContext);
|
|
84
|
+
if (!described) {
|
|
85
|
+
return outside("description", "p", props);
|
|
86
|
+
}
|
|
87
|
+
const owner = described;
|
|
88
|
+
return /* @__PURE__ */ jsx(
|
|
89
|
+
InField,
|
|
90
|
+
{
|
|
91
|
+
field: owner,
|
|
92
|
+
slot: "description",
|
|
93
|
+
part: { id: props.id },
|
|
94
|
+
props,
|
|
95
|
+
tag: "p"
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
function FieldError({
|
|
100
|
+
match,
|
|
101
|
+
children = message,
|
|
102
|
+
...props
|
|
103
|
+
}) {
|
|
104
|
+
const field = React.useContext(FieldContext);
|
|
105
|
+
const made = React.useId();
|
|
106
|
+
if (!field) {
|
|
107
|
+
return fieldOutsideErrorShown({ match }) ? outside("error", "div", { ...props, children }) : null;
|
|
108
|
+
}
|
|
109
|
+
const id = props.id ?? (match === void 0 ? void 0 : made);
|
|
110
|
+
return /* @__PURE__ */ jsx(
|
|
111
|
+
InField,
|
|
112
|
+
{
|
|
113
|
+
field,
|
|
114
|
+
slot: "error",
|
|
115
|
+
part: { id, match },
|
|
116
|
+
props: { ...props, children },
|
|
117
|
+
tag: "div"
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
var message = (state) => state.message;
|
|
122
|
+
function FieldControl({
|
|
123
|
+
name,
|
|
124
|
+
render,
|
|
125
|
+
...rest
|
|
126
|
+
}) {
|
|
127
|
+
const field = React.useContext(FieldContext);
|
|
128
|
+
if (!field) {
|
|
129
|
+
return outside("control", "input", { ...rest, name, render });
|
|
130
|
+
}
|
|
131
|
+
const [props, element] = ownDescription(rest, render);
|
|
132
|
+
const control = { id: props.id, describedBy: props["aria-describedby"] };
|
|
133
|
+
const user = { ...props, render: element, name: name ?? field.name };
|
|
134
|
+
return /* @__PURE__ */ jsx(
|
|
135
|
+
InField,
|
|
136
|
+
{
|
|
137
|
+
field,
|
|
138
|
+
slot: "control",
|
|
139
|
+
part: control,
|
|
140
|
+
props: user,
|
|
141
|
+
tag: "input"
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
function FieldSet({
|
|
146
|
+
disabled,
|
|
147
|
+
debug,
|
|
148
|
+
...props
|
|
149
|
+
}) {
|
|
150
|
+
const set = usePrimitive(fieldSet, { disabled, debug });
|
|
151
|
+
return /* @__PURE__ */ jsx(DescribedContext.Provider, { value: set, children: usePart(set, "set", {}, props, "fieldset") });
|
|
152
|
+
}
|
|
153
|
+
function FieldLegend(props) {
|
|
154
|
+
return usePart(fieldSet, "legend", { id: props.id }, props, "legend");
|
|
155
|
+
}
|
|
156
|
+
function FieldGroup(props) {
|
|
157
|
+
return usePart(usePrimitive(fieldGroup, {}), "group", {}, props, "div");
|
|
158
|
+
}
|
|
159
|
+
export {
|
|
160
|
+
Field,
|
|
161
|
+
FieldControl,
|
|
162
|
+
FieldDescription,
|
|
163
|
+
FieldError,
|
|
164
|
+
FieldGroup,
|
|
165
|
+
FieldLabel,
|
|
166
|
+
FieldLegend,
|
|
167
|
+
FieldSet,
|
|
168
|
+
useFieldControl
|
|
169
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type FileInputItemProps, type FileInputItemRemoveState, type FileInputItemState, type FileInputOptions, type FileInputState, type FileInputTriggerProps } from "@ui-sdk/core/file-input";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { type PartProps } from "./use-primitive.js";
|
|
4
|
+
type DivProps<State> = Omit<PartProps<"div", State>, "defaultValue" | "onChange" | "onSelect" | "onDrop">;
|
|
5
|
+
type ButtonProps<State> = Omit<PartProps<"button", State>, "name" | "form" | "value" | "onSelect">;
|
|
6
|
+
/**
|
|
7
|
+
* The root: it holds the files, and renders the hidden file input that opens
|
|
8
|
+
* the picker and that a form submits.
|
|
9
|
+
* @stable
|
|
10
|
+
*/
|
|
11
|
+
declare function FileInput({ value, defaultValue, onValueChange, onReject, accept, multiple, directory, capture, maxFiles, maxSize, minSize, validate, name, form, required, disabled, announcement, controller, debug, children, ...props }: FileInputOptions & DivProps<FileInputState>): React.JSX.Element | null;
|
|
12
|
+
/**
|
|
13
|
+
* Opens the file picker. Inside a Field, the field's label names it with the
|
|
14
|
+
* button's own text. Outside the file input, it connects through `controller`.
|
|
15
|
+
* @stable
|
|
16
|
+
*/
|
|
17
|
+
declare function FileInputTrigger({ controller, render, ...props }: ButtonProps<FileInputState> & FileInputTriggerProps): React.JSX.Element;
|
|
18
|
+
/**
|
|
19
|
+
* Takes dropped and pasted files. Put the trigger inside it, which is how
|
|
20
|
+
* keyboard and screen reader users choose files.
|
|
21
|
+
* @stable
|
|
22
|
+
*/
|
|
23
|
+
declare const FileInputDropzone: import("./use-primitive.js").PartComponent<import("@ui-sdk/core/file-input").FileInputPrimitive, "dropzone", "div">;
|
|
24
|
+
/**
|
|
25
|
+
* The files, as a list. Its children render once for each file, so put a
|
|
26
|
+
* FileInputItem in it.
|
|
27
|
+
* @stable
|
|
28
|
+
*/
|
|
29
|
+
declare function FileInputList({ children, ...props }: Omit<DivProps<FileInputState>, "children"> & {
|
|
30
|
+
children?: React.ReactNode;
|
|
31
|
+
}): React.JSX.Element | null;
|
|
32
|
+
/**
|
|
33
|
+
* One file. Its render state has the file, for its name, size and preview.
|
|
34
|
+
* Arrow keys move between items, and Backspace or Delete removes the focused one.
|
|
35
|
+
* @stable
|
|
36
|
+
*/
|
|
37
|
+
declare function FileInputItem({ file: own, ...props }: DivProps<FileInputItemState> & Partial<FileInputItemProps>): React.JSX.Element;
|
|
38
|
+
/**
|
|
39
|
+
* Removes its item's file, or the `file` it's given. It's named "Remove <file
|
|
40
|
+
* name>" unless you name it.
|
|
41
|
+
* @stable
|
|
42
|
+
*/
|
|
43
|
+
declare function FileInputItemRemove({ file: own, ...props }: ButtonProps<FileInputItemRemoveState> & Partial<FileInputItemProps>): React.JSX.Element | null;
|
|
44
|
+
export { createFileInputController, formatFileSize, relativePath, } from "@ui-sdk/core/file-input";
|
|
45
|
+
export type { FileInputApi, FileInputChange, FileInputChangeOptions, FileInputController, FileInputDropzoneProps, FileInputDropzoneState, FileInputDropzoneTarget, FileInputItemProps, FileInputItemRemoveState, FileInputItemState, FileInputOptions, FileInputPasteTarget, FileInputPrimitive, FileInputState, FileInputTriggerProps, FileInputValueChangeDetails, FileInputValueChangeReason, FileLike, FileRejection, FileRejectionReason, FileRules, } from "@ui-sdk/core/file-input";
|
|
46
|
+
export { FileInput, FileInputDropzone, FileInputItem, FileInputItemRemove, FileInputList, FileInputTrigger, };
|