atlas-react-kit 0.12.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS.md +201 -100
- package/DESIGN_RULES.md +44 -1
- package/README.md +10 -9
- package/dist/accordion.d.ts +1 -0
- package/dist/alert.d.ts +1 -1
- package/dist/avatar.d.ts +1 -0
- package/dist/badge.d.ts +4 -5
- package/dist/breadcrumb.d.ts +2 -3
- package/dist/button.d.ts +4 -5
- package/dist/calendar.d.ts +2 -0
- package/dist/card.d.ts +3 -0
- package/dist/chart.d.ts +152 -0
- package/dist/chart.js +177 -0
- package/dist/color-legend.d.ts +8 -0
- package/dist/combobox.d.ts +13 -4
- package/dist/combobox.js +1 -8
- package/dist/date-picker.d.ts +16 -6
- package/dist/date-picker.js +13 -20
- package/dist/date-time-picker.d.ts +5 -2
- package/dist/date-time-picker.js +6 -5
- package/dist/dialog.d.ts +1 -0
- package/dist/dialog.js +4 -2
- package/dist/dropdown-menu.d.ts +9 -8
- package/dist/empty-panel.d.ts +8 -2
- package/dist/empty-panel.js +2 -2
- package/dist/error-boundary.d.ts +7 -2
- package/dist/field.d.ts +4 -1
- package/dist/field.js +1 -1
- package/dist/form/checkbox-field.d.ts +45 -0
- package/dist/form/checkbox-field.js +39 -0
- package/dist/form/combobox-field.d.ts +13 -0
- package/dist/form/combobox-field.js +14 -0
- package/dist/form/control-field.d.ts +30 -0
- package/dist/form/control-field.js +22 -0
- package/dist/form/date-picker-field.d.ts +7 -21
- package/dist/form/date-picker-field.js +4 -4
- package/dist/form/date-time-picker-field.d.ts +7 -22
- package/dist/form/date-time-picker-field.js +3 -3
- package/dist/form/feedback-field.d.ts +2 -0
- package/dist/form/field-error.d.ts +49 -0
- package/dist/form/field-shell.d.ts +47 -8
- package/dist/form/field-shell.js +24 -7
- package/dist/form/markdown-field.d.ts +4 -16
- package/dist/form/markdown-field.js +2 -2
- package/dist/form/select-field.d.ts +7 -7
- package/dist/form/select-field.js +2 -2
- package/dist/form/text-field.d.ts +29 -12
- package/dist/form/text-field.js +10 -6
- package/dist/form/toggle-group-field.d.ts +30 -0
- package/dist/form/toggle-group-field.js +19 -0
- package/dist/info-tip.d.ts +10 -1
- package/dist/internal/as-child.d.ts +8 -0
- package/dist/internal/as-child.js +1 -0
- package/dist/internal/date-like.d.ts +23 -0
- package/dist/internal/form-control.d.ts +3 -2
- package/dist/internal/form-control.js +3 -2
- package/dist/internal/kanban-layout.d.ts +55 -0
- package/dist/internal/kanban-layout.js +80 -0
- package/dist/internal/kanban-plugins.d.ts +17 -0
- package/dist/internal/kanban-plugins.js +17 -0
- package/dist/internal/use-media-query.d.ts +4 -2
- package/dist/internal/use-media-query.js +11 -15
- package/dist/kanban.d.ts +84 -0
- package/dist/kanban.js +197 -0
- package/dist/markdown.d.ts +2 -0
- package/dist/meter.d.ts +7 -0
- package/dist/nav-link.d.ts +23 -0
- package/dist/nav-link.js +31 -0
- package/dist/next/nav-link.d.ts +11 -0
- package/dist/next/nav-link.js +14 -0
- package/dist/next/period-stepper.d.ts +11 -0
- package/dist/next/period-stepper.js +16 -0
- package/dist/page-header.d.ts +19 -0
- package/dist/page-header.js +11 -0
- package/dist/pagination.d.ts +2 -0
- package/dist/period-stepper.d.ts +32 -0
- package/dist/period-stepper.js +27 -0
- package/dist/picker-shell.d.ts +43 -6
- package/dist/picker-shell.js +2 -2
- package/dist/progress.d.ts +1 -0
- package/dist/search-picker.d.ts +12 -0
- package/dist/select.d.ts +1 -0
- package/dist/skip-link.d.ts +7 -0
- package/dist/skip-link.js +10 -0
- package/dist/slider.d.ts +11 -0
- package/dist/sortable-table-head.d.ts +2 -0
- package/dist/stat-tile.d.ts +5 -0
- package/dist/table-body-skeleton.d.ts +2 -0
- package/dist/table.d.ts +1 -0
- package/dist/tabs.d.ts +9 -5
- package/dist/tabs.js +1 -1
- package/dist/toast.d.ts +7 -1
- package/dist/toggle-group.d.ts +9 -2
- package/dist/toggle-group.js +2 -1
- package/dist/toggle.d.ts +1 -1
- package/package.json +85 -11
- package/skills/atlas-react-kit/SKILL.md +2 -0
- package/theme.css +11 -0
|
@@ -1,29 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { type PickerFieldBaseProps } from "./field-shell.js";
|
|
2
|
+
type Props = PickerFieldBaseProps & {
|
|
3
|
+
/** The picked instant, or `null` when empty. */
|
|
4
4
|
value: Date | null;
|
|
5
|
+
/** Called with the picked instant, or `null` on Clear. */
|
|
5
6
|
onValueChange: (date: Date | null) => void;
|
|
6
|
-
|
|
7
|
-
meta?: FieldMetaState;
|
|
7
|
+
/** Trigger text while nothing is picked. Default "Pick a date and time". */
|
|
8
8
|
placeholder?: string;
|
|
9
|
-
|
|
10
|
-
/** Marks the label and adds "Required" to the trigger's description. */
|
|
11
|
-
required?: boolean;
|
|
12
|
-
/** Earliest day that can be picked; earlier days are disabled. */
|
|
13
|
-
minDate?: DateLike;
|
|
14
|
-
/** Latest day that can be picked; later days are disabled. */
|
|
15
|
-
maxDate?: DateLike;
|
|
16
|
-
/** Minute increment forwarded to the picker. */
|
|
9
|
+
/** Minute increment for the time selects (1, 5, 15, 30, or 60). Default 15. */
|
|
17
10
|
timeStep?: number;
|
|
18
|
-
/** Forwarded to the date-time picker trigger. */
|
|
19
|
-
className?: string;
|
|
20
|
-
/** Classes for the field wrapper (label, trigger, and error). */
|
|
21
|
-
fieldClassName?: string;
|
|
22
|
-
/** Forwarded to the date-time picker popover. */
|
|
23
|
-
contentClassName?: string;
|
|
24
|
-
/** Day Picker options forwarded to the calendar (disabled days, etc.). */
|
|
25
|
-
calendarProps?: DatePickerCalendarProps;
|
|
26
11
|
};
|
|
27
12
|
/** Date-time picker with built-in field error text and invalid styling. */
|
|
28
|
-
export declare function FormDateTimePickerField({ onValueChange, label, meta, required, fieldClassName, ...picker }: Props): import("react").JSX.Element;
|
|
13
|
+
export declare function FormDateTimePickerField({ onValueChange, label, meta, submitted, showError, required, fieldClassName, ...picker }: Props): import("react").JSX.Element;
|
|
29
14
|
export {};
|
|
@@ -4,8 +4,8 @@ import { useId } from "react";
|
|
|
4
4
|
import { DateTimePickerButton } from "../date-time-picker.js";
|
|
5
5
|
import { FormFieldShell, metaErrorText, pickerFieldAria, } from "./field-shell.js";
|
|
6
6
|
/** Date-time picker with built-in field error text and invalid styling. */
|
|
7
|
-
export function FormDateTimePickerField({ onValueChange, label, meta, required, fieldClassName, ...picker }) {
|
|
8
|
-
const errorText = metaErrorText(meta);
|
|
7
|
+
export function FormDateTimePickerField({ onValueChange, label, meta, submitted, showError, required, fieldClassName, ...picker }) {
|
|
8
|
+
const errorText = metaErrorText(meta, { submitted, showError });
|
|
9
9
|
const id = useId();
|
|
10
|
-
return (_jsx(FormFieldShell, { id: id, label: label, errorText: errorText, required: required, className: fieldClassName, children: _jsx(DateTimePickerButton, { ...picker, id: id,
|
|
10
|
+
return (_jsx(FormFieldShell, { id: id, label: label, errorText: errorText, required: required, className: fieldClassName, children: _jsx(DateTimePickerButton, { ...picker, id: id, onValueChange: onValueChange, ...pickerFieldAria(id, errorText, required) }) }));
|
|
11
11
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Form-level submit or mutation error (not tied to a single field). */
|
|
2
2
|
export declare function FormFeedbackField({ message, className, }: {
|
|
3
|
+
/** Error text to show; `null` or empty renders nothing. */
|
|
3
4
|
message: string | null;
|
|
5
|
+
/** Classes for the message paragraph. */
|
|
4
6
|
className?: string;
|
|
5
7
|
}): import("react").JSX.Element | null;
|
|
@@ -1,15 +1,64 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
export type FieldErrorMessage = string | {
|
|
2
3
|
message?: string;
|
|
3
4
|
} | undefined;
|
|
4
5
|
export type FieldMetaState = {
|
|
6
|
+
/** Validation errors for the field; the `form/*` fields show the first. */
|
|
5
7
|
errors: FieldErrorMessage[];
|
|
8
|
+
/**
|
|
9
|
+
* Whether the person has changed or left the field (TanStack Form's
|
|
10
|
+
* `meta.isTouched`). When it is `false`, the `form/*` fields hold back
|
|
11
|
+
* the error until the field is touched or their `submitted` prop is set.
|
|
12
|
+
* Leave it out to show errors as soon as they exist.
|
|
13
|
+
*/
|
|
14
|
+
isTouched?: boolean;
|
|
15
|
+
};
|
|
16
|
+
/** When a field shows its error: the `form/*` fields' shared timing props. */
|
|
17
|
+
export type ErrorTimingProps = {
|
|
18
|
+
/**
|
|
19
|
+
* Set once the form has been submitted (TanStack Form:
|
|
20
|
+
* `form.state.submissionAttempts > 0`), so an untouched field shows its
|
|
21
|
+
* error too. Only matters when `meta.isTouched` is passed.
|
|
22
|
+
*/
|
|
23
|
+
submitted?: boolean;
|
|
24
|
+
/** When false, never shows error text or invalid styling. Default true. */
|
|
25
|
+
showError?: boolean;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Props every labelled `form/*` field shares: the error timing, the label,
|
|
29
|
+
* and the classes for the field wrapper.
|
|
30
|
+
*/
|
|
31
|
+
export type FormFieldBaseProps = ErrorTimingProps & {
|
|
32
|
+
/** Visible label text (the legend, for a checkbox group). */
|
|
33
|
+
label: string;
|
|
34
|
+
/**
|
|
35
|
+
* Classes for the field wrapper (`data-slot="form-field"`: label, hint,
|
|
36
|
+
* control, and error), e.g. a width.
|
|
37
|
+
*/
|
|
38
|
+
fieldClassName?: string;
|
|
39
|
+
};
|
|
40
|
+
/** Error meta for the `form/*` fields that are not bound to a `field` API. */
|
|
41
|
+
export type FormFieldMetaProps = {
|
|
42
|
+
/**
|
|
43
|
+
* The field's meta (TanStack Form's `field.state.meta`); its first error
|
|
44
|
+
* shows under the control. Leave it out for no error text.
|
|
45
|
+
*/
|
|
46
|
+
meta?: FieldMetaState;
|
|
47
|
+
};
|
|
48
|
+
/** The optional hint the `form/*` fields render under the label. */
|
|
49
|
+
export type FormFieldDescriptionProps = {
|
|
50
|
+
/** Hint between the label and the control, read with the control. */
|
|
51
|
+
description?: ReactNode;
|
|
6
52
|
};
|
|
7
53
|
/** First TanStack Form error message for a field, if any. */
|
|
8
54
|
export declare function getFieldErrorMessage(message: FieldErrorMessage): string | undefined;
|
|
9
55
|
export declare function FieldError({ id, message, text, className, }: {
|
|
10
56
|
/** Point the control's `aria-describedby` here so the error is read with it. */
|
|
11
57
|
id?: string;
|
|
58
|
+
/** Error to show, as TanStack Form reports it; ignored when `text` is set. */
|
|
12
59
|
message?: FieldErrorMessage;
|
|
60
|
+
/** Error text to show as is; takes precedence over `message`. */
|
|
13
61
|
text?: string;
|
|
62
|
+
/** Classes for the error paragraph. */
|
|
14
63
|
className?: string;
|
|
15
64
|
}): import("react").JSX.Element | null;
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
import {
|
|
1
|
+
import type { ComponentProps, ReactNode } from "react";
|
|
2
|
+
import type { DateLike, DatePickerCalendarProps } from "../date-picker.js";
|
|
3
|
+
import { type ErrorTimingProps, type FieldMetaState, type FormFieldBaseProps, type FormFieldMetaProps } from "./field-error.js";
|
|
3
4
|
/**
|
|
4
5
|
* Not a public entry. The layout and error wiring every `form/*` field
|
|
5
|
-
* shares, so a field only says which control it renders.
|
|
6
|
+
* shares, so a field only says which control it renders. Custom controls
|
|
7
|
+
* get the same shell through the public `FormControlField`.
|
|
6
8
|
*/
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
+
/**
|
|
10
|
+
* First error in `meta`, or `undefined` when there is no meta, no error,
|
|
11
|
+
* `showError` is false, or the field is untouched (`isTouched: false`)
|
|
12
|
+
* and the form has not been submitted.
|
|
13
|
+
*/
|
|
14
|
+
export declare function metaErrorText(meta: FieldMetaState | undefined, { submitted, showError }?: ErrorTimingProps): string | undefined;
|
|
9
15
|
/** `aria-invalid` for the control: `true` while there is error text. */
|
|
10
16
|
export declare function invalidWhen(errorText: string | undefined): true | undefined;
|
|
11
17
|
/** Id of the label `FormFieldShell` renders for control `id`. */
|
|
12
18
|
export declare function labelIdFor(id: string): string;
|
|
19
|
+
/** Id of the hint `FormFieldShell` renders for control `id`. */
|
|
20
|
+
export declare function descriptionIdFor(id: string): string;
|
|
13
21
|
/** Id of the error text `FormFieldShell` renders for control `id`. */
|
|
14
22
|
export declare function errorIdFor(id: string): string;
|
|
15
23
|
/**
|
|
@@ -22,6 +30,26 @@ export declare function requiredIdFor(id: string): string;
|
|
|
22
30
|
* text while there is one, or `undefined` when there is nothing to read.
|
|
23
31
|
*/
|
|
24
32
|
export declare function describedBy(id: string, errorText: string | undefined, ...hintIds: Array<string | undefined>): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Props the date and date-time fields share; each adds its own `value`,
|
|
35
|
+
* `onValueChange`, and `placeholder`.
|
|
36
|
+
*/
|
|
37
|
+
export type PickerFieldBaseProps = FormFieldBaseProps & FormFieldMetaProps & {
|
|
38
|
+
/** Disables the trigger so no date can be picked. */
|
|
39
|
+
disabled?: boolean;
|
|
40
|
+
/** Marks the label and adds "Required" to the trigger's description. */
|
|
41
|
+
required?: boolean;
|
|
42
|
+
/** Earliest day that can be picked; earlier days are disabled. */
|
|
43
|
+
minDate?: DateLike;
|
|
44
|
+
/** Latest day that can be picked; later days are disabled. */
|
|
45
|
+
maxDate?: DateLike;
|
|
46
|
+
/** Forwarded to the picker trigger. */
|
|
47
|
+
className?: string;
|
|
48
|
+
/** Forwarded to the picker popover. */
|
|
49
|
+
contentClassName?: string;
|
|
50
|
+
/** Day Picker options forwarded to the calendar (disabled days, etc.). */
|
|
51
|
+
calendarProps?: DatePickerCalendarProps;
|
|
52
|
+
};
|
|
25
53
|
/**
|
|
26
54
|
* Trigger ARIA for the date and date-time fields: invalid while there is
|
|
27
55
|
* error text, named "label, value" (a `<label for>` alone would hide the
|
|
@@ -38,16 +66,27 @@ export declare function pickerFieldAria(id: string, errorText: string | undefine
|
|
|
38
66
|
* `labelAction` sits on the label's row (the Markdown field's mode toggle).
|
|
39
67
|
* Set `labelFor` to false when the control is not rendered (Markdown
|
|
40
68
|
* preview), so the label does not point at a missing element.
|
|
41
|
-
* `
|
|
69
|
+
* `description` is a hint between the label and the control, with id
|
|
70
|
+
* `descriptionIdFor(id)`. `className` and other div props go to the
|
|
71
|
+
* wrapper (`data-slot="form-field"`), e.g. a width.
|
|
42
72
|
* `required` marks the label; the control still sets its own `required`.
|
|
73
|
+
* The error sits below the control and takes no space while there is none,
|
|
74
|
+
* so put fields in a grid row with `items-start` to keep controls aligned.
|
|
43
75
|
*/
|
|
44
|
-
export declare function FormFieldShell({ id, label, labelAction, errorText, labelFor, required, className, children, }: {
|
|
76
|
+
export declare function FormFieldShell({ id, label, labelAction, description, errorText, labelFor, required, className, children, ...props }: Omit<ComponentProps<"div">, "id" | "children"> & {
|
|
77
|
+
/** Id of the control; the label, hint, and error ids derive from it. */
|
|
45
78
|
id: string;
|
|
79
|
+
/** Visible label text. */
|
|
46
80
|
label: string;
|
|
81
|
+
/** Content on the label's row, after the label (e.g. a mode toggle). */
|
|
47
82
|
labelAction?: ReactNode;
|
|
83
|
+
/** Hint between the label and the control, with id `descriptionIdFor(id)`. */
|
|
84
|
+
description?: ReactNode;
|
|
85
|
+
/** Error text under the control; `undefined` shows none. */
|
|
48
86
|
errorText: string | undefined;
|
|
87
|
+
/** When false, the label does not point at the control. Default true. */
|
|
49
88
|
labelFor?: boolean;
|
|
89
|
+
/** Marks the label and renders the hidden "Required" text. */
|
|
50
90
|
required?: boolean;
|
|
51
|
-
className?: string;
|
|
52
91
|
children: ReactNode;
|
|
53
92
|
}): import("react").JSX.Element;
|
package/dist/form/field-shell.js
CHANGED
|
@@ -5,11 +5,20 @@ import { cn } from "../utils.js";
|
|
|
5
5
|
import { FieldError, getFieldErrorMessage, } from "./field-error.js";
|
|
6
6
|
/**
|
|
7
7
|
* Not a public entry. The layout and error wiring every `form/*` field
|
|
8
|
-
* shares, so a field only says which control it renders.
|
|
8
|
+
* shares, so a field only says which control it renders. Custom controls
|
|
9
|
+
* get the same shell through the public `FormControlField`.
|
|
9
10
|
*/
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* First error in `meta`, or `undefined` when there is no meta, no error,
|
|
13
|
+
* `showError` is false, or the field is untouched (`isTouched: false`)
|
|
14
|
+
* and the form has not been submitted.
|
|
15
|
+
*/
|
|
16
|
+
export function metaErrorText(meta, { submitted, showError = true } = {}) {
|
|
17
|
+
if (!meta || !showError)
|
|
18
|
+
return undefined;
|
|
19
|
+
if (meta.isTouched === false && !submitted)
|
|
20
|
+
return undefined;
|
|
21
|
+
return getFieldErrorMessage(meta.errors[0]);
|
|
13
22
|
}
|
|
14
23
|
/** `aria-invalid` for the control: `true` while there is error text. */
|
|
15
24
|
export function invalidWhen(errorText) {
|
|
@@ -19,6 +28,10 @@ export function invalidWhen(errorText) {
|
|
|
19
28
|
export function labelIdFor(id) {
|
|
20
29
|
return `${id}-label`;
|
|
21
30
|
}
|
|
31
|
+
/** Id of the hint `FormFieldShell` renders for control `id`. */
|
|
32
|
+
export function descriptionIdFor(id) {
|
|
33
|
+
return `${id}-description`;
|
|
34
|
+
}
|
|
22
35
|
/** Id of the error text `FormFieldShell` renders for control `id`. */
|
|
23
36
|
export function errorIdFor(id) {
|
|
24
37
|
return `${id}-error`;
|
|
@@ -56,10 +69,14 @@ export function pickerFieldAria(id, errorText, required) {
|
|
|
56
69
|
* `labelAction` sits on the label's row (the Markdown field's mode toggle).
|
|
57
70
|
* Set `labelFor` to false when the control is not rendered (Markdown
|
|
58
71
|
* preview), so the label does not point at a missing element.
|
|
59
|
-
* `
|
|
72
|
+
* `description` is a hint between the label and the control, with id
|
|
73
|
+
* `descriptionIdFor(id)`. `className` and other div props go to the
|
|
74
|
+
* wrapper (`data-slot="form-field"`), e.g. a width.
|
|
60
75
|
* `required` marks the label; the control still sets its own `required`.
|
|
76
|
+
* The error sits below the control and takes no space while there is none,
|
|
77
|
+
* so put fields in a grid row with `items-start` to keep controls aligned.
|
|
61
78
|
*/
|
|
62
|
-
export function FormFieldShell({ id, label, labelAction, errorText, labelFor = true, required, className, children, }) {
|
|
79
|
+
export function FormFieldShell({ id, label, labelAction, description, errorText, labelFor = true, required, className, children, ...props }) {
|
|
63
80
|
const labelNode = (_jsx(Label, { id: labelIdFor(id), htmlFor: labelFor ? id : undefined, required: required, children: label }));
|
|
64
|
-
return (_jsxs("div", { "data-slot": "form-field", className: cn("flex flex-col gap-1.5", className), children: [labelAction ? (_jsxs("div", { "data-slot": "form-field-header", className: "flex items-center justify-between gap-2", children: [labelNode, labelAction] })) : (labelNode), children, required ? (_jsx("span", { id: requiredIdFor(id), hidden: true, children: "Required" })) : null, _jsx(FieldError, { id: errorIdFor(id), text: errorText })] }));
|
|
81
|
+
return (_jsxs("div", { "data-slot": "form-field", className: cn("flex flex-col gap-1.5", className), ...props, children: [labelAction ? (_jsxs("div", { "data-slot": "form-field-header", className: "flex items-center justify-between gap-2", children: [labelNode, labelAction] })) : (labelNode), description ? (_jsx("p", { id: descriptionIdFor(id), "data-slot": "form-field-description", className: "text-xs text-muted-foreground", children: description })) : null, children, required ? (_jsx("span", { id: requiredIdFor(id), hidden: true, children: "Required" })) : null, _jsx(FieldError, { id: errorIdFor(id), text: errorText })] }));
|
|
65
82
|
}
|
|
@@ -1,25 +1,13 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TextFieldBaseProps } from "./text-field.js";
|
|
2
2
|
/**
|
|
3
3
|
* GFM body field: Write is a textarea, Preview is the sanitized Markdown
|
|
4
4
|
* renderer. String-in/string-out — not a WYSIWYG document model.
|
|
5
5
|
*/
|
|
6
|
-
export declare function FormMarkdownField({ field, id, label, placeholder, rows, showError, required, className, fieldClassName, previewClassName, }: {
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Control id the label points at. Defaults to `field.name`; pass a unique
|
|
10
|
-
* id when two forms on one page share a field name.
|
|
11
|
-
*/
|
|
12
|
-
id?: string;
|
|
13
|
-
label: string;
|
|
6
|
+
export declare function FormMarkdownField({ field, id, label, placeholder, rows, showError, submitted, required, className, fieldClassName, previewClassName, }: TextFieldBaseProps & {
|
|
7
|
+
/** Write textarea placeholder. Default "Markdown supported". */
|
|
14
8
|
placeholder?: string;
|
|
9
|
+
/** Write textarea rows. Default 5. */
|
|
15
10
|
rows?: number;
|
|
16
|
-
showError?: boolean;
|
|
17
|
-
/** Sets `required` on the Write textarea and marks the label. */
|
|
18
|
-
required?: boolean;
|
|
19
|
-
/** Forwarded to the Write textarea. */
|
|
20
|
-
className?: string;
|
|
21
|
-
/** Classes for the field wrapper (label row, body, and error). */
|
|
22
|
-
fieldClassName?: string;
|
|
23
11
|
/** Classes for the Preview surface, e.g. a taller `min-h-40`. */
|
|
24
12
|
previewClassName?: string;
|
|
25
13
|
}): import("react").JSX.Element;
|
|
@@ -16,10 +16,10 @@ const Markdown = lazy(() => loadMarkdown().then((module) => ({ default: module.M
|
|
|
16
16
|
* GFM body field: Write is a textarea, Preview is the sanitized Markdown
|
|
17
17
|
* renderer. String-in/string-out — not a WYSIWYG document model.
|
|
18
18
|
*/
|
|
19
|
-
export function FormMarkdownField({ field, id = field.name, label, placeholder = "Markdown supported", rows = 5, showError
|
|
19
|
+
export function FormMarkdownField({ field, id = field.name, label, placeholder = "Markdown supported", rows = 5, showError, submitted, required, className, fieldClassName, previewClassName, }) {
|
|
20
20
|
const [mode, setMode] = useState("write");
|
|
21
21
|
const onChange = onInputChange(field.handleChange);
|
|
22
|
-
const errorText =
|
|
22
|
+
const errorText = metaErrorText(field.state.meta, { submitted, showError });
|
|
23
23
|
const trimmed = field.state.value.trim();
|
|
24
24
|
function handleModeChange(value) {
|
|
25
25
|
if (value === "write" || value === "preview")
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import type {
|
|
3
|
-
type Props = {
|
|
2
|
+
import type { FormFieldBaseProps, FormFieldMetaProps } from "./field-error.js";
|
|
3
|
+
type Props = FormFieldBaseProps & FormFieldMetaProps & {
|
|
4
|
+
/** The selected item's value, or `undefined` for none. */
|
|
4
5
|
value: string | undefined;
|
|
5
|
-
|
|
6
|
-
label: string;
|
|
6
|
+
/** Called with the value of the item the person picks. */
|
|
7
7
|
onValueChange: (value: string) => void;
|
|
8
|
+
/** Trigger text while no item is selected. */
|
|
8
9
|
placeholder?: string;
|
|
9
10
|
/** Requires a value (native form validation) and marks the label. */
|
|
10
11
|
required?: boolean;
|
|
11
12
|
/** Forwarded to the select trigger. */
|
|
12
13
|
className?: string;
|
|
13
|
-
/** Classes for the field wrapper (label, trigger, and error). */
|
|
14
|
-
fieldClassName?: string;
|
|
15
14
|
/** Forwarded to the select's option list (`SelectContent`). */
|
|
16
15
|
contentClassName?: string;
|
|
16
|
+
/** The `SelectItem`s (and groups) to choose from. */
|
|
17
17
|
children: ReactNode;
|
|
18
18
|
};
|
|
19
19
|
/** Select control with built-in field error text and invalid styling. */
|
|
20
|
-
export declare function FormSelectField({ value, meta, label, onValueChange, placeholder, required, className, fieldClassName, contentClassName, children, }: Props): import("react").JSX.Element;
|
|
20
|
+
export declare function FormSelectField({ value, meta, submitted, showError, label, onValueChange, placeholder, required, className, fieldClassName, contentClassName, children, }: Props): import("react").JSX.Element;
|
|
21
21
|
export {};
|
|
@@ -4,8 +4,8 @@ import { useId } from "react";
|
|
|
4
4
|
import { Select, SelectContent, SelectTrigger, SelectValue } from "../select.js";
|
|
5
5
|
import { describedBy, FormFieldShell, invalidWhen, metaErrorText, } from "./field-shell.js";
|
|
6
6
|
/** Select control with built-in field error text and invalid styling. */
|
|
7
|
-
export function FormSelectField({ value, meta, label, onValueChange, placeholder, required, className, fieldClassName, contentClassName, children, }) {
|
|
8
|
-
const errorText = metaErrorText(meta);
|
|
7
|
+
export function FormSelectField({ value, meta, submitted, showError, label, onValueChange, placeholder, required, className, fieldClassName, contentClassName, children, }) {
|
|
8
|
+
const errorText = metaErrorText(meta, { submitted, showError });
|
|
9
9
|
const id = useId();
|
|
10
10
|
return (_jsx(FormFieldShell, { id: id, label: label, errorText: errorText, required: required, className: fieldClassName, children: _jsxs(Select, { value: value, onValueChange: onValueChange, required: required, children: [_jsx(SelectTrigger, { id: id, className: className, "aria-required": required || undefined, "aria-invalid": invalidWhen(errorText), "aria-describedby": describedBy(id, errorText), children: _jsx(SelectValue, { placeholder: placeholder }) }), _jsx(SelectContent, { className: contentClassName, children: children })] }) }));
|
|
11
11
|
}
|
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
import type { FieldMetaState } from "./field-error.js";
|
|
1
|
+
import type { FieldMetaState, FormFieldBaseProps } from "./field-error.js";
|
|
2
2
|
export type TextFieldApi = {
|
|
3
|
+
/** Field name; the default control id. */
|
|
3
4
|
name: string;
|
|
4
5
|
state: {
|
|
6
|
+
/** Current text. */
|
|
5
7
|
value: string;
|
|
8
|
+
/** Error meta; its first error shows under the control. */
|
|
6
9
|
meta: FieldMetaState;
|
|
7
10
|
};
|
|
11
|
+
/** Called with the new text on every change. */
|
|
8
12
|
handleChange: (value: string) => void;
|
|
13
|
+
/** Called when the control loses focus, to mark the field touched. */
|
|
9
14
|
handleBlur: () => void;
|
|
10
15
|
};
|
|
11
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Props the text and Markdown fields share: both bind to a TanStack Form
|
|
18
|
+
* `field` and render a text control.
|
|
19
|
+
*/
|
|
20
|
+
export type TextFieldBaseProps = FormFieldBaseProps & {
|
|
21
|
+
/** The TanStack Form field (or the same shape) the control reads and writes. */
|
|
12
22
|
field: TextFieldApi;
|
|
13
23
|
/**
|
|
14
24
|
* Control id the label points at. Defaults to `field.name`; pass a unique
|
|
@@ -16,23 +26,30 @@ export declare function FormTextField({ field, id, label, placeholder, descripti
|
|
|
16
26
|
* `email`), or the second label focuses the first input.
|
|
17
27
|
*/
|
|
18
28
|
id?: string;
|
|
19
|
-
label
|
|
29
|
+
/** Sets `required` on the text control and marks the label. */
|
|
30
|
+
required?: boolean;
|
|
31
|
+
/** Forwarded to the text control (the input or textarea). */
|
|
32
|
+
className?: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Text input, or a textarea with `multiline`, bound to a TanStack Form
|
|
36
|
+
* `field`, with a label, optional hint, and the `form/*` error text.
|
|
37
|
+
*/
|
|
38
|
+
export declare function FormTextField({ field, id, label, placeholder, description, autoFocus, multiline, rows, inputType, showError, submitted, autoComplete, required, minLength, className, fieldClassName, }: TextFieldBaseProps & {
|
|
39
|
+
/** Text shown in the empty control. */
|
|
20
40
|
placeholder?: string;
|
|
21
41
|
/** Optional hint under the label (employer vs referrer, etc.). */
|
|
22
42
|
description?: string;
|
|
43
|
+
/** Focuses the input on mount (ignored with `multiline`). */
|
|
23
44
|
autoFocus?: boolean;
|
|
45
|
+
/** Renders a textarea instead of an input. */
|
|
24
46
|
multiline?: boolean;
|
|
25
|
-
/** Textarea rows when `multiline` is set. */
|
|
47
|
+
/** Textarea rows when `multiline` is set. Default 3. */
|
|
26
48
|
rows?: number;
|
|
49
|
+
/** The input's `type` when not `multiline`. Default "text". */
|
|
27
50
|
inputType?: "text" | "email" | "password" | "date" | "datetime-local" | "time" | "number";
|
|
28
|
-
/**
|
|
29
|
-
showError?: boolean;
|
|
51
|
+
/** Forwarded to the control's `autoComplete`. */
|
|
30
52
|
autoComplete?: string;
|
|
31
|
-
/**
|
|
32
|
-
required?: boolean;
|
|
53
|
+
/** Minimum text length (native form validation). */
|
|
33
54
|
minLength?: number;
|
|
34
|
-
/** Forwarded to the input or textarea. */
|
|
35
|
-
className?: string;
|
|
36
|
-
/** Classes for the field wrapper (label, hint, control, and error). */
|
|
37
|
-
fieldClassName?: string;
|
|
38
55
|
}): import("react").JSX.Element;
|
package/dist/form/text-field.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { Input } from "../input.js";
|
|
4
4
|
import { Textarea } from "../textarea.js";
|
|
5
5
|
import { onInputChange } from "../utils.js";
|
|
6
|
-
import { describedBy, FormFieldShell, invalidWhen, metaErrorText, } from "./field-shell.js";
|
|
7
|
-
|
|
6
|
+
import { describedBy, descriptionIdFor, FormFieldShell, invalidWhen, metaErrorText, } from "./field-shell.js";
|
|
7
|
+
/**
|
|
8
|
+
* Text input, or a textarea with `multiline`, bound to a TanStack Form
|
|
9
|
+
* `field`, with a label, optional hint, and the `form/*` error text.
|
|
10
|
+
*/
|
|
11
|
+
export function FormTextField({ field, id = field.name, label, placeholder, description, autoFocus, multiline, rows = 3, inputType = "text", showError, submitted, autoComplete, required, minLength, className, fieldClassName, }) {
|
|
8
12
|
const onChange = onInputChange(field.handleChange);
|
|
9
|
-
const errorText =
|
|
10
|
-
const descriptionId = description ?
|
|
13
|
+
const errorText = metaErrorText(field.state.meta, { submitted, showError });
|
|
14
|
+
const descriptionId = description ? descriptionIdFor(id) : undefined;
|
|
11
15
|
const controlProps = {
|
|
12
16
|
id,
|
|
13
17
|
value: field.state.value,
|
|
@@ -21,5 +25,5 @@ export function FormTextField({ field, id = field.name, label, placeholder, desc
|
|
|
21
25
|
"aria-invalid": invalidWhen(errorText),
|
|
22
26
|
"aria-describedby": describedBy(id, errorText, descriptionId),
|
|
23
27
|
};
|
|
24
|
-
return (
|
|
28
|
+
return (_jsx(FormFieldShell, { id: id, label: label, description: description, errorText: errorText, required: required, className: fieldClassName, children: multiline ? (_jsx(Textarea, { ...controlProps, rows: rows })) : (_jsx(Input, { ...controlProps, type: inputType, autoFocus: autoFocus })) }));
|
|
25
29
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { FormFieldBaseProps, FormFieldDescriptionProps, FormFieldMetaProps } from "./field-error.js";
|
|
3
|
+
export type ToggleGroupFieldOption<T extends string> = {
|
|
4
|
+
/** Value passed to `onValueChange` when this item is pressed. */
|
|
5
|
+
value: T;
|
|
6
|
+
/** Content of the toggle item. */
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
};
|
|
9
|
+
type Props<T extends string> = FormFieldBaseProps & FormFieldMetaProps & FormFieldDescriptionProps & {
|
|
10
|
+
/** The selected option, or `""` for none yet. */
|
|
11
|
+
value: T | "";
|
|
12
|
+
/** Called with an option's value; pressing the active item keeps it. */
|
|
13
|
+
onValueChange: (value: T) => void;
|
|
14
|
+
/** The items to choose from, in order. */
|
|
15
|
+
options: ToggleGroupFieldOption<T>[];
|
|
16
|
+
/** Marks the label. */
|
|
17
|
+
required?: boolean;
|
|
18
|
+
/** Disables every item in the group. */
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
/** Size of the toggle items. Default "sm". */
|
|
21
|
+
size?: "default" | "sm" | "lg";
|
|
22
|
+
/** Forwarded to the toggle group. */
|
|
23
|
+
className?: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* One choice from a few as a joined outline toggle group (a segmented
|
|
27
|
+
* control), with a visible label and the `form/*` error wiring.
|
|
28
|
+
*/
|
|
29
|
+
export declare function FormToggleGroupField<T extends string>({ label, description, value, onValueChange, options, meta, submitted, showError, required, disabled, size, className, fieldClassName, }: Props<T>): import("react").JSX.Element;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
import { ToggleGroup, ToggleGroupItem } from "../toggle-group.js";
|
|
5
|
+
import { describedBy, descriptionIdFor, FormFieldShell, invalidWhen, labelIdFor, metaErrorText, } from "./field-shell.js";
|
|
6
|
+
/**
|
|
7
|
+
* One choice from a few as a joined outline toggle group (a segmented
|
|
8
|
+
* control), with a visible label and the `form/*` error wiring.
|
|
9
|
+
*/
|
|
10
|
+
export function FormToggleGroupField({ label, description, value, onValueChange, options, meta, submitted, showError, required, disabled, size = "sm", className, fieldClassName, }) {
|
|
11
|
+
const id = useId();
|
|
12
|
+
const errorText = metaErrorText(meta, { submitted, showError });
|
|
13
|
+
function handleValueChange(next) {
|
|
14
|
+
const option = options.find((o) => o.value === next);
|
|
15
|
+
if (option)
|
|
16
|
+
onValueChange(option.value);
|
|
17
|
+
}
|
|
18
|
+
return (_jsx(FormFieldShell, { id: id, label: label, labelFor: false, description: description, errorText: errorText, required: required, className: fieldClassName, children: _jsx(ToggleGroup, { id: id, type: "single", value: value, onValueChange: handleValueChange, variant: "outline", size: size, spacing: 0, disabled: disabled, "aria-labelledby": labelIdFor(id), "aria-invalid": invalidWhen(errorText), "aria-describedby": describedBy(id, errorText, description ? descriptionIdFor(id) : undefined), className: className, children: options.map((option) => (_jsx(ToggleGroupItem, { value: option.value, children: option.label }, option.value))) }) }));
|
|
19
|
+
}
|
package/dist/info-tip.d.ts
CHANGED
|
@@ -4,15 +4,24 @@ export type InfoTipLayout = "box" | "inline";
|
|
|
4
4
|
export type InfoTipProps = {
|
|
5
5
|
/** Required name for the icon button (the glyph has no visible text). */
|
|
6
6
|
label: string;
|
|
7
|
+
/** Panel heading; also names the panel. Without it the panel uses `label`. */
|
|
7
8
|
title?: string;
|
|
9
|
+
/** Muted text under the title. */
|
|
8
10
|
description?: React.ReactNode;
|
|
9
11
|
/** Extra body after the title and description. */
|
|
10
12
|
children?: React.ReactNode;
|
|
11
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* `inline` keeps the surrounding line height; the 44px hit area overflows.
|
|
15
|
+
* Default `box`.
|
|
16
|
+
*/
|
|
12
17
|
layout?: InfoTipLayout;
|
|
18
|
+
/** Panel side. Default `top`; Radix still flips on collision. */
|
|
13
19
|
side?: React.ComponentProps<typeof PopoverContent>["side"];
|
|
20
|
+
/** Panel alignment against the trigger. Default `center`. */
|
|
14
21
|
align?: React.ComponentProps<typeof PopoverContent>["align"];
|
|
22
|
+
/** Shown beside the title, e.g. a `Badge`. */
|
|
15
23
|
badge?: React.ReactNode;
|
|
24
|
+
/** Replaces the default question-mark glyph. */
|
|
16
25
|
icon?: React.ReactNode;
|
|
17
26
|
/** Classes for the trigger button. */
|
|
18
27
|
className?: string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Not a public entry. The Slot prop that Button, Badge, and the links share. */
|
|
2
|
+
export type AsChildProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Render the single child (e.g. a router `Link`) with these styles instead
|
|
5
|
+
* of the default element. Default `false`.
|
|
6
|
+
*/
|
|
7
|
+
asChild?: boolean;
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -6,3 +6,26 @@ export type DateLike = Date | string | number | null | undefined;
|
|
|
6
6
|
* shift when the runtime timezone is behind UTC.
|
|
7
7
|
*/
|
|
8
8
|
export declare function toDate(value: DateLike): Date | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* A from/to pair of days. `to` is unset while a range is half picked. Same
|
|
11
|
+
* shape as Day Picker's, so either can be passed where the other is expected.
|
|
12
|
+
*/
|
|
13
|
+
export type DateRange = {
|
|
14
|
+
from: Date | undefined;
|
|
15
|
+
to?: Date | undefined;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Matches calendar days, for `disabled` and `hidden`: `true` for every day,
|
|
19
|
+
* one date or a list, a range, days `before` / `after` a date (both: the days
|
|
20
|
+
* outside them), weekdays (`0` is Sunday), or a predicate.
|
|
21
|
+
*/
|
|
22
|
+
export type DateMatcher = boolean | Date | Date[] | DateRange | {
|
|
23
|
+
before: Date;
|
|
24
|
+
} | {
|
|
25
|
+
after: Date;
|
|
26
|
+
} | {
|
|
27
|
+
before: Date;
|
|
28
|
+
after: Date;
|
|
29
|
+
} | {
|
|
30
|
+
dayOfWeek: number | number[];
|
|
31
|
+
} | ((date: Date) => boolean);
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
export declare const formControlTriggerClassName = "h-10 w-full border-input bg-background px-3 font-normal text-base tracking-normal shadow-xs normal-case md:text-sm hover:border-input hover:bg-background hover:text-foreground focus-visible:text-foreground aria-expanded:border-input aria-expanded:bg-background aria-expanded:text-foreground has-data-[icon=inline-start]:pl-3 has-data-[icon=inline-end]:pr-3 dark:hover:bg-background dark:aria-expanded:bg-background";
|
|
10
10
|
/**
|
|
11
11
|
* Date and date-time picker trigger: the form-control chrome, start-aligned,
|
|
12
|
-
* with muted text while empty (`data-empty`).
|
|
12
|
+
* with muted text while empty (`data-empty`). Intrinsic padding makes one
|
|
13
|
+
* line 40px tall while longer values wrap and consumer height classes work.
|
|
13
14
|
*/
|
|
14
|
-
export declare const pickerTriggerClassName = "h-10 w-full border-input bg-background px-3 font-normal text-base tracking-normal shadow-xs normal-case md:text-sm hover:border-input hover:bg-background hover:text-foreground focus-visible:text-foreground aria-expanded:border-input aria-expanded:bg-background aria-expanded:text-foreground has-data-[icon=inline-start]:pl-3 has-data-[icon=inline-end]:pr-3 dark:hover:bg-background dark:aria-expanded:bg-background justify-start data-[empty=true]:text-muted-foreground";
|
|
15
|
+
export declare const pickerTriggerClassName = "h-10 w-full border-input bg-background px-3 font-normal text-base tracking-normal shadow-xs normal-case md:text-sm hover:border-input hover:bg-background hover:text-foreground focus-visible:text-foreground aria-expanded:border-input aria-expanded:bg-background aria-expanded:text-foreground has-data-[icon=inline-start]:pl-3 has-data-[icon=inline-end]:pr-3 dark:hover:bg-background dark:aria-expanded:bg-background h-auto justify-start py-[calc((--spacing(10)_-_1lh_-_2px)/2)] data-[empty=true]:text-muted-foreground";
|
|
15
16
|
/** Calendar popover body: fits the viewport height and scrolls inside it. */
|
|
16
17
|
export declare const pickerContentClassName = "max-h-(--radix-popover-content-available-height) overflow-y-auto rounded-none p-0";
|
|
17
18
|
/** Gutter used when a calendar popover collides with the viewport. */
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
export const formControlTriggerClassName = "h-10 w-full border-input bg-background px-3 font-normal text-base tracking-normal shadow-xs normal-case md:text-sm hover:border-input hover:bg-background hover:text-foreground focus-visible:text-foreground aria-expanded:border-input aria-expanded:bg-background aria-expanded:text-foreground has-data-[icon=inline-start]:pl-3 has-data-[icon=inline-end]:pr-3 dark:hover:bg-background dark:aria-expanded:bg-background";
|
|
10
10
|
/**
|
|
11
11
|
* Date and date-time picker trigger: the form-control chrome, start-aligned,
|
|
12
|
-
* with muted text while empty (`data-empty`).
|
|
12
|
+
* with muted text while empty (`data-empty`). Intrinsic padding makes one
|
|
13
|
+
* line 40px tall while longer values wrap and consumer height classes work.
|
|
13
14
|
*/
|
|
14
|
-
export const pickerTriggerClassName = `${formControlTriggerClassName} justify-start data-[empty=true]:text-muted-foreground`;
|
|
15
|
+
export const pickerTriggerClassName = `${formControlTriggerClassName} h-auto justify-start py-[calc((--spacing(10)_-_1lh_-_2px)/2)] data-[empty=true]:text-muted-foreground`;
|
|
15
16
|
/** Calendar popover body: fits the viewport height and scrolls inside it. */
|
|
16
17
|
export const pickerContentClassName = "max-h-(--radix-popover-content-available-height) overflow-y-auto rounded-none p-0";
|
|
17
18
|
/** Gutter used when a calendar popover collides with the viewport. */
|