@zeroman.yang/react-auto-components 0.1.1 → 0.1.3
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/README.md +17 -3
- package/dist/adapters/xlsx.d.ts +7 -1
- package/dist/components/AutoChat/types.d.ts +7 -0
- package/dist/components/AutoDialog/index.d.ts +15 -0
- package/dist/components/AutoForm/types.d.ts +28 -0
- package/dist/components/AutoMenu/index.d.ts +7 -0
- package/dist/components/AutoSearch/index.d.ts +40 -0
- package/dist/components/AutoTable/registry.d.ts +8 -0
- package/dist/components/AutoTable/types.d.ts +69 -3
- package/dist/components/AutoTabs/index.d.ts +21 -2
- package/dist/components/AutoTabs/useAutoTabsWorkspace.d.ts +65 -0
- package/dist/core/AutoConfigProvider.d.ts +27 -0
- package/dist/core/config.d.ts +6 -1
- package/dist/core/dev.d.ts +27 -0
- package/dist/core/errors.d.ts +20 -0
- package/dist/core/query.d.ts +9 -0
- package/dist/core/registry.d.ts +33 -0
- package/dist/core/testid.d.ts +5 -0
- package/dist/core/types.d.ts +320 -17
- package/dist/errors-BT5WUIOV.js +28 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1889 -1465
- package/dist/style.css +1 -1
- package/dist/xlsx.js +13 -6
- package/docs/auto-dialog.md +64 -0
- package/docs/auto-form.md +64 -0
- package/docs/auto-menu.md +47 -0
- package/docs/auto-search.md +60 -0
- package/docs/auto-table.md +144 -0
- package/docs/auto-tabs.md +99 -0
- package/docs/errors.md +118 -0
- package/docs/i18n/de/README.md +8 -2
- package/docs/i18n/de/auto-dialog.md +23 -0
- package/docs/i18n/de/auto-form.md +35 -0
- package/docs/i18n/de/auto-menu.md +23 -0
- package/docs/i18n/de/auto-search.md +32 -0
- package/docs/i18n/de/auto-table.md +31 -0
- package/docs/i18n/de/auto-tabs.md +25 -0
- package/docs/i18n/de/errors.md +110 -0
- package/docs/i18n/es/README.md +8 -2
- package/docs/i18n/es/auto-dialog.md +23 -0
- package/docs/i18n/es/auto-form.md +35 -0
- package/docs/i18n/es/auto-menu.md +23 -0
- package/docs/i18n/es/auto-search.md +32 -0
- package/docs/i18n/es/auto-table.md +31 -0
- package/docs/i18n/es/auto-tabs.md +25 -0
- package/docs/i18n/es/errors.md +110 -0
- package/docs/i18n/fr/README.md +8 -2
- package/docs/i18n/fr/auto-dialog.md +23 -0
- package/docs/i18n/fr/auto-form.md +35 -0
- package/docs/i18n/fr/auto-menu.md +23 -0
- package/docs/i18n/fr/auto-search.md +32 -0
- package/docs/i18n/fr/auto-table.md +31 -0
- package/docs/i18n/fr/auto-tabs.md +25 -0
- package/docs/i18n/fr/errors.md +110 -0
- package/docs/i18n/ja/README.md +8 -2
- package/docs/i18n/ja/auto-dialog.md +23 -0
- package/docs/i18n/ja/auto-form.md +36 -0
- package/docs/i18n/ja/auto-menu.md +23 -0
- package/docs/i18n/ja/auto-search.md +34 -0
- package/docs/i18n/ja/auto-table.md +31 -0
- package/docs/i18n/ja/auto-tabs.md +25 -0
- package/docs/i18n/ja/errors.md +110 -0
- package/docs/i18n/ko/README.md +8 -2
- package/docs/i18n/ko/auto-dialog.md +23 -0
- package/docs/i18n/ko/auto-form.md +35 -0
- package/docs/i18n/ko/auto-menu.md +23 -0
- package/docs/i18n/ko/auto-search.md +32 -0
- package/docs/i18n/ko/auto-table.md +31 -0
- package/docs/i18n/ko/auto-tabs.md +25 -0
- package/docs/i18n/ko/errors.md +110 -0
- package/docs/i18n/pt-BR/README.md +8 -2
- package/docs/i18n/pt-BR/auto-dialog.md +23 -0
- package/docs/i18n/pt-BR/auto-form.md +35 -0
- package/docs/i18n/pt-BR/auto-menu.md +23 -0
- package/docs/i18n/pt-BR/auto-search.md +32 -0
- package/docs/i18n/pt-BR/auto-table.md +31 -0
- package/docs/i18n/pt-BR/auto-tabs.md +25 -0
- package/docs/i18n/pt-BR/errors.md +110 -0
- package/docs/i18n/ru/README.md +8 -2
- package/docs/i18n/ru/auto-dialog.md +23 -0
- package/docs/i18n/ru/auto-form.md +35 -0
- package/docs/i18n/ru/auto-menu.md +23 -0
- package/docs/i18n/ru/auto-search.md +32 -0
- package/docs/i18n/ru/auto-table.md +31 -0
- package/docs/i18n/ru/auto-tabs.md +25 -0
- package/docs/i18n/ru/errors.md +110 -0
- package/docs/i18n/zh-CN/README.md +8 -2
- package/docs/i18n/zh-CN/auto-dialog.md +64 -0
- package/docs/i18n/zh-CN/auto-form.md +62 -0
- package/docs/i18n/zh-CN/auto-menu.md +47 -0
- package/docs/i18n/zh-CN/auto-search.md +55 -0
- package/docs/i18n/zh-CN/auto-table.md +62 -0
- package/docs/i18n/zh-CN/auto-tabs.md +99 -0
- package/docs/i18n/zh-CN/errors.md +112 -0
- package/docs/i18n/zh-TW/README.md +8 -2
- package/docs/i18n/zh-TW/auto-dialog.md +64 -0
- package/docs/i18n/zh-TW/auto-form.md +62 -0
- package/docs/i18n/zh-TW/auto-menu.md +47 -0
- package/docs/i18n/zh-TW/auto-search.md +55 -0
- package/docs/i18n/zh-TW/auto-table.md +62 -0
- package/docs/i18n/zh-TW/auto-tabs.md +44 -0
- package/docs/i18n/zh-TW/errors.md +112 -0
- package/llms.txt +69 -0
- package/package.json +18 -2
- package/dist/components/AutoSearchPanel/index.d.ts +0 -21
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { QueryNode } from "./query";
|
|
3
|
+
/**
|
|
4
|
+
* Functions for a column `component` key. A function set on the column wins.
|
|
5
|
+
* `row` is the row object the host registered this renderer for.
|
|
6
|
+
*/
|
|
7
|
+
export interface ColumnRegistry {
|
|
8
|
+
render?: (value: unknown, row: object, index: number) => ReactNode;
|
|
9
|
+
format?: (value: unknown, row: object) => string | number;
|
|
10
|
+
sort?: (a: object, b: object) => number;
|
|
11
|
+
exportFormat?: (row: object) => unknown;
|
|
12
|
+
}
|
|
13
|
+
/** Query passed to a registered table source. Same shape as `TableQuery`. */
|
|
14
|
+
export interface SourceQuery {
|
|
15
|
+
pageIndex: number;
|
|
16
|
+
pageSize: number;
|
|
17
|
+
sort: {
|
|
18
|
+
id: string;
|
|
19
|
+
desc: boolean;
|
|
20
|
+
}[];
|
|
21
|
+
filter: QueryNode;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Remote page loader registered on `config.sources`.
|
|
25
|
+
* Resolve `{ rows, total }`. `total` is the full filtered count.
|
|
26
|
+
* Reject to show `error.message` and a retry button.
|
|
27
|
+
*/
|
|
28
|
+
export type SourceLoader = (query: SourceQuery, context: {
|
|
29
|
+
signal: AbortSignal;
|
|
30
|
+
}) => Promise<{
|
|
31
|
+
rows: object[];
|
|
32
|
+
total: number;
|
|
33
|
+
}>;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,40 +1,348 @@
|
|
|
1
1
|
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
/** Loose record used by custom field renderers registered on the provider. */
|
|
2
3
|
export type Values = Record<string, unknown>;
|
|
4
|
+
/**
|
|
5
|
+
* Control height token.
|
|
6
|
+
* Default `"medium"` comes from `AutoConfigProvider` (`config.size`).
|
|
7
|
+
*/
|
|
3
8
|
export type ComponentSize = "small" | "medium" | "large";
|
|
9
|
+
/**
|
|
10
|
+
* Vertical spacing token for forms, menus, tabs, and chat.
|
|
11
|
+
* Default `"comfortable"`. Tables use {@link TableDensity} instead.
|
|
12
|
+
*/
|
|
4
13
|
export type ComponentDensity = "comfortable" | "compact";
|
|
14
|
+
/**
|
|
15
|
+
* Table row spacing. `"normal"` is the table default when no provider density is set.
|
|
16
|
+
* A provider `density: "compact"` maps to table `"compact"`; `"comfortable"` maps to `"normal"`.
|
|
17
|
+
*/
|
|
5
18
|
export type TableDensity = "compact" | "normal" | "comfortable";
|
|
19
|
+
/**
|
|
20
|
+
* Label layout shared by `AutoForm` and `AutoSearch`.
|
|
21
|
+
* Defaults: `labelPosition` `"top"`, `labelWidth` `"auto"` (measured, capped at 45% of the field).
|
|
22
|
+
*/
|
|
6
23
|
export interface AutoFormLayout {
|
|
24
|
+
/** `"top"` stacks the label. `"left"` puts it beside the control. Default `"top"`. */
|
|
7
25
|
labelPosition?: "top" | "left";
|
|
26
|
+
/** Used when `labelPosition` is `"left"`. Default `"right"` for left labels, otherwise `"left"`. */
|
|
8
27
|
labelAlign?: "left" | "right";
|
|
28
|
+
/**
|
|
29
|
+
* Left-label column width. `"auto"` measures the longest label.
|
|
30
|
+
* A number is pixels. A string is any CSS width (`"8rem"`).
|
|
31
|
+
*/
|
|
9
32
|
labelWidth?: CSSProperties["width"];
|
|
10
33
|
density?: ComponentDensity;
|
|
11
34
|
size?: ComponentSize;
|
|
12
35
|
}
|
|
36
|
+
/** String keys of the value object. Symbols and numbers are not field names. */
|
|
13
37
|
export type FieldName<T> = Extract<keyof T, string>;
|
|
38
|
+
/**
|
|
39
|
+
* A static value, or a function of the current form values.
|
|
40
|
+
* Functions run during render. Keep them pure.
|
|
41
|
+
*/
|
|
14
42
|
export type Dynamic<V, T> = V | ((values: Readonly<T>) => V);
|
|
43
|
+
/**
|
|
44
|
+
* Hide or disable a field, column, tab, or menu item.
|
|
45
|
+
* Both lists are AND-ed: every listed role and permission must pass `canAccess`.
|
|
46
|
+
* Default `canAccess` returns true for everything.
|
|
47
|
+
*/
|
|
15
48
|
export interface Access {
|
|
49
|
+
/** Visible when the user has every role. Omit to skip the role check. */
|
|
16
50
|
roles?: readonly string[];
|
|
51
|
+
/** Visible when the user has every permission. Omit to skip the permission check. */
|
|
17
52
|
permissions?: readonly string[];
|
|
18
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* One choice. `value` keeps boolean and numeric identity (`false` and `0` are selectable).
|
|
56
|
+
* `children` is only read by `type: "cascader"`.
|
|
57
|
+
*/
|
|
19
58
|
export interface Option {
|
|
20
59
|
value: string | number | boolean;
|
|
21
60
|
label: string;
|
|
22
61
|
disabled?: boolean;
|
|
62
|
+
/** Next cascader column. Ignored by select, radio, and checkbox. */
|
|
23
63
|
children?: readonly Option[];
|
|
24
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Widget id. Omit it and the field renders as a text input.
|
|
67
|
+
* Illegal combinations (`select` without `options`, a scalar on `daterange`) are rejected by {@link Field}.
|
|
68
|
+
*/
|
|
25
69
|
export type FieldType = "input" | "email" | "textarea" | "integer" | "float" | "percentage" | "progress" | "switch" | "select" | "select-v2" | "radio" | "checkbox" | "cascader" | "autocomplete" | "date" | "datetime" | "daterange" | "datetimerange" | "upload" | "text" | "title" | "tip" | "button" | "append" | "custom";
|
|
70
|
+
/** Widgets that render an empty control when `options` is missing. `options` is required. */
|
|
71
|
+
export type ChoiceFieldType = "select" | "select-v2" | "radio" | "checkbox" | "cascader";
|
|
72
|
+
/** Value is a two-item `[start, end]`. A scalar string or number is rejected. */
|
|
73
|
+
export type DateRangeFieldType = "daterange" | "datetimerange";
|
|
74
|
+
/**
|
|
75
|
+
* How a search field compares. Default is `"eq"`, or `"in"` when the value is an array.
|
|
76
|
+
* `"between"` is legal only when the model field is a two-item tuple.
|
|
77
|
+
* `"isNull"` ignores the value and matches null or undefined.
|
|
78
|
+
*/
|
|
79
|
+
export type MatchOperator = "eq" | "in" | "contains" | "between" | "isNull";
|
|
80
|
+
/**
|
|
81
|
+
* Recommended `[from, to]` / `[start, end]` value.
|
|
82
|
+
* A wider array type also passes {@link Field}; a scalar does not.
|
|
83
|
+
* Open ends may be `null`.
|
|
84
|
+
*/
|
|
85
|
+
export type Pair<T = string | number | null> = readonly [T, T];
|
|
86
|
+
/** Props passed to `render` and to renderers registered on `AutoConfigProvider.config.fields`. */
|
|
26
87
|
export interface FieldContext<T extends object> {
|
|
88
|
+
/** DOM id for the control and its `<label htmlFor>`. */
|
|
27
89
|
id: string;
|
|
28
90
|
value: unknown;
|
|
29
91
|
values: Readonly<T>;
|
|
30
92
|
onChange: (value: unknown) => void;
|
|
31
93
|
disabled: boolean;
|
|
94
|
+
/** Present when this field failed validation. Also referenced by `aria-describedby`. */
|
|
32
95
|
error?: string;
|
|
33
96
|
}
|
|
34
|
-
|
|
97
|
+
type RangeOk<V> = 0 extends 1 & V ? true : [unknown] extends [V] ? true : NonNullable<V> extends readonly unknown[] ? true : false;
|
|
98
|
+
/**
|
|
99
|
+
* Props every named field accepts.
|
|
100
|
+
* Type-specific props live on the variant (`options` on choice fields, `rows` on textarea).
|
|
101
|
+
* Putting them on the wrong variant is a TypeScript excess-property error.
|
|
102
|
+
*/
|
|
103
|
+
export interface FieldShared<T extends object, K extends FieldName<T> = FieldName<T>> extends Access {
|
|
104
|
+
/** Key of `T`. Title, tip, append, and button omit it. */
|
|
105
|
+
name: K;
|
|
106
|
+
/**
|
|
107
|
+
* Shown next to the control. Falls back to `name`.
|
|
108
|
+
* When `lang` is set, `config.t(lang, label)` is used instead.
|
|
109
|
+
*/
|
|
110
|
+
label?: string;
|
|
111
|
+
/** Message key passed to `config.t`. `label` is the fallback. */
|
|
112
|
+
lang?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Initial value when the form is uncontrolled. Must be `T[name]`.
|
|
115
|
+
* Ignored once `value` is passed. Cloned with `structuredClone`.
|
|
116
|
+
*/
|
|
117
|
+
defaultValue?: T[K];
|
|
118
|
+
/** Hidden fields are not validated and are omitted from the search query. */
|
|
119
|
+
hidden?: Dynamic<boolean, T>;
|
|
120
|
+
/** Disabled fields stay visible but are not validated. */
|
|
121
|
+
disabled?: Dynamic<boolean, T>;
|
|
122
|
+
/**
|
|
123
|
+
* Blocks submit when the value is `undefined`, `null`, `""`, or an empty array.
|
|
124
|
+
* Hidden, disabled, and inaccessible fields are not checked.
|
|
125
|
+
*/
|
|
126
|
+
required?: boolean;
|
|
127
|
+
placeholder?: string;
|
|
128
|
+
/** Grid columns this field spans. Default `1`. Clamped to the form's `columns`. */
|
|
129
|
+
span?: number;
|
|
130
|
+
/** Start on a new row and span the full grid. */
|
|
131
|
+
lineBreak?: boolean;
|
|
132
|
+
style?: CSSProperties;
|
|
133
|
+
className?: string;
|
|
134
|
+
/** Help text under the control. Also the body of `type: "tip"` and `type: "append"`. */
|
|
135
|
+
tip?: ReactNode;
|
|
136
|
+
/**
|
|
137
|
+
* Run after the required check, in order. Return an error string, or throw (the message is shown).
|
|
138
|
+
* A resolve of `undefined` passes. Later rules are skipped after the first failure.
|
|
139
|
+
*/
|
|
140
|
+
rules?: readonly ((value: unknown, values: Readonly<T>) => string | undefined | Promise<string | undefined>)[];
|
|
141
|
+
/**
|
|
142
|
+
* Replace the built-in control. Called instead of `type`.
|
|
143
|
+
* Throwing here escapes the input handler; the previous form value stays.
|
|
144
|
+
*/
|
|
145
|
+
render?: (context: FieldContext<T>) => ReactNode;
|
|
146
|
+
/**
|
|
147
|
+
* Key in `AutoConfigProvider` `config.fields`. Used when `render` is absent.
|
|
148
|
+
* The registered function receives this field's context.
|
|
149
|
+
*/
|
|
150
|
+
component?: string;
|
|
151
|
+
/**
|
|
152
|
+
* After this field changes, return a partial value to patch other fields.
|
|
153
|
+
* Throw to reject the keystroke; the previous value stays.
|
|
154
|
+
*/
|
|
155
|
+
onChange?: (value: unknown, values: T) => Partial<T> | void;
|
|
156
|
+
/**
|
|
157
|
+
* Search comparison. See {@link MatchOperator}.
|
|
158
|
+
* `"between"` requires `T[name]` to be a two-item tuple.
|
|
159
|
+
*/
|
|
160
|
+
match?: MatchOperator;
|
|
161
|
+
/** Case-fold string comparisons. Only affects `"contains"` and `"eq"` style matches. */
|
|
162
|
+
ignoreCase?: boolean;
|
|
163
|
+
/** Also match rows where the field is null or undefined (`OR` with `isNull`). */
|
|
164
|
+
includeNull?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Query these row keys instead of `name`, OR-ed together.
|
|
167
|
+
* Example: one "keyword" input searching `first` and `last`.
|
|
168
|
+
*/
|
|
169
|
+
searchFields?: readonly string[];
|
|
170
|
+
/** Search panels hide this field behind "More" until the user expands them. */
|
|
171
|
+
more?: boolean;
|
|
172
|
+
}
|
|
173
|
+
/** Text input. This is the default when `type` is omitted. `autocomplete` shows `options` as suggestions, not a closed list. */
|
|
174
|
+
export interface InputField<T extends object, K extends FieldName<T> = FieldName<T>> extends FieldShared<T, K> {
|
|
175
|
+
/**
|
|
176
|
+
* `"input"` is a text box. `"email"` uses the email keyboard. `"text"` is read-only.
|
|
177
|
+
* `"autocomplete"` is a text box plus an optional suggestion list.
|
|
178
|
+
*/
|
|
179
|
+
type?: "input" | "email" | "text" | "autocomplete";
|
|
180
|
+
/** Suggestions for `"autocomplete"`. Not required. Other text types ignore this. */
|
|
181
|
+
options?: Dynamic<readonly Option[], T>;
|
|
182
|
+
}
|
|
183
|
+
/** Multi-line text. `rows` defaults to `3`. */
|
|
184
|
+
export interface TextareaField<T extends object, K extends FieldName<T> = FieldName<T>> extends FieldShared<T, K> {
|
|
185
|
+
type: "textarea";
|
|
186
|
+
/** Visible lines. Default `3`. */
|
|
187
|
+
rows?: number;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Numeric control.
|
|
191
|
+
* `"integer"` uses step `1` and stores a number (`undefined` while empty).
|
|
192
|
+
* `"float"` and `"percentage"` store the raw decimal string so `"1."` can be typed.
|
|
193
|
+
* `"progress"` is a read-only meter; `max` defaults to `100`.
|
|
194
|
+
*/
|
|
195
|
+
export interface NumberField<T extends object, K extends FieldName<T> = FieldName<T>> extends FieldShared<T, K> {
|
|
196
|
+
type: "integer" | "float" | "percentage" | "progress";
|
|
197
|
+
min?: number;
|
|
198
|
+
max?: number;
|
|
199
|
+
/** Default `1` for `"integer"`. Floats have no default step. */
|
|
200
|
+
step?: number;
|
|
201
|
+
}
|
|
202
|
+
/** Boolean checkbox with `role="switch"`. The stored value is `true` or `false`. */
|
|
203
|
+
export interface SwitchField<T extends object, K extends FieldName<T> = FieldName<T>> extends FieldShared<T, K> {
|
|
204
|
+
type: "switch";
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Closed set of options. `options` is required at compile time.
|
|
208
|
+
* `"checkbox"` stores an array and keeps `false` as a real value.
|
|
209
|
+
* `"cascader"` stores the path array and reads `Option.children`.
|
|
210
|
+
* `"select-v2"` virtualizes long lists. `"multiple"` applies to `"select"` and `"select-v2"`.
|
|
211
|
+
*/
|
|
212
|
+
export interface ChoiceField<T extends object, K extends FieldName<T> = FieldName<T>> extends FieldShared<T, K> {
|
|
213
|
+
type: ChoiceFieldType;
|
|
214
|
+
/** Static list, or a function of the other values. An empty list renders no choices. */
|
|
215
|
+
options: Dynamic<readonly Option[], T>;
|
|
216
|
+
/** `"select"` / `"select-v2"` only. Stores an array of option values. */
|
|
217
|
+
multiple?: boolean;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* One calendar value.
|
|
221
|
+
* `dateValue: "string"` (default) stores `YYYY-MM-DD` or `YYYY-MM-DDTHH:mm`.
|
|
222
|
+
* `dateValue: "timestamp"` stores epoch milliseconds in local time.
|
|
223
|
+
*/
|
|
224
|
+
export interface DateField<T extends object, K extends FieldName<T> = FieldName<T>> extends FieldShared<T, K> {
|
|
225
|
+
type: "date" | "datetime";
|
|
226
|
+
/** Default `"string"`. */
|
|
227
|
+
dateValue?: "string" | "timestamp";
|
|
228
|
+
/** Buttons that call `onChange` with `value()`. Return the same shape as the field value. */
|
|
229
|
+
shortcuts?: readonly {
|
|
230
|
+
label: string;
|
|
231
|
+
value: () => unknown;
|
|
232
|
+
}[];
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Two calendar values, `[start, end]`.
|
|
236
|
+
* The model field must be a two-item tuple (`Pair` or `[string, string]`). A scalar is a type error.
|
|
237
|
+
* Same `dateValue` rules as {@link DateField}.
|
|
238
|
+
*/
|
|
239
|
+
export interface DateRangeField<T extends object, K extends FieldName<T> = FieldName<T>> extends FieldShared<T, K> {
|
|
240
|
+
type: DateRangeFieldType;
|
|
241
|
+
dateValue?: "string" | "timestamp";
|
|
242
|
+
shortcuts?: readonly {
|
|
243
|
+
label: string;
|
|
244
|
+
value: () => unknown;
|
|
245
|
+
}[];
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* File input. Without `upload`, the stored value is the `File` list.
|
|
249
|
+
* `upload` runs on change. Rejecting it shows the error under the control and does not store a value.
|
|
250
|
+
* `reset()` aborts the `AbortSignal` and drops a late result.
|
|
251
|
+
*/
|
|
252
|
+
export interface UploadField<T extends object, K extends FieldName<T> = FieldName<T>> extends FieldShared<T, K> {
|
|
253
|
+
type: "upload";
|
|
254
|
+
/** Passed to `<input accept>`. Example: `"image/*"`. */
|
|
255
|
+
accept?: string;
|
|
256
|
+
multiple?: boolean;
|
|
257
|
+
/** Return the value to store. Throw or reject to keep the previous value and show the message. */
|
|
258
|
+
upload?: (files: File[], signal: AbortSignal) => Promise<unknown>;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Your control, via `render` or `component`.
|
|
262
|
+
* Neither is required by the type so a host can attach one later; dev mode warns when both are missing.
|
|
263
|
+
*/
|
|
264
|
+
export interface CustomField<T extends object, K extends FieldName<T> = FieldName<T>> extends FieldShared<T, K> {
|
|
265
|
+
type: "custom";
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Printed when `daterange` is attached to a scalar model field.
|
|
269
|
+
* Assigning a string or number fails against `fix`. Do not construct this type.
|
|
270
|
+
*/
|
|
271
|
+
interface DateRangeMismatch<T extends object, K extends FieldName<T>> extends Omit<DateRangeField<T, K>, "defaultValue"> {
|
|
272
|
+
defaultValue: {
|
|
273
|
+
readonly code: "RAC-FIELD-RANGE";
|
|
274
|
+
readonly fix: "Type this field as a two-item tuple [start, end]. daterange rejects a scalar string or number.";
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Printed when `match: "between"` is attached to a scalar model field.
|
|
279
|
+
* One member, so the error is this fix and not every other widget. Do not construct it.
|
|
280
|
+
*/
|
|
281
|
+
type BetweenError<T extends object, K extends FieldName<T>> = Omit<FieldShared<T, K>, "match"> & {
|
|
282
|
+
match: "between";
|
|
283
|
+
readonly "RAC-FIELD-BETWEEN": {
|
|
284
|
+
readonly code: "RAC-FIELD-BETWEEN";
|
|
285
|
+
readonly fix: "Type this field as a two-item tuple [from, to]. match between rejects a scalar.";
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
type DateRangeFor<T extends object, K extends FieldName<T>> = RangeOk<T[K]> extends true ? DateRangeField<T, K> : DateRangeMismatch<T, K>;
|
|
289
|
+
type FieldVariant<T extends object, K extends FieldName<T>> = InputField<T, K> | TextareaField<T, K> | NumberField<T, K> | SwitchField<T, K> | ChoiceField<T, K> | DateField<T, K> | DateRangeFor<T, K> | UploadField<T, K> | CustomField<T, K>;
|
|
290
|
+
type WithMatch<T extends object, K extends FieldName<T>> = RangeOk<T[K]> extends true ? FieldVariant<T, K> : (FieldVariant<T, K> & {
|
|
291
|
+
match?: Exclude<MatchOperator, "between">;
|
|
292
|
+
}) | BetweenError<T, K>;
|
|
293
|
+
/**
|
|
294
|
+
* One schema field.
|
|
295
|
+
*
|
|
296
|
+
* Discriminant is `type` (and `name`, and `match: "between"`).
|
|
297
|
+
* `type: "select"` without `options` errors on {@link ChoiceField} only.
|
|
298
|
+
* A scalar model field used as `"daterange"` or `match: "between"` errors with
|
|
299
|
+
* `RAC-FIELD-RANGE` or `RAC-FIELD-BETWEEN` and a one-line fix, not every widget.
|
|
300
|
+
* `name` still completes `defaultValue` as `T[name]`.
|
|
301
|
+
*
|
|
302
|
+
* {@link AnyField} plus `unsafeField` skip these checks. Dev warnings still run.
|
|
303
|
+
*/
|
|
304
|
+
export type Field<T extends object> = {
|
|
305
|
+
[K in FieldName<T>]: WithMatch<T, K>;
|
|
306
|
+
}[FieldName<T>] | DisplayField<T>;
|
|
307
|
+
/**
|
|
308
|
+
* No `name` and no value. `"title"` renders `label` as a heading.
|
|
309
|
+
* Do not add `defaultValue` here. An optional `undefined` default collapses `type` in error messages and hides `RAC-FIELD-RANGE`.
|
|
310
|
+
* `"tip"` and `"append"` render `tip`. `"button"` renders `label` and calls `onAction` on click.
|
|
311
|
+
* `onAction` throwing propagates to the click handler; the form value does not change.
|
|
312
|
+
*/
|
|
313
|
+
export interface DisplayField<T extends object> extends Access {
|
|
314
|
+
/** Display fields are not keys of T. A string name belongs on a value field. */
|
|
315
|
+
name?: undefined;
|
|
316
|
+
type: "title" | "tip" | "append" | "button";
|
|
317
|
+
label?: string;
|
|
318
|
+
tip?: ReactNode;
|
|
319
|
+
span?: number;
|
|
320
|
+
lineBreak?: boolean;
|
|
321
|
+
hidden?: Dynamic<boolean, T>;
|
|
322
|
+
disabled?: Dynamic<boolean, T>;
|
|
323
|
+
style?: CSSProperties;
|
|
324
|
+
className?: string;
|
|
325
|
+
/** Ignored. Present so a mixed field list can be read without narrowing. */
|
|
326
|
+
lang?: string;
|
|
327
|
+
required?: boolean;
|
|
328
|
+
rules?: FieldShared<T>["rules"];
|
|
329
|
+
onChange?: (value: unknown, values: T) => Partial<T> | void;
|
|
330
|
+
/** Ignored. Search panels only hide named fields. */
|
|
331
|
+
more?: boolean;
|
|
332
|
+
/** `"button"` click. Receives the current values. */
|
|
333
|
+
onAction?: (values: Readonly<T>) => void;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Unchecked field. Every prop is optional, so `type: "select"` without `options` compiles.
|
|
337
|
+
* This is the escape hatch. Pass it through {@link unsafeField} when a component asks for {@link Field}.
|
|
338
|
+
* Dev mode still warns about missing options, scalar ranges, and `match: "between"`.
|
|
339
|
+
*/
|
|
340
|
+
export interface AnyField<T extends object> extends Access {
|
|
341
|
+
name?: FieldName<T>;
|
|
35
342
|
label?: string;
|
|
36
343
|
lang?: string;
|
|
37
344
|
type?: FieldType;
|
|
345
|
+
defaultValue?: unknown;
|
|
38
346
|
hidden?: Dynamic<boolean, T>;
|
|
39
347
|
disabled?: Dynamic<boolean, T>;
|
|
40
348
|
required?: boolean;
|
|
@@ -46,7 +354,7 @@ export interface FieldBase<T extends object> extends Access {
|
|
|
46
354
|
style?: CSSProperties;
|
|
47
355
|
className?: string;
|
|
48
356
|
tip?: ReactNode;
|
|
49
|
-
rules?:
|
|
357
|
+
rules?: FieldShared<T>["rules"];
|
|
50
358
|
render?: (context: FieldContext<T>) => ReactNode;
|
|
51
359
|
component?: string;
|
|
52
360
|
onChange?: (value: unknown, values: T) => Partial<T> | void;
|
|
@@ -63,31 +371,26 @@ export interface FieldBase<T extends object> extends Access {
|
|
|
63
371
|
}[];
|
|
64
372
|
onAction?: (values: Readonly<T>) => void;
|
|
65
373
|
more?: boolean;
|
|
66
|
-
match?:
|
|
374
|
+
match?: MatchOperator;
|
|
67
375
|
ignoreCase?: boolean;
|
|
68
376
|
includeNull?: boolean;
|
|
69
377
|
searchFields?: readonly string[];
|
|
70
378
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
};
|
|
76
|
-
}[FieldName<T>] | (FieldBase<T> & {
|
|
77
|
-
name?: never;
|
|
78
|
-
type: "title" | "tip" | "append" | "button";
|
|
79
|
-
defaultValue?: never;
|
|
80
|
-
});
|
|
81
|
-
export type AnyField<T extends object> = FieldBase<T> & {
|
|
82
|
-
name?: FieldName<T>;
|
|
83
|
-
defaultValue?: unknown;
|
|
84
|
-
};
|
|
379
|
+
/**
|
|
380
|
+
* `localStorage` adapter used when `config.storage` is omitted.
|
|
381
|
+
* `get` returns `undefined` for missing and corrupt JSON. `set` / `remove` swallow quota errors.
|
|
382
|
+
*/
|
|
85
383
|
export interface StorageAdapter {
|
|
86
384
|
get(key: string): unknown;
|
|
87
385
|
set(key: string, value: unknown): void;
|
|
88
386
|
remove(key: string): void;
|
|
89
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Optional remote store for table settings. Keys already include the namespace, for example `my-app:table:orders`.
|
|
390
|
+
* `load` resolving `undefined` keeps the local copy. A rejection shows "Could not save settings" and a retry button.
|
|
391
|
+
*/
|
|
90
392
|
export interface SettingsAdapter {
|
|
91
393
|
load(key: string): Promise<unknown>;
|
|
92
394
|
save(key: string, value: unknown): Promise<void>;
|
|
93
395
|
}
|
|
396
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/core/errors.ts
|
|
2
|
+
var e = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
userKey;
|
|
5
|
+
constructor(e, t, r, i, a) {
|
|
6
|
+
super(n(e, t, r, i)), this.name = "RacError", this.code = t, this.userKey = a, process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test" && console.error(this.message);
|
|
7
|
+
}
|
|
8
|
+
}, t = "https://github.com/Zeroman/react-auto-components/blob/main/docs/errors.md#";
|
|
9
|
+
function n(e, n, r, i) {
|
|
10
|
+
return `[${e}] ${r}\nFix: ${i}\nCode: ${n}\nDocs: ${t}${n.toLowerCase()}`;
|
|
11
|
+
}
|
|
12
|
+
var r = /* @__PURE__ */ new Set();
|
|
13
|
+
function i(e, t, i, a) {
|
|
14
|
+
if (process.env.NODE_ENV === "production") return;
|
|
15
|
+
let o = `${t}\0${i}`;
|
|
16
|
+
r.has(o) || (r.add(o), console.warn(n(e, t, i, a)));
|
|
17
|
+
}
|
|
18
|
+
function a() {
|
|
19
|
+
r.clear();
|
|
20
|
+
}
|
|
21
|
+
function o(e) {
|
|
22
|
+
return Array.isArray(e) ? `array(length=${e.length})` : e === null ? "null" : typeof e;
|
|
23
|
+
}
|
|
24
|
+
function s(t, n) {
|
|
25
|
+
return n instanceof e && n.userKey ? t(n.userKey) : t(n instanceof Error ? n.message : String(n));
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { s as a, a as i, i as n, o, n as r, e as t };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export * from "./core/types";
|
|
2
|
+
export * from "./core/registry";
|
|
3
|
+
export * from "./core/testid";
|
|
4
|
+
export * from "./core/errors";
|
|
2
5
|
export * from "./core/config";
|
|
3
6
|
export * from "./core/query";
|
|
4
7
|
export * from "./core/AutoConfigProvider";
|
|
5
8
|
export * from "./components/AutoForm";
|
|
6
|
-
export * from "./components/
|
|
9
|
+
export * from "./components/AutoSearch";
|
|
7
10
|
export * from "./components/AutoDialog";
|
|
8
11
|
export * from "./components/AutoTabs";
|
|
9
12
|
export * from "./components/AutoMenu";
|