@arcfusionz/arc-primitive-ui 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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
- package/src/styles/theme.css +341 -341
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/components/Field/FieldContext.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Control wiring a connected `Field` provides to the form control inside it.
|
|
4
|
+
* The shape mirrors React Hook Form's `field` object from `useController`,
|
|
5
|
+
* kept structural so consumers of the context never import react-hook-form.
|
|
6
|
+
*/
|
|
7
|
+
interface FieldControlProps {
|
|
8
|
+
/** Field name registered with the form. */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Current field value from form state. */
|
|
11
|
+
value: unknown;
|
|
12
|
+
/** Whether react-hook-form marked the field disabled (form- or field-level). */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Change handler — accepts either a change event or a raw value. */
|
|
15
|
+
onChange: (eventOrValue: unknown) => void;
|
|
16
|
+
/** Blur handler — marks the field as touched. */
|
|
17
|
+
onBlur: () => void;
|
|
18
|
+
/** Ref callback used for focus management (e.g. focus-first-error on submit). */
|
|
19
|
+
ref: (instance: unknown) => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Control wiring published by the closest connected `Field`, or `null` when
|
|
23
|
+
* the component is not inside one. `Input` consumes this automatically; use
|
|
24
|
+
* it to connect controls that don't yet, e.g. a Select:
|
|
25
|
+
*
|
|
26
|
+
* function PlanSelect(props: SelectProps<string>) {
|
|
27
|
+
* const control = useFieldControl();
|
|
28
|
+
* return (
|
|
29
|
+
* <Select
|
|
30
|
+
* value={control?.value as string}
|
|
31
|
+
* onValueChange={control?.onChange}
|
|
32
|
+
* inputRef={control?.ref}
|
|
33
|
+
* {...props}
|
|
34
|
+
* />
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* React Hook Form's `onChange` accepts raw values, so Base UI `onValueChange`
|
|
39
|
+
* callbacks can be passed straight through.
|
|
40
|
+
*/
|
|
41
|
+
declare function useFieldControl(): FieldControlProps | null;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { FieldControlProps, useFieldControl };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
//#region src/components/Field/FieldContext.ts
|
|
3
|
+
const FieldContext = createContext(null);
|
|
4
|
+
/**
|
|
5
|
+
* Control wiring published by the closest connected `Field`, or `null` when
|
|
6
|
+
* the component is not inside one. `Input` consumes this automatically; use
|
|
7
|
+
* it to connect controls that don't yet, e.g. a Select:
|
|
8
|
+
*
|
|
9
|
+
* function PlanSelect(props: SelectProps<string>) {
|
|
10
|
+
* const control = useFieldControl();
|
|
11
|
+
* return (
|
|
12
|
+
* <Select
|
|
13
|
+
* value={control?.value as string}
|
|
14
|
+
* onValueChange={control?.onChange}
|
|
15
|
+
* inputRef={control?.ref}
|
|
16
|
+
* {...props}
|
|
17
|
+
* />
|
|
18
|
+
* );
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* React Hook Form's `onChange` accepts raw values, so Base UI `onValueChange`
|
|
22
|
+
* callbacks can be passed straight through.
|
|
23
|
+
*/
|
|
24
|
+
function useFieldControl() {
|
|
25
|
+
return useContext(FieldContext)?.control ?? null;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { FieldContext, useFieldControl };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Field, FieldDescription, FieldDescriptionProps, FieldError, FieldErrorProps, FieldItem, FieldItemProps, FieldLabel, FieldLabelProps, FieldLabelVariantsOptions, FieldOrientation, FieldProps, FieldValidity, FieldValidityProps, fieldLabelVariants } from "./Field.js";
|
|
2
|
+
import { FieldControlProps, useFieldControl } from "./FieldContext.js";
|
|
3
|
+
export { Field, type FieldControlProps, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorProps, FieldItem, type FieldItemProps, FieldLabel, type FieldLabelProps, type FieldLabelVariantsOptions, type FieldOrientation, type FieldProps, FieldValidity, type FieldValidityProps, fieldLabelVariants, useFieldControl };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { useFieldControl } from "./FieldContext.js";
|
|
2
|
+
import { Field, FieldDescription, FieldError, FieldItem, FieldLabel, FieldValidity, fieldLabelVariants } from "./Field.js";
|
|
3
|
+
export { Field, FieldDescription, FieldError, FieldItem, FieldLabel, FieldValidity, fieldLabelVariants, useFieldControl };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, HTMLAttributes } from "react";
|
|
2
|
+
import { Fieldset } from "@base-ui/react/fieldset";
|
|
3
|
+
//#region src/components/Fieldset/Fieldset.d.ts
|
|
4
|
+
interface FieldsetProps extends Omit<ComponentPropsWithoutRef<typeof Fieldset.Root>, "className"> {
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Groups related fields under one shared `FieldsetLegend` — required for
|
|
9
|
+
* radio and checkbox groups (WCAG 1.3.1), useful for form sections like
|
|
10
|
+
* "Billing details". Renders a native `<fieldset>`, so `disabled` disables
|
|
11
|
+
* every control inside it at once; with React Hook Form, note that disabling
|
|
12
|
+
* here is visual/interactive only — schema validation still runs, so also
|
|
13
|
+
* disable or exclude those fields in the form when they shouldn't block
|
|
14
|
+
* submission.
|
|
15
|
+
*/
|
|
16
|
+
declare const Fieldset$1: import("react").ForwardRefExoticComponent<FieldsetProps & import("react").RefAttributes<HTMLFieldSetElement>>;
|
|
17
|
+
type FieldsetLegendVariant = "section" | "label";
|
|
18
|
+
interface FieldsetLegendProps extends Omit<ComponentPropsWithoutRef<typeof Fieldset.Legend>, "className"> {
|
|
19
|
+
/**
|
|
20
|
+
* `section` (default) styles the legend as a form-section heading;
|
|
21
|
+
* `label` matches `FieldLabel` for radio/checkbox groups, so the group
|
|
22
|
+
* caption reads like the labels of the fields around it.
|
|
23
|
+
*/
|
|
24
|
+
variant?: FieldsetLegendVariant;
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The fieldset's caption, automatically associated with the group for
|
|
29
|
+
* assistive technology. Keep it short — some screen readers repeat the
|
|
30
|
+
* legend before every control in the group.
|
|
31
|
+
*/
|
|
32
|
+
declare const FieldsetLegend: import("react").ForwardRefExoticComponent<FieldsetLegendProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
33
|
+
interface FieldsetDescriptionProps extends Omit<HTMLAttributes<HTMLParagraphElement>, "className"> {
|
|
34
|
+
className?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Supporting copy for the whole group, placed right after the legend.
|
|
38
|
+
* Visible text content read in sequence — unlike `FieldDescription` it is
|
|
39
|
+
* not wired into any control's `aria-describedby`.
|
|
40
|
+
*/
|
|
41
|
+
declare const FieldsetDescription: import("react").ForwardRefExoticComponent<FieldsetDescriptionProps & import("react").RefAttributes<HTMLParagraphElement>>;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { Fieldset$1 as Fieldset, FieldsetDescription, FieldsetDescriptionProps, FieldsetLegend, FieldsetLegendProps, FieldsetLegendVariant, FieldsetProps };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { Fieldset } from "@base-ui/react/fieldset";
|
|
5
|
+
//#region src/components/Fieldset/Fieldset.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Groups related fields under one shared `FieldsetLegend` — required for
|
|
8
|
+
* radio and checkbox groups (WCAG 1.3.1), useful for form sections like
|
|
9
|
+
* "Billing details". Renders a native `<fieldset>`, so `disabled` disables
|
|
10
|
+
* every control inside it at once; with React Hook Form, note that disabling
|
|
11
|
+
* here is visual/interactive only — schema validation still runs, so also
|
|
12
|
+
* disable or exclude those fields in the form when they shouldn't block
|
|
13
|
+
* submission.
|
|
14
|
+
*/
|
|
15
|
+
const Fieldset$1 = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx(Fieldset.Root, {
|
|
16
|
+
ref,
|
|
17
|
+
className: cn("flex min-w-0 flex-col gap-4", className),
|
|
18
|
+
...rest
|
|
19
|
+
}));
|
|
20
|
+
Fieldset$1.displayName = "Fieldset";
|
|
21
|
+
const legendVariantClasses = {
|
|
22
|
+
section: "font-heading text-lg font-semibold text-foreground",
|
|
23
|
+
label: "font-sans text-sm font-medium text-foreground"
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The fieldset's caption, automatically associated with the group for
|
|
27
|
+
* assistive technology. Keep it short — some screen readers repeat the
|
|
28
|
+
* legend before every control in the group.
|
|
29
|
+
*/
|
|
30
|
+
const FieldsetLegend = forwardRef(({ variant = "section", className, ...rest }, ref) => /* @__PURE__ */ jsx(Fieldset.Legend, {
|
|
31
|
+
ref,
|
|
32
|
+
className: cn(legendVariantClasses[variant], "data-disabled:opacity-50", className),
|
|
33
|
+
...rest
|
|
34
|
+
}));
|
|
35
|
+
FieldsetLegend.displayName = "FieldsetLegend";
|
|
36
|
+
/**
|
|
37
|
+
* Supporting copy for the whole group, placed right after the legend.
|
|
38
|
+
* Visible text content read in sequence — unlike `FieldDescription` it is
|
|
39
|
+
* not wired into any control's `aria-describedby`.
|
|
40
|
+
*/
|
|
41
|
+
const FieldsetDescription = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx("p", {
|
|
42
|
+
ref,
|
|
43
|
+
className: cn("font-sans text-sm text-muted-foreground in-data-disabled:opacity-50", className),
|
|
44
|
+
...rest
|
|
45
|
+
}));
|
|
46
|
+
FieldsetDescription.displayName = "FieldsetDescription";
|
|
47
|
+
//#endregion
|
|
48
|
+
export { Fieldset$1 as Fieldset, FieldsetDescription, FieldsetLegend };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Fieldset, FieldsetDescription, FieldsetDescriptionProps, FieldsetLegend, FieldsetLegendProps, FieldsetLegendVariant, FieldsetProps } from "./Fieldset.js";
|
|
2
|
+
export { Fieldset, FieldsetDescription, type FieldsetDescriptionProps, FieldsetLegend, type FieldsetLegendProps, type FieldsetLegendVariant, type FieldsetProps };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactNode, Ref } from "react";
|
|
2
|
+
import { FieldValues, SubmitErrorHandler, SubmitHandler, UseFormReturn } from "react-hook-form";
|
|
3
|
+
import { Form } from "@base-ui/react/form";
|
|
4
|
+
//#region src/components/Form/Form.d.ts
|
|
5
|
+
type BaseFormProps = ComponentPropsWithoutRef<typeof Form>;
|
|
6
|
+
interface FormProps<TFieldValues extends FieldValues = FieldValues, TTransformedValues = TFieldValues> extends Omit<BaseFormProps, "className"> {
|
|
7
|
+
/**
|
|
8
|
+
* The `useForm` return value. Providing it switches the form to React Hook
|
|
9
|
+
* Form mode: children get the form context (so `<Field name="…">` connects
|
|
10
|
+
* with no extra props), submission runs through `handleSubmit`, and native
|
|
11
|
+
* constraint validation is turned off (`noValidate`) so the schema is the
|
|
12
|
+
* single source of truth. Omit it for a native Base UI form (constraint
|
|
13
|
+
* validation, the `errors` server-error map, `onFormSubmit`).
|
|
14
|
+
*/
|
|
15
|
+
form?: UseFormReturn<TFieldValues, any, TTransformedValues>;
|
|
16
|
+
/**
|
|
17
|
+
* Called with the parsed values when submission passes validation — with a
|
|
18
|
+
* Zod resolver this is the schema's output type. React Hook Form focuses
|
|
19
|
+
* the first invalid control when validation fails (`shouldFocusError`).
|
|
20
|
+
*/
|
|
21
|
+
onValidSubmit?: SubmitHandler<TTransformedValues>;
|
|
22
|
+
/** Called with the field errors when submission fails validation. */
|
|
23
|
+
onInvalidSubmit?: SubmitErrorHandler<TFieldValues>;
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
interface FormComponent {
|
|
27
|
+
<TFieldValues extends FieldValues = FieldValues, TTransformedValues = TFieldValues>(props: FormProps<TFieldValues, TTransformedValues> & {
|
|
28
|
+
ref?: Ref<HTMLFormElement>;
|
|
29
|
+
}): ReactNode;
|
|
30
|
+
displayName?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The form element for both worlds. With `form={useForm(…)}` it becomes the
|
|
34
|
+
* React Hook Form shell — provider, `handleSubmit`, and `noValidate` in one:
|
|
35
|
+
*
|
|
36
|
+
* const schema = z.object({ email: z.email("Enter a valid email") });
|
|
37
|
+
* const form = useForm({ resolver: zodResolver(schema), mode: "onTouched" });
|
|
38
|
+
*
|
|
39
|
+
* <Form form={form} onValidSubmit={(data) => save(data)}>
|
|
40
|
+
* <Field name="email">
|
|
41
|
+
* <FieldLabel>Email</FieldLabel>
|
|
42
|
+
* <Input type="email" autoComplete="email" />
|
|
43
|
+
* <FieldError />
|
|
44
|
+
* </Field>
|
|
45
|
+
* <Button type="submit">Save</Button>
|
|
46
|
+
* </Form>
|
|
47
|
+
*
|
|
48
|
+
* Without `form` it is Base UI's native form: constraint validation drives
|
|
49
|
+
* `FieldError` via `match`, `errors` maps server errors onto fields by name,
|
|
50
|
+
* and `onFormSubmit` receives values as a plain object.
|
|
51
|
+
*/
|
|
52
|
+
declare const Form$1: FormComponent;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { Form$1 as Form, FormProps };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { FormProvider } from "react-hook-form";
|
|
5
|
+
import { Form } from "@base-ui/react/form";
|
|
6
|
+
//#region src/components/Form/Form.tsx
|
|
7
|
+
const formClasses = "flex w-full min-w-0 flex-col gap-6";
|
|
8
|
+
function noopSubmit() {}
|
|
9
|
+
const FormImpl = forwardRef(({ form, onValidSubmit, onInvalidSubmit, onSubmit, noValidate, className, ...rest }, ref) => {
|
|
10
|
+
if (form == null) return /* @__PURE__ */ jsx(Form, {
|
|
11
|
+
ref,
|
|
12
|
+
onSubmit,
|
|
13
|
+
noValidate,
|
|
14
|
+
className: cn(formClasses, className),
|
|
15
|
+
...rest
|
|
16
|
+
});
|
|
17
|
+
const handleSubmit = (event) => {
|
|
18
|
+
onSubmit?.(event);
|
|
19
|
+
if (event.defaultPrevented) return;
|
|
20
|
+
form.handleSubmit(onValidSubmit ?? noopSubmit, onInvalidSubmit)(event);
|
|
21
|
+
};
|
|
22
|
+
return /* @__PURE__ */ jsx(FormProvider, {
|
|
23
|
+
...form,
|
|
24
|
+
children: /* @__PURE__ */ jsx(Form, {
|
|
25
|
+
ref,
|
|
26
|
+
onSubmit: handleSubmit,
|
|
27
|
+
noValidate: noValidate ?? true,
|
|
28
|
+
className: cn(formClasses, className),
|
|
29
|
+
...rest
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
FormImpl.displayName = "Form";
|
|
34
|
+
/**
|
|
35
|
+
* The form element for both worlds. With `form={useForm(…)}` it becomes the
|
|
36
|
+
* React Hook Form shell — provider, `handleSubmit`, and `noValidate` in one:
|
|
37
|
+
*
|
|
38
|
+
* const schema = z.object({ email: z.email("Enter a valid email") });
|
|
39
|
+
* const form = useForm({ resolver: zodResolver(schema), mode: "onTouched" });
|
|
40
|
+
*
|
|
41
|
+
* <Form form={form} onValidSubmit={(data) => save(data)}>
|
|
42
|
+
* <Field name="email">
|
|
43
|
+
* <FieldLabel>Email</FieldLabel>
|
|
44
|
+
* <Input type="email" autoComplete="email" />
|
|
45
|
+
* <FieldError />
|
|
46
|
+
* </Field>
|
|
47
|
+
* <Button type="submit">Save</Button>
|
|
48
|
+
* </Form>
|
|
49
|
+
*
|
|
50
|
+
* Without `form` it is Base UI's native form: constraint validation drives
|
|
51
|
+
* `FieldError` via `match`, `errors` maps server errors onto fields by name,
|
|
52
|
+
* and `onFormSubmit` receives values as a plain object.
|
|
53
|
+
*/
|
|
54
|
+
const Form$1 = FormImpl;
|
|
55
|
+
Form$1.displayName = "Form";
|
|
56
|
+
//#endregion
|
|
57
|
+
export { Form$1 as Form };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, HTMLAttributes } from "react";
|
|
2
|
+
import { Input } from "@base-ui/react/input";
|
|
3
|
+
//#region src/components/Input/Input.d.ts
|
|
4
|
+
type InputSize = "sm" | "md" | "lg";
|
|
5
|
+
interface InputVariantsOptions {
|
|
6
|
+
size?: InputSize;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Class list for an element styled as a standalone Input — for input-shaped
|
|
11
|
+
* elements that aren't this component (a `<textarea>`, a fake search box that
|
|
12
|
+
* opens a command palette) so every text control shares one look. Inside an
|
|
13
|
+
* `InputGroup` the group owns the frame; these classes are for standalone use.
|
|
14
|
+
*/
|
|
15
|
+
declare function inputVariants({ size, className }?: InputVariantsOptions): string;
|
|
16
|
+
type BaseInputProps = ComponentPropsWithoutRef<typeof Input>;
|
|
17
|
+
interface InputProps extends Omit<BaseInputProps, "className" | "size"> {
|
|
18
|
+
/** Control height. `sm` (32px) meets the WCAG 2.5.8 AA target-size floor; prefer `md`/`lg` for touch-first surfaces. Inside an `InputGroup` the group's `size` wins. */
|
|
19
|
+
size?: InputSize;
|
|
20
|
+
/** The native `size` attribute (visible width in characters) — renamed because `size` selects the control height. */
|
|
21
|
+
htmlSize?: number;
|
|
22
|
+
/** Marks the input invalid (`aria-invalid` + destructive styling) when validation is wired manually. Composed `Field`s set this state for you via `data-invalid`. */
|
|
23
|
+
invalid?: boolean;
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Native text input built on Base UI's Input. Full width by default — size
|
|
28
|
+
* it via the container. Inside a `Field` it inherits labelling, description
|
|
29
|
+
* and error wiring plus state data-attributes automatically; inside a
|
|
30
|
+
* *connected* Field (React Hook Form) the value, change/blur handlers, and
|
|
31
|
+
* focus ref are wired for you too — passing `value`, `defaultValue`,
|
|
32
|
+
* `onChange`, or `name` yourself takes back manual control (don't also
|
|
33
|
+
* `register` the same name: the Field already registered it). Standalone
|
|
34
|
+
* max-performance registration `{...form.register("name")}` works as usual.
|
|
35
|
+
* Fields that collect data about the user must pass the matching
|
|
36
|
+
* `autocomplete` token (WCAG 1.3.5).
|
|
37
|
+
*/
|
|
38
|
+
declare const Input$1: import("react").ForwardRefExoticComponent<InputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
39
|
+
interface InputGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, "className"> {
|
|
40
|
+
/** Frame height, mirroring Input sizes. The Input inside inherits it. */
|
|
41
|
+
size?: InputSize;
|
|
42
|
+
className?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Frame that seats decorations next to an `Input` — icons, text affixes like
|
|
46
|
+
* `$` or `.com`, or interactive addons — inside one shared border with a
|
|
47
|
+
* single focus ring. Compose `InputGroupAddon`(s) and one `Input` in visual
|
|
48
|
+
* order; the input goes bare and the group takes over its frame, including
|
|
49
|
+
* invalid/disabled/read-only states. Works inside `Field` unchanged.
|
|
50
|
+
*/
|
|
51
|
+
declare const InputGroup: import("react").ForwardRefExoticComponent<InputGroupProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
52
|
+
interface InputGroupAddonProps extends Omit<HTMLAttributes<HTMLDivElement>, "className"> {
|
|
53
|
+
className?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A decoration slot inside `InputGroup` — place it before or after the
|
|
57
|
+
* `Input` in the children. Addon content sits outside the input's accessible
|
|
58
|
+
* name: mark purely decorative content (icons, unit text repeated in the
|
|
59
|
+
* label) with `aria-hidden`, and never hide interactive addons — a clear or
|
|
60
|
+
* show-password `Button` must stay in the accessibility tree.
|
|
61
|
+
*/
|
|
62
|
+
declare const InputGroupAddon: import("react").ForwardRefExoticComponent<InputGroupAddonProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
63
|
+
//#endregion
|
|
64
|
+
export { Input$1 as Input, InputGroup, InputGroupAddon, InputGroupAddonProps, InputGroupProps, InputProps, InputSize, InputVariantsOptions, inputVariants };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { FieldContext } from "../Field/FieldContext.js";
|
|
3
|
+
import { createContext, forwardRef, useContext, useMemo } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { Input } from "@base-ui/react/input";
|
|
6
|
+
//#region src/components/Input/Input.tsx
|
|
7
|
+
const inputBaseClasses = "block w-full min-w-0 appearance-none rounded-md border border-border bg-background font-sans text-foreground placeholder:text-muted-foreground transition-colors duration-150 hover:border-slate-300 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring data-invalid:border-destructive data-invalid:hover:border-destructive data-invalid:focus-visible:outline-destructive aria-invalid:border-destructive aria-invalid:hover:border-destructive aria-invalid:focus-visible:outline-destructive [&[readonly]]:bg-surface disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 file:me-3 file:h-full file:cursor-pointer file:border-0 file:bg-transparent file:font-sans file:text-sm file:font-medium file:text-foreground";
|
|
8
|
+
const inputSizeClasses = {
|
|
9
|
+
sm: "h-8 px-2.5 text-sm any-pointer-coarse:text-base",
|
|
10
|
+
md: "h-10 px-3 text-sm any-pointer-coarse:text-base",
|
|
11
|
+
lg: "h-12 px-3.5 text-base"
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Class list for an element styled as a standalone Input — for input-shaped
|
|
15
|
+
* elements that aren't this component (a `<textarea>`, a fake search box that
|
|
16
|
+
* opens a command palette) so every text control shares one look. Inside an
|
|
17
|
+
* `InputGroup` the group owns the frame; these classes are for standalone use.
|
|
18
|
+
*/
|
|
19
|
+
function inputVariants({ size = "md", className } = {}) {
|
|
20
|
+
return cn(inputBaseClasses, inputSizeClasses[size], className);
|
|
21
|
+
}
|
|
22
|
+
const bareInputClasses = "h-full w-full min-w-0 flex-1 appearance-none rounded-none border-0 bg-transparent p-0 font-sans text-inherit placeholder:text-muted-foreground outline-none disabled:pointer-events-none file:me-3 file:h-full file:cursor-pointer file:border-0 file:bg-transparent file:font-sans file:text-sm file:font-medium file:text-foreground";
|
|
23
|
+
function composeRefs(...refs) {
|
|
24
|
+
return (node) => {
|
|
25
|
+
for (const ref of refs) if (typeof ref === "function") ref(node);
|
|
26
|
+
else if (ref != null) ref.current = node;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Native text input built on Base UI's Input. Full width by default — size
|
|
31
|
+
* it via the container. Inside a `Field` it inherits labelling, description
|
|
32
|
+
* and error wiring plus state data-attributes automatically; inside a
|
|
33
|
+
* *connected* Field (React Hook Form) the value, change/blur handlers, and
|
|
34
|
+
* focus ref are wired for you too — passing `value`, `defaultValue`,
|
|
35
|
+
* `onChange`, or `name` yourself takes back manual control (don't also
|
|
36
|
+
* `register` the same name: the Field already registered it). Standalone
|
|
37
|
+
* max-performance registration `{...form.register("name")}` works as usual.
|
|
38
|
+
* Fields that collect data about the user must pass the matching
|
|
39
|
+
* `autocomplete` token (WCAG 1.3.5).
|
|
40
|
+
*/
|
|
41
|
+
const Input$1 = forwardRef(({ size = "md", htmlSize, invalid, type, name, value, defaultValue, onChange, onBlur, disabled, required, className, ...rest }, ref) => {
|
|
42
|
+
const fieldContext = useContext(FieldContext);
|
|
43
|
+
const groupSize = useContext(InputGroupContext);
|
|
44
|
+
const adapter = fieldContext?.control ?? null;
|
|
45
|
+
const wired = adapter != null && !(value !== void 0 || defaultValue !== void 0 || onChange !== void 0 || name !== void 0);
|
|
46
|
+
const isFile = type === "file";
|
|
47
|
+
const requiredState = required ?? (fieldContext?.required ? true : void 0);
|
|
48
|
+
return /* @__PURE__ */ jsx(Input, {
|
|
49
|
+
ref: useMemo(() => wired ? composeRefs(ref, adapter.ref) : ref, [
|
|
50
|
+
wired,
|
|
51
|
+
ref,
|
|
52
|
+
adapter?.ref
|
|
53
|
+
]),
|
|
54
|
+
type,
|
|
55
|
+
size: htmlSize,
|
|
56
|
+
name: wired ? adapter.name : name,
|
|
57
|
+
disabled: disabled ?? (wired ? adapter.disabled : void 0),
|
|
58
|
+
value: wired && !isFile ? adapter.value ?? "" : value,
|
|
59
|
+
defaultValue,
|
|
60
|
+
onChange: wired ? (event) => adapter.onChange(event) : onChange,
|
|
61
|
+
onBlur: (event) => {
|
|
62
|
+
onBlur?.(event);
|
|
63
|
+
if (wired) adapter.onBlur();
|
|
64
|
+
},
|
|
65
|
+
required: wired ? void 0 : requiredState,
|
|
66
|
+
"aria-required": wired && requiredState ? true : void 0,
|
|
67
|
+
"aria-invalid": invalid || void 0,
|
|
68
|
+
className: cn(groupSize != null ? bareInputClasses : inputVariants({ size }), className),
|
|
69
|
+
...rest
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
Input$1.displayName = "Input";
|
|
73
|
+
const InputGroupContext = createContext(null);
|
|
74
|
+
const groupBaseClasses = "flex w-full min-w-0 items-center rounded-md border border-border bg-background font-sans text-foreground transition-colors duration-150 hover:border-slate-300 focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring has-data-invalid:border-destructive has-data-invalid:hover:border-destructive has-data-invalid:focus-within:outline-destructive has-aria-invalid:border-destructive has-aria-invalid:hover:border-destructive has-aria-invalid:focus-within:outline-destructive has-[input[readonly]]:bg-surface has-[input:disabled]:pointer-events-none has-[input:disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4";
|
|
75
|
+
const groupSizeClasses = {
|
|
76
|
+
sm: "h-8 gap-1.5 px-2.5 text-sm any-pointer-coarse:text-base",
|
|
77
|
+
md: "h-10 gap-2 px-3 text-sm any-pointer-coarse:text-base",
|
|
78
|
+
lg: "h-12 gap-2 px-3.5 text-base [&_svg:not([class*='size-'])]:size-5"
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Frame that seats decorations next to an `Input` — icons, text affixes like
|
|
82
|
+
* `$` or `.com`, or interactive addons — inside one shared border with a
|
|
83
|
+
* single focus ring. Compose `InputGroupAddon`(s) and one `Input` in visual
|
|
84
|
+
* order; the input goes bare and the group takes over its frame, including
|
|
85
|
+
* invalid/disabled/read-only states. Works inside `Field` unchanged.
|
|
86
|
+
*/
|
|
87
|
+
const InputGroup = forwardRef(({ size = "md", className, ...rest }, ref) => /* @__PURE__ */ jsx(InputGroupContext.Provider, {
|
|
88
|
+
value: size,
|
|
89
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
90
|
+
ref,
|
|
91
|
+
className: cn(groupBaseClasses, groupSizeClasses[size], className),
|
|
92
|
+
...rest
|
|
93
|
+
})
|
|
94
|
+
}));
|
|
95
|
+
InputGroup.displayName = "InputGroup";
|
|
96
|
+
const addonClasses = "flex shrink-0 select-none items-center gap-1.5 text-muted-foreground";
|
|
97
|
+
/**
|
|
98
|
+
* A decoration slot inside `InputGroup` — place it before or after the
|
|
99
|
+
* `Input` in the children. Addon content sits outside the input's accessible
|
|
100
|
+
* name: mark purely decorative content (icons, unit text repeated in the
|
|
101
|
+
* label) with `aria-hidden`, and never hide interactive addons — a clear or
|
|
102
|
+
* show-password `Button` must stay in the accessibility tree.
|
|
103
|
+
*/
|
|
104
|
+
const InputGroupAddon = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx("div", {
|
|
105
|
+
ref,
|
|
106
|
+
className: cn(addonClasses, className),
|
|
107
|
+
...rest
|
|
108
|
+
}));
|
|
109
|
+
InputGroupAddon.displayName = "InputGroupAddon";
|
|
110
|
+
//#endregion
|
|
111
|
+
export { Input$1 as Input, InputGroup, InputGroupAddon, inputVariants };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Input, InputGroup, InputGroupAddon, InputGroupAddonProps, InputGroupProps, InputProps, InputSize, InputVariantsOptions, inputVariants } from "./Input.js";
|
|
2
|
+
export { Input, InputGroup, InputGroupAddon, type InputGroupAddonProps, type InputGroupProps, type InputProps, type InputSize, type InputVariantsOptions, inputVariants };
|