@jwcarman/roux-web 0.0.0-stage → 0.1.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/LICENSE +201 -0
- package/README.md +21 -2
- package/dist/api/client.d.ts +17 -0
- package/dist/api/client.js +57 -0
- package/dist/api/config.d.ts +11 -0
- package/dist/api/config.js +15 -0
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.js +4 -0
- package/dist/api/serverAction.d.ts +23 -0
- package/dist/api/serverAction.js +28 -0
- package/dist/feedback/ConfirmProvider.d.ts +21 -0
- package/dist/feedback/ConfirmProvider.js +50 -0
- package/dist/feedback/ErrorMessage.d.ts +7 -0
- package/dist/feedback/ErrorMessage.js +11 -0
- package/dist/feedback/index.d.ts +4 -0
- package/dist/feedback/index.js +5 -0
- package/dist/feedback/notify.d.ts +16 -0
- package/dist/feedback/notify.js +27 -0
- package/dist/feedback/toaster.d.ts +7 -0
- package/dist/feedback/toaster.js +29 -0
- package/dist/form/FormDialog.d.ts +34 -0
- package/dist/form/FormDialog.js +36 -0
- package/dist/form/errors.d.ts +8 -0
- package/dist/form/errors.js +17 -0
- package/dist/form/fields/CheckboxField.d.ts +4 -0
- package/dist/form/fields/CheckboxField.js +25 -0
- package/dist/form/fields/FormField.d.ts +20 -0
- package/dist/form/fields/FormField.js +24 -0
- package/dist/form/fields/InputField.d.ts +5 -0
- package/dist/form/fields/InputField.js +21 -0
- package/dist/form/fields/NumberField.d.ts +10 -0
- package/dist/form/fields/NumberField.js +26 -0
- package/dist/form/fields/RadioGroupField.d.ts +8 -0
- package/dist/form/fields/RadioGroupField.js +33 -0
- package/dist/form/fields/SelectField.d.ts +12 -0
- package/dist/form/fields/SelectField.js +25 -0
- package/dist/form/fields/TextAreaField.d.ts +5 -0
- package/dist/form/fields/TextAreaField.js +21 -0
- package/dist/form/fields/formComponents.d.ts +18 -0
- package/dist/form/fields/formComponents.js +50 -0
- package/dist/form/form.d.ts +73 -0
- package/dist/form/form.js +54 -0
- package/dist/form/formContext.d.ts +2 -0
- package/dist/form/formContext.js +4 -0
- package/dist/form/index.d.ts +13 -0
- package/dist/form/index.js +14 -0
- package/dist/form/values.d.ts +20 -0
- package/dist/form/values.js +24 -0
- package/dist/paging/index.d.ts +1 -0
- package/dist/paging/index.js +1 -0
- package/dist/paging/paging.d.ts +80 -0
- package/dist/paging/paging.js +71 -0
- package/dist/problem/index.d.ts +1 -0
- package/dist/problem/index.js +1 -0
- package/dist/problem/problem.d.ts +22 -0
- package/dist/problem/problem.js +24 -0
- package/dist/table/FilterChips.d.ts +16 -0
- package/dist/table/FilterChips.js +28 -0
- package/dist/table/QueryTable.d.ts +11 -0
- package/dist/table/QueryTable.js +29 -0
- package/dist/table/SimpleQueryTable.d.ts +17 -0
- package/dist/table/SimpleQueryTable.js +37 -0
- package/dist/table/TablePageSizeSelect.d.ts +9 -0
- package/dist/table/TablePageSizeSelect.js +35 -0
- package/dist/table/TablePagination.d.ts +5 -0
- package/dist/table/TablePagination.js +65 -0
- package/dist/table/TableStatus.d.ts +6 -0
- package/dist/table/TableStatus.js +27 -0
- package/dist/table/TableView.d.ts +7 -0
- package/dist/table/TableView.js +31 -0
- package/dist/table/TanstackTable.d.ts +16 -0
- package/dist/table/TanstackTable.js +61 -0
- package/dist/table/index.d.ts +11 -0
- package/dist/table/index.js +12 -0
- package/dist/table/selectColumn.d.ts +17 -0
- package/dist/table/selectColumn.js +36 -0
- package/dist/table/useDebounce.d.ts +2 -0
- package/dist/table/useDebounce.js +10 -0
- package/dist/table/useQueryTable.d.ts +49 -0
- package/dist/table/useQueryTable.js +127 -0
- package/package.json +85 -4
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Problem } from "../problem/problem";
|
|
2
|
+
/**
|
|
3
|
+
* The messages to show for a field's errors. Validators return strings, or objects with a
|
|
4
|
+
* `message` (as schema validators do), or lists of either; empty entries and repeats are dropped.
|
|
5
|
+
*/
|
|
6
|
+
export declare function errorMessages(errors: readonly unknown[]): string[];
|
|
7
|
+
/** A problem's field errors, the first message for each field, for `showServerErrors`. */
|
|
8
|
+
export declare function fieldErrorsOf(problem: Problem): Record<string, string>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function e(e) {
|
|
2
|
+
let t = [], n = (e) => {
|
|
3
|
+
if (Array.isArray(e)) e.forEach(n);
|
|
4
|
+
else if (typeof e == "string") t.push(e);
|
|
5
|
+
else if (typeof e == "object" && e) {
|
|
6
|
+
let n = e.message;
|
|
7
|
+
t.push(typeof n == "string" ? n : "Invalid value");
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
return e.forEach(n), [...new Set(t.filter((e) => e.trim() !== ""))];
|
|
11
|
+
}
|
|
12
|
+
function t(e) {
|
|
13
|
+
let t = {};
|
|
14
|
+
for (let { field: n, message: r } of e.errors ?? []) t[n] ??= r;
|
|
15
|
+
return t;
|
|
16
|
+
}
|
|
17
|
+
export { e as errorMessages, t as fieldErrorsOf };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type FormFieldProps } from "./FormField";
|
|
2
|
+
export type CheckboxFieldProps = Omit<FormFieldProps, "children" | "controlLabelled">;
|
|
3
|
+
/** A checkbox for a boolean field, named by its own label. */
|
|
4
|
+
export declare function CheckboxField({ label, helperText, required }: CheckboxFieldProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useFieldContext as e } from "../formContext.js";
|
|
2
|
+
import { FormField as t } from "./FormField.js";
|
|
3
|
+
import { Checkbox as n } from "@chakra-ui/react";
|
|
4
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
5
|
+
// src/form/fields/CheckboxField.tsx
|
|
6
|
+
function a({ label: a, helperText: o, required: s }) {
|
|
7
|
+
let c = e();
|
|
8
|
+
return /* @__PURE__ */ r(t, {
|
|
9
|
+
label: a,
|
|
10
|
+
helperText: o,
|
|
11
|
+
required: s,
|
|
12
|
+
controlLabelled: !0,
|
|
13
|
+
children: /* @__PURE__ */ i(n.Root, {
|
|
14
|
+
name: c.name,
|
|
15
|
+
checked: c.state.value,
|
|
16
|
+
onCheckedChange: ({ checked: e }) => c.handleChange(e === !0),
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ r(n.HiddenInput, { onBlur: c.handleBlur }),
|
|
19
|
+
/* @__PURE__ */ r(n.Control, {}),
|
|
20
|
+
/* @__PURE__ */ r(n.Label, { children: a })
|
|
21
|
+
]
|
|
22
|
+
})
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export { a as CheckboxField };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface FormFieldProps {
|
|
3
|
+
label: ReactNode;
|
|
4
|
+
/** A hint under the field, replaced by its errors when it has any. */
|
|
5
|
+
helperText?: ReactNode;
|
|
6
|
+
required?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* The control names itself with `label` (a radio group's own group label), so the frame shows no
|
|
9
|
+
* `<label>` of its own.
|
|
10
|
+
*/
|
|
11
|
+
controlLabelled?: boolean;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A field's frame: its label, its control (the children, wired by Chakra's Field to the label and
|
|
16
|
+
* the messages, so screen readers announce them), and its errors. Errors show once the field has
|
|
17
|
+
* been left or the form submitted, never while a first entry is still being typed, and a server's
|
|
18
|
+
* error for the field shows at once (TanStack Form clears it when the field changes).
|
|
19
|
+
*/
|
|
20
|
+
export declare function FormField({ label, helperText, required, controlLabelled, children }: FormFieldProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { errorMessages as e } from "../errors.js";
|
|
2
|
+
import { useFieldContext as t } from "../formContext.js";
|
|
3
|
+
import { Box as n, Field as r } from "@chakra-ui/react";
|
|
4
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
|
+
import { useStore as o } from "@tanstack/react-form";
|
|
6
|
+
// src/form/fields/FormField.tsx
|
|
7
|
+
function s({ label: s, helperText: c, required: l, controlLabelled: u = !1, children: d }) {
|
|
8
|
+
let f = t(), p = o(f.form.store, (e) => e.submissionAttempts > 0), m = f.state.meta, h = m.isBlurred || p || m.errorMap.onServer ? e(m.errors) : [];
|
|
9
|
+
return /* @__PURE__ */ a(r.Root, {
|
|
10
|
+
invalid: h.length > 0,
|
|
11
|
+
required: l,
|
|
12
|
+
children: [
|
|
13
|
+
!u && /* @__PURE__ */ a(r.Label, { children: [s, l && /* @__PURE__ */ i(r.RequiredIndicator, {})] }),
|
|
14
|
+
d,
|
|
15
|
+
/* @__PURE__ */ i(n, {
|
|
16
|
+
display: "flex",
|
|
17
|
+
flexDirection: "column",
|
|
18
|
+
minH: "4",
|
|
19
|
+
children: h.length > 0 ? /* @__PURE__ */ i(r.ErrorText, { children: h.join(" ") }) : c && /* @__PURE__ */ i(r.HelperText, { children: c })
|
|
20
|
+
})
|
|
21
|
+
]
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export { s as FormField };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type InputProps } from "@chakra-ui/react";
|
|
2
|
+
import { type FormFieldProps } from "./FormField";
|
|
3
|
+
export type InputFieldProps = Omit<InputProps, "value" | "onChange" | "onBlur" | "name" | "required"> & Omit<FormFieldProps, "children">;
|
|
4
|
+
/** A text input (or email, password, search: any `type`) for a string field. */
|
|
5
|
+
export declare function InputField({ label, helperText, required, ...props }: InputFieldProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useFieldContext as e } from "../formContext.js";
|
|
2
|
+
import { FormField as t } from "./FormField.js";
|
|
3
|
+
import { Input as n } from "@chakra-ui/react";
|
|
4
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
5
|
+
// src/form/fields/InputField.tsx
|
|
6
|
+
function i({ label: i, helperText: a, required: o, ...s }) {
|
|
7
|
+
let c = e();
|
|
8
|
+
return /* @__PURE__ */ r(t, {
|
|
9
|
+
label: i,
|
|
10
|
+
helperText: a,
|
|
11
|
+
required: o,
|
|
12
|
+
children: /* @__PURE__ */ r(n, {
|
|
13
|
+
name: c.name,
|
|
14
|
+
value: c.state.value,
|
|
15
|
+
onChange: (e) => c.handleChange(e.target.value),
|
|
16
|
+
onBlur: c.handleBlur,
|
|
17
|
+
...s
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export { i as InputField };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type FormFieldProps } from "./FormField";
|
|
2
|
+
export type NumberFieldProps = Omit<FormFieldProps, "children"> & {
|
|
3
|
+
min?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
step?: number;
|
|
6
|
+
};
|
|
7
|
+
/** What the input shows for the field's value: nothing for `undefined`. */
|
|
8
|
+
export declare function numberTextOf(value: number | undefined): string;
|
|
9
|
+
/** A number input; an empty or unreadable entry is `undefined`, never NaN. */
|
|
10
|
+
export declare function NumberField({ label, helperText, required, min, max, step }: NumberFieldProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useFieldContext as e } from "../formContext.js";
|
|
2
|
+
import { FormField as t } from "./FormField.js";
|
|
3
|
+
import { NumberInput as n } from "@chakra-ui/react";
|
|
4
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
5
|
+
// src/form/fields/NumberField.tsx
|
|
6
|
+
function a(e) {
|
|
7
|
+
return e === void 0 ? "" : String(e);
|
|
8
|
+
}
|
|
9
|
+
function o({ label: o, helperText: s, required: c, min: l, max: u, step: d }) {
|
|
10
|
+
let f = e();
|
|
11
|
+
return /* @__PURE__ */ r(t, {
|
|
12
|
+
label: o,
|
|
13
|
+
helperText: s,
|
|
14
|
+
required: c,
|
|
15
|
+
children: /* @__PURE__ */ i(n.Root, {
|
|
16
|
+
name: f.name,
|
|
17
|
+
value: a(f.state.value),
|
|
18
|
+
onValueChange: ({ valueAsNumber: e }) => f.handleChange(Number.isFinite(e) ? e : void 0),
|
|
19
|
+
min: l,
|
|
20
|
+
max: u,
|
|
21
|
+
step: d,
|
|
22
|
+
children: [/* @__PURE__ */ r(n.Control, {}), /* @__PURE__ */ r(n.Input, { onBlur: f.handleBlur })]
|
|
23
|
+
})
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export { o as NumberField, a as numberTextOf };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type FormFieldProps } from "./FormField";
|
|
2
|
+
import type { Option } from "./SelectField";
|
|
3
|
+
export type RadioGroupFieldProps = Omit<FormFieldProps, "children"> & {
|
|
4
|
+
options: readonly Option[];
|
|
5
|
+
orientation?: "horizontal" | "vertical";
|
|
6
|
+
};
|
|
7
|
+
/** One choice of `options` for a string field, as radio buttons. */
|
|
8
|
+
export declare function RadioGroupField({ label, helperText, required, options, orientation, }: RadioGroupFieldProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useFieldContext as e } from "../formContext.js";
|
|
2
|
+
import { FormField as t } from "./FormField.js";
|
|
3
|
+
import { RadioGroup as n, Stack as r } from "@chakra-ui/react";
|
|
4
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
|
+
// src/form/fields/RadioGroupField.tsx
|
|
6
|
+
function o({ label: o, helperText: s, required: c, options: l, orientation: u = "vertical" }) {
|
|
7
|
+
let d = e();
|
|
8
|
+
return /* @__PURE__ */ i(t, {
|
|
9
|
+
label: o,
|
|
10
|
+
helperText: s,
|
|
11
|
+
required: c,
|
|
12
|
+
controlLabelled: !0,
|
|
13
|
+
children: /* @__PURE__ */ a(n.Root, {
|
|
14
|
+
name: d.name,
|
|
15
|
+
value: d.state.value,
|
|
16
|
+
onValueChange: ({ value: e }) => d.handleChange(e),
|
|
17
|
+
onBlur: d.handleBlur,
|
|
18
|
+
children: [/* @__PURE__ */ i(n.Label, { children: o }), /* @__PURE__ */ i(r, {
|
|
19
|
+
direction: u === "vertical" ? "column" : "row",
|
|
20
|
+
gap: "3",
|
|
21
|
+
children: l.map((e) => /* @__PURE__ */ a(n.Item, {
|
|
22
|
+
value: e.value,
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ i(n.ItemHiddenInput, {}),
|
|
25
|
+
/* @__PURE__ */ i(n.ItemIndicator, {}),
|
|
26
|
+
/* @__PURE__ */ i(n.ItemText, { children: e.label })
|
|
27
|
+
]
|
|
28
|
+
}, e.value))
|
|
29
|
+
})]
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export { o as RadioGroupField };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type FormFieldProps } from "./FormField";
|
|
2
|
+
export interface Option {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
export type SelectFieldProps = Omit<FormFieldProps, "children"> & {
|
|
7
|
+
options: readonly Option[];
|
|
8
|
+
/** Shown while nothing is chosen; the field's value is then "". */
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
};
|
|
11
|
+
/** A drop-down of `options` for a string field (the browser's own select: accessible everywhere). */
|
|
12
|
+
export declare function SelectField({ label, helperText, required, options, placeholder }: SelectFieldProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useFieldContext as e } from "../formContext.js";
|
|
2
|
+
import { FormField as t } from "./FormField.js";
|
|
3
|
+
import { NativeSelect as n } from "@chakra-ui/react";
|
|
4
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
5
|
+
// src/form/fields/SelectField.tsx
|
|
6
|
+
function a({ label: a, helperText: o, required: s, options: c, placeholder: l }) {
|
|
7
|
+
let u = e();
|
|
8
|
+
return /* @__PURE__ */ r(t, {
|
|
9
|
+
label: a,
|
|
10
|
+
helperText: o,
|
|
11
|
+
required: s,
|
|
12
|
+
children: /* @__PURE__ */ i(n.Root, { children: [/* @__PURE__ */ r(n.Field, {
|
|
13
|
+
name: u.name,
|
|
14
|
+
value: u.state.value,
|
|
15
|
+
onChange: (e) => u.handleChange(e.target.value),
|
|
16
|
+
onBlur: u.handleBlur,
|
|
17
|
+
placeholder: l,
|
|
18
|
+
children: c.map((e) => /* @__PURE__ */ r("option", {
|
|
19
|
+
value: e.value,
|
|
20
|
+
children: e.label
|
|
21
|
+
}, e.value))
|
|
22
|
+
}), /* @__PURE__ */ r(n.Indicator, {})] })
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export { a as SelectField };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type TextareaProps } from "@chakra-ui/react";
|
|
2
|
+
import { type FormFieldProps } from "./FormField";
|
|
3
|
+
export type TextAreaFieldProps = Omit<TextareaProps, "value" | "onChange" | "onBlur" | "name" | "required"> & Omit<FormFieldProps, "children">;
|
|
4
|
+
/** A multi-line text input for a string field. */
|
|
5
|
+
export declare function TextAreaField({ label, helperText, required, ...props }: TextAreaFieldProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useFieldContext as e } from "../formContext.js";
|
|
2
|
+
import { FormField as t } from "./FormField.js";
|
|
3
|
+
import { Textarea as n } from "@chakra-ui/react";
|
|
4
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
5
|
+
// src/form/fields/TextAreaField.tsx
|
|
6
|
+
function i({ label: i, helperText: a, required: o, ...s }) {
|
|
7
|
+
let c = e();
|
|
8
|
+
return /* @__PURE__ */ r(t, {
|
|
9
|
+
label: i,
|
|
10
|
+
helperText: a,
|
|
11
|
+
required: o,
|
|
12
|
+
children: /* @__PURE__ */ r(n, {
|
|
13
|
+
name: c.name,
|
|
14
|
+
value: c.state.value,
|
|
15
|
+
onChange: (e) => c.handleChange(e.target.value),
|
|
16
|
+
onBlur: c.handleBlur,
|
|
17
|
+
...s
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export { i as TextAreaField };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ButtonProps } from "@chakra-ui/react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* The `<form>`, submitting through the form once: a submit button inside it (or Enter in a field)
|
|
5
|
+
* submits, and nothing else calls `handleSubmit`. The browser's own validation is off; the form's
|
|
6
|
+
* validators speak for it, in the app's words.
|
|
7
|
+
*/
|
|
8
|
+
export declare function Form({ children }: {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
/** Submits the form; busy and disabled while it submits, so a second click sends nothing. */
|
|
12
|
+
export declare function SubmitButton({ children, ...props }: Omit<ButtonProps, "type" | "onClick">): import("react").JSX.Element;
|
|
13
|
+
/** Puts every field back to its default value. */
|
|
14
|
+
export declare function ResetButton({ children, ...props }: Omit<ButtonProps, "type" | "onClick">): import("react").JSX.Element;
|
|
15
|
+
/** "Saving…" (or `children`), announced, while the form submits. */
|
|
16
|
+
export declare function SubmittingIndicator({ children }: {
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useFormContext as e } from "../formContext.js";
|
|
2
|
+
import { Button as t, HStack as n, Spinner as r, Text as i } from "@chakra-ui/react";
|
|
3
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
4
|
+
import { useStore as s } from "@tanstack/react-form";
|
|
5
|
+
// src/form/fields/formComponents.tsx
|
|
6
|
+
function c({ children: t }) {
|
|
7
|
+
let n = e();
|
|
8
|
+
return /* @__PURE__ */ a("form", {
|
|
9
|
+
noValidate: !0,
|
|
10
|
+
onSubmit: (e) => {
|
|
11
|
+
e.preventDefault(), e.stopPropagation(), n.validateAllFields("submit").then(() => n.handleSubmit());
|
|
12
|
+
},
|
|
13
|
+
children: t
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function l({ children: n, ...r }) {
|
|
17
|
+
let i = e(), o = s(i.store, (e) => e.isSubmitting);
|
|
18
|
+
return /* @__PURE__ */ a(t, {
|
|
19
|
+
type: "submit",
|
|
20
|
+
loading: o,
|
|
21
|
+
loadingText: n,
|
|
22
|
+
disabled: o,
|
|
23
|
+
alignSelf: "start",
|
|
24
|
+
...r,
|
|
25
|
+
children: n
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function u({ children: n = "Reset", ...r }) {
|
|
29
|
+
let i = e();
|
|
30
|
+
return /* @__PURE__ */ a(t, {
|
|
31
|
+
type: "button",
|
|
32
|
+
variant: "outline",
|
|
33
|
+
onClick: () => i.reset(),
|
|
34
|
+
...r,
|
|
35
|
+
children: n
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function d({ children: t = "Saving…" }) {
|
|
39
|
+
let c = e();
|
|
40
|
+
return s(c.store, (e) => e.isSubmitting) ? /* @__PURE__ */ o(n, {
|
|
41
|
+
role: "status",
|
|
42
|
+
gap: "2",
|
|
43
|
+
color: "fg.muted",
|
|
44
|
+
children: [/* @__PURE__ */ a(r, { size: "sm" }), /* @__PURE__ */ a(i, {
|
|
45
|
+
fontSize: "sm",
|
|
46
|
+
children: t
|
|
47
|
+
})]
|
|
48
|
+
}) : null;
|
|
49
|
+
}
|
|
50
|
+
export { c as Form, u as ResetButton, l as SubmitButton, d as SubmittingIndicator };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type AnyFormApi } from "@tanstack/react-form";
|
|
2
|
+
import { CheckboxField } from "./fields/CheckboxField";
|
|
3
|
+
import { Form, ResetButton, SubmitButton, SubmittingIndicator } from "./fields/formComponents";
|
|
4
|
+
import { InputField } from "./fields/InputField";
|
|
5
|
+
import { NumberField } from "./fields/NumberField";
|
|
6
|
+
import { RadioGroupField } from "./fields/RadioGroupField";
|
|
7
|
+
import { SelectField } from "./fields/SelectField";
|
|
8
|
+
import { TextAreaField } from "./fields/TextAreaField";
|
|
9
|
+
/**
|
|
10
|
+
* The app's forms: TanStack Form with Chakra fields.
|
|
11
|
+
*
|
|
12
|
+
* const form = useAppForm({ defaultValues: { name: "" }, onSubmit: async ({ value }) => ... });
|
|
13
|
+
* <form.AppForm>
|
|
14
|
+
* <form.Form>
|
|
15
|
+
* <form.AppField name="name" validators={{ onBlur: ({ value }) => (value.trim() ? undefined : "Enter a name") }}>
|
|
16
|
+
* {(field) => <field.InputField label="Name" required />}
|
|
17
|
+
* </form.AppField>
|
|
18
|
+
* <form.SubmitButton>Save</form.SubmitButton>
|
|
19
|
+
* </form.Form>
|
|
20
|
+
* </form.AppForm>
|
|
21
|
+
*/
|
|
22
|
+
export declare const useAppForm: <TFormData, TOnMount extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnChange extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnChangeAsync extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TOnBlur extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnBlurAsync extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TOnSubmit extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnSubmitAsync extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TOnDynamic extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnDynamicAsync extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TOnServer extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TSubmitMeta>(props: import("@tanstack/form-core").FormOptions<TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta>) => import("@tanstack/react-form").AppFieldExtendedReactFormApi<TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta, {
|
|
23
|
+
readonly CheckboxField: typeof CheckboxField;
|
|
24
|
+
readonly InputField: typeof InputField;
|
|
25
|
+
readonly NumberField: typeof NumberField;
|
|
26
|
+
readonly TextAreaField: typeof TextAreaField;
|
|
27
|
+
readonly SelectField: typeof SelectField;
|
|
28
|
+
readonly RadioGroupField: typeof RadioGroupField;
|
|
29
|
+
}, {
|
|
30
|
+
readonly Form: typeof Form;
|
|
31
|
+
readonly SubmitButton: typeof SubmitButton;
|
|
32
|
+
readonly ResetButton: typeof ResetButton;
|
|
33
|
+
readonly SubmittingIndicator: typeof SubmittingIndicator;
|
|
34
|
+
}>, withForm: <TFormData, TOnMount extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnChange extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnChangeAsync extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TOnBlur extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnBlurAsync extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TOnSubmit extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnSubmitAsync extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TOnDynamic extends undefined | import("@tanstack/form-core").FormValidateOrFn<TFormData>, TOnDynamicAsync extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TOnServer extends undefined | import("@tanstack/form-core").FormAsyncValidateOrFn<TFormData>, TSubmitMeta, TRenderProps extends object = {}>({ render, props, }: import("@tanstack/react-form").WithFormProps<TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta, {
|
|
35
|
+
readonly CheckboxField: typeof CheckboxField;
|
|
36
|
+
readonly InputField: typeof InputField;
|
|
37
|
+
readonly NumberField: typeof NumberField;
|
|
38
|
+
readonly TextAreaField: typeof TextAreaField;
|
|
39
|
+
readonly SelectField: typeof SelectField;
|
|
40
|
+
readonly RadioGroupField: typeof RadioGroupField;
|
|
41
|
+
}, {
|
|
42
|
+
readonly Form: typeof Form;
|
|
43
|
+
readonly SubmitButton: typeof SubmitButton;
|
|
44
|
+
readonly ResetButton: typeof ResetButton;
|
|
45
|
+
readonly SubmittingIndicator: typeof SubmittingIndicator;
|
|
46
|
+
}, TRenderProps>) => import("react").FunctionComponent<import("react").PropsWithChildren<NoInfer<[unknown] extends [TRenderProps] ? any : TRenderProps> & {
|
|
47
|
+
form: import("@tanstack/react-form").AppFieldExtendedReactFormApi<[unknown] extends [TFormData] ? any : TFormData, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnMount] ? [TOnMount] extends [TOnMount & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnMount : TOnMount, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnChange] ? [TOnChange] extends [TOnChange & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnChange : TOnChange, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnChangeAsync] ? [TOnChangeAsync] extends [TOnChangeAsync & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnChangeAsync : TOnChangeAsync, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnBlur] ? [TOnBlur] extends [TOnBlur & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnBlur : TOnBlur, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnBlurAsync] ? [TOnBlurAsync] extends [TOnBlurAsync & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnBlurAsync : TOnBlurAsync, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnSubmit] ? [TOnSubmit] extends [TOnSubmit & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnSubmit : TOnSubmit, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnSubmitAsync] ? [TOnSubmitAsync] extends [TOnSubmitAsync & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnSubmitAsync : TOnSubmitAsync, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnDynamic] ? [TOnDynamic] extends [TOnDynamic & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnDynamic : TOnDynamic, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnDynamicAsync] ? [TOnDynamicAsync] extends [TOnDynamicAsync & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnDynamicAsync : TOnDynamicAsync, [import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined] extends [TOnServer] ? [TOnServer] extends [TOnServer & (import("@tanstack/form-core").FormValidateOrFn<TFormData> | undefined)] ? any : TOnServer : TOnServer, [unknown] extends [TSubmitMeta] ? any : TSubmitMeta, {
|
|
48
|
+
readonly CheckboxField: typeof CheckboxField;
|
|
49
|
+
readonly InputField: typeof InputField;
|
|
50
|
+
readonly NumberField: typeof NumberField;
|
|
51
|
+
readonly TextAreaField: typeof TextAreaField;
|
|
52
|
+
readonly SelectField: typeof SelectField;
|
|
53
|
+
readonly RadioGroupField: typeof RadioGroupField;
|
|
54
|
+
}, {
|
|
55
|
+
readonly Form: typeof Form;
|
|
56
|
+
readonly SubmitButton: typeof SubmitButton;
|
|
57
|
+
readonly ResetButton: typeof ResetButton;
|
|
58
|
+
readonly SubmittingIndicator: typeof SubmittingIndicator;
|
|
59
|
+
}>;
|
|
60
|
+
}>>;
|
|
61
|
+
/**
|
|
62
|
+
* Shows the server's messages from a 400 under their fields (see `fieldErrorsOf`); each clears
|
|
63
|
+
* when its field is edited. Returns the messages for fields the form does not have, to show
|
|
64
|
+
* elsewhere.
|
|
65
|
+
*/
|
|
66
|
+
export declare function showServerErrors(form: AnyFormApi, fields: Record<string, string>): string[];
|
|
67
|
+
/**
|
|
68
|
+
* Tells the user why the server refused a form: each field error goes under its field (a server
|
|
69
|
+
* field can be named to a form field with `fieldNames`, such as `{ rule: "days" }`), messages with
|
|
70
|
+
* no field to go under are toasted under `fallback`, and a refusal without field errors toasts the
|
|
71
|
+
* server's reason, or `fallback` when it gave none.
|
|
72
|
+
*/
|
|
73
|
+
export declare function showProblem(form: AnyFormApi, response: Response, fallback: string, fieldNames?: Record<string, string>): Promise<void>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { CheckboxField as e } from "./fields/CheckboxField.js";
|
|
2
|
+
import { Form as t, ResetButton as n, SubmitButton as r, SubmittingIndicator as i } from "./fields/formComponents.js";
|
|
3
|
+
import { InputField as a } from "./fields/InputField.js";
|
|
4
|
+
import { NumberField as o } from "./fields/NumberField.js";
|
|
5
|
+
import { RadioGroupField as s } from "./fields/RadioGroupField.js";
|
|
6
|
+
import { SelectField as c } from "./fields/SelectField.js";
|
|
7
|
+
import { TextAreaField as l } from "./fields/TextAreaField.js";
|
|
8
|
+
import { fieldContext as u, formContext as d } from "./formContext.js";
|
|
9
|
+
import { fieldErrorsOf as f } from "./errors.js";
|
|
10
|
+
import { notify as p } from "../feedback/notify.js";
|
|
11
|
+
import { problemOf as m } from "../problem/problem.js";
|
|
12
|
+
import { createFormHook as h } from "@tanstack/react-form";
|
|
13
|
+
// src/form/form.tsx
|
|
14
|
+
var { useAppForm: g, withForm: _ } = h({
|
|
15
|
+
fieldContext: u,
|
|
16
|
+
formContext: d,
|
|
17
|
+
fieldComponents: {
|
|
18
|
+
CheckboxField: e,
|
|
19
|
+
InputField: a,
|
|
20
|
+
NumberField: o,
|
|
21
|
+
TextAreaField: l,
|
|
22
|
+
SelectField: c,
|
|
23
|
+
RadioGroupField: s
|
|
24
|
+
},
|
|
25
|
+
formComponents: {
|
|
26
|
+
Form: t,
|
|
27
|
+
SubmitButton: r,
|
|
28
|
+
ResetButton: n,
|
|
29
|
+
SubmittingIndicator: i
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
function v(e, t) {
|
|
33
|
+
let n = [];
|
|
34
|
+
for (let [r, i] of Object.entries(t)) r in e.fieldInfo ? e.setFieldMeta(r, (e) => ({
|
|
35
|
+
...e,
|
|
36
|
+
errorMap: {
|
|
37
|
+
...e.errorMap,
|
|
38
|
+
onServer: i
|
|
39
|
+
}
|
|
40
|
+
})) : n.push(i);
|
|
41
|
+
return n;
|
|
42
|
+
}
|
|
43
|
+
async function y(e, t, n, r = {}) {
|
|
44
|
+
let i = await m(t);
|
|
45
|
+
if (i.errors === void 0) {
|
|
46
|
+
p.problem(i, n);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
let a = {};
|
|
50
|
+
for (let [e, t] of Object.entries(f(i))) a[r[e] ?? e] = t;
|
|
51
|
+
let o = v(e, a);
|
|
52
|
+
o.length > 0 && p.error(n, o.join(" "));
|
|
53
|
+
}
|
|
54
|
+
export { y as showProblem, v as showServerErrors, g as useAppForm, _ as withForm };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** The contexts the field and form components read; see form.tsx. */
|
|
2
|
+
export declare const fieldContext: import("react").Context<import("@tanstack/form-core").AnyFieldApi>, useFieldContext: <TData>() => import("@tanstack/form-core").FieldApi<any, string, TData, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any>, formContext: import("react").Context<import("@tanstack/form-core").AnyFormApi>, useFormContext: () => import("@tanstack/react-form").ReactFormExtendedApi<Record<string, never>, any, any, any, any, any, any, any, any, any, any, any>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { createFormHookContexts as e } from "@tanstack/react-form";
|
|
2
|
+
// src/form/formContext.ts
|
|
3
|
+
var { fieldContext: t, useFieldContext: n, formContext: r, useFormContext: i } = e();
|
|
4
|
+
export { t as fieldContext, r as formContext, n as useFieldContext, i as useFormContext };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { errorMessages, fieldErrorsOf } from "./errors";
|
|
2
|
+
export { showProblem, showServerErrors, useAppForm, withForm } from "./form";
|
|
3
|
+
export { fieldContext, formContext, useFieldContext, useFormContext } from "./formContext";
|
|
4
|
+
export { FormDialog, type FormDialogProps } from "./FormDialog";
|
|
5
|
+
export { dateTimeInputOf, inputOf, instantOrNull, numberInputOf, numberOrNull, textOrNull } from "./values";
|
|
6
|
+
export { CheckboxField, type CheckboxFieldProps } from "./fields/CheckboxField";
|
|
7
|
+
export { Form, ResetButton, SubmitButton, SubmittingIndicator } from "./fields/formComponents";
|
|
8
|
+
export { FormField, type FormFieldProps } from "./fields/FormField";
|
|
9
|
+
export { InputField, type InputFieldProps } from "./fields/InputField";
|
|
10
|
+
export { NumberField, type NumberFieldProps } from "./fields/NumberField";
|
|
11
|
+
export { RadioGroupField, type RadioGroupFieldProps } from "./fields/RadioGroupField";
|
|
12
|
+
export { SelectField, type Option, type SelectFieldProps } from "./fields/SelectField";
|
|
13
|
+
export { TextAreaField, type TextAreaFieldProps } from "./fields/TextAreaField";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { errorMessages as e, fieldErrorsOf as t } from "./errors.js";
|
|
2
|
+
import { showProblem as n, showServerErrors as r, useAppForm as i, withForm as a } from "./form.js";
|
|
3
|
+
import { fieldContext as o, formContext as s, useFieldContext as c, useFormContext as l } from "./formContext.js";
|
|
4
|
+
import { FormDialog as u } from "./FormDialog.js";
|
|
5
|
+
import { dateTimeInputOf as d, inputOf as f, instantOrNull as p, numberInputOf as m, numberOrNull as h, textOrNull as g } from "./values.js";
|
|
6
|
+
import { CheckboxField as _ } from "./fields/CheckboxField.js";
|
|
7
|
+
import { Form as v, ResetButton as y, SubmitButton as b, SubmittingIndicator as x } from "./fields/formComponents.js";
|
|
8
|
+
import { FormField as S } from "./fields/FormField.js";
|
|
9
|
+
import { InputField as C } from "./fields/InputField.js";
|
|
10
|
+
import { NumberField as w } from "./fields/NumberField.js";
|
|
11
|
+
import { RadioGroupField as T } from "./fields/RadioGroupField.js";
|
|
12
|
+
import { SelectField as E } from "./fields/SelectField.js";
|
|
13
|
+
import { TextAreaField as D } from "./fields/TextAreaField.js";
|
|
14
|
+
export { _ as CheckboxField, v as Form, u as FormDialog, S as FormField, C as InputField, w as NumberField, T as RadioGroupField, y as ResetButton, E as SelectField, b as SubmitButton, x as SubmittingIndicator, D as TextAreaField, d as dateTimeInputOf, e as errorMessages, o as fieldContext, t as fieldErrorsOf, s as formContext, f as inputOf, p as instantOrNull, m as numberInputOf, h as numberOrNull, n as showProblem, r as showServerErrors, g as textOrNull, i as useAppForm, c as useFieldContext, l as useFormContext, a as withForm };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form values to and from a record's. Inputs hold strings (and NumberField `number | undefined`);
|
|
3
|
+
* the API takes `null` for an empty optional field, never `""`.
|
|
4
|
+
*/
|
|
5
|
+
/** Trimmed text, or null when blank. */
|
|
6
|
+
export declare function textOrNull(value: string): string | null;
|
|
7
|
+
/** A number input's value, or null when empty. */
|
|
8
|
+
export declare function numberOrNull(value: number | undefined): number | null;
|
|
9
|
+
/** A record's number as a number input's value. */
|
|
10
|
+
export declare function numberInputOf(value: number | null): number | undefined;
|
|
11
|
+
/** A record's text as an input's value. */
|
|
12
|
+
export declare function inputOf(value: string | null): string;
|
|
13
|
+
/** An ISO instant as a `datetime-local` input's value, in the browser's time zone. */
|
|
14
|
+
export declare function dateTimeInputOf(iso: string | null): string;
|
|
15
|
+
/**
|
|
16
|
+
* A `datetime-local` input's value (the browser's time zone) as an ISO instant, or null. The input
|
|
17
|
+
* shows minutes only, so an input that still shows `original` gives `original` back whole: saving a
|
|
18
|
+
* form must not drop the seconds of an instant nobody changed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function instantOrNull(local: string, original?: string | null): string | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/form/values.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
let t = e.trim();
|
|
4
|
+
return t === "" ? null : t;
|
|
5
|
+
}
|
|
6
|
+
function t(e) {
|
|
7
|
+
return e ?? null;
|
|
8
|
+
}
|
|
9
|
+
function n(e) {
|
|
10
|
+
return e ?? void 0;
|
|
11
|
+
}
|
|
12
|
+
function r(e) {
|
|
13
|
+
return e ?? "";
|
|
14
|
+
}
|
|
15
|
+
var i = (e) => String(e).padStart(2, "0");
|
|
16
|
+
function a(e) {
|
|
17
|
+
if (e === null) return "";
|
|
18
|
+
let t = new Date(e);
|
|
19
|
+
return `${t.getFullYear()}-${i(t.getMonth() + 1)}-${i(t.getDate())}T${i(t.getHours())}:${i(t.getMinutes())}`;
|
|
20
|
+
}
|
|
21
|
+
function o(e, t = null) {
|
|
22
|
+
return e === a(t) ? t : e === "" ? null : new Date(e).toISOString();
|
|
23
|
+
}
|
|
24
|
+
export { a as dateTimeInputOf, r as inputOf, o as instantOrNull, n as numberInputOf, t as numberOrNull, e as textOrNull };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { enumSearchOf, fetchAllPages, MAX_PAGE_SIZE, MAX_PAGES, nextPageIndex, pageParamsOf, pageQuery, rowRange, searchTermOf, tableSearchOf, type PageDto, type PageParams, type PaginationDto, type SortDirection, type TableSearch, } from "./paging";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MAX_PAGES, MAX_PAGE_SIZE, enumSearchOf, fetchAllPages, nextPageIndex, pageParamsOf, pageQuery, rowRange, searchTermOf, tableSearchOf } from "./paging.js";
|