@k3-universe/react-kit 0.0.13 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +413 -403
- package/dist/kit/builder/data-table/types.d.ts +1 -1
- package/dist/kit/builder/data-table/types.d.ts.map +1 -1
- package/dist/kit/builder/form/components/FormBuilder.d.ts +3 -172
- package/dist/kit/builder/form/components/FormBuilder.d.ts.map +1 -1
- package/dist/kit/builder/form/components/FormBuilderField.d.ts +8 -8
- package/dist/kit/builder/form/components/FormBuilderField.d.ts.map +1 -1
- package/dist/kit/builder/form/components/fields/types.d.ts +3 -3
- package/dist/kit/builder/form/components/fields/types.d.ts.map +1 -1
- package/dist/kit/builder/form/index.d.ts +1 -0
- package/dist/kit/builder/form/index.d.ts.map +1 -1
- package/dist/kit/builder/form/types.d.ts +175 -0
- package/dist/kit/builder/form/types.d.ts.map +1 -0
- package/dist/kit/builder/form/utils/common-forms.d.ts +1 -1
- package/dist/kit/builder/form/utils/common-forms.d.ts.map +1 -1
- package/dist/kit/builder/form/utils/field-factories.d.ts +3 -3
- package/dist/kit/builder/form/utils/field-factories.d.ts.map +1 -1
- package/dist/kit/builder/form/utils/section-factories.d.ts +4 -4
- package/dist/kit/builder/form/utils/section-factories.d.ts.map +1 -1
- package/dist/kit/builder/stack-dialog/provider.d.ts.map +1 -1
- package/dist/kit/builder/stack-dialog/renderer.d.ts.map +1 -1
- package/dist/kit/components/autocomplete/Autocomplete.d.ts +8 -8
- package/dist/kit/components/autocomplete/Autocomplete.d.ts.map +1 -1
- package/dist/kit/components/autocomplete/types.d.ts +6 -4
- package/dist/kit/components/autocomplete/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/kit/builder/data-table/components/DataTable.tsx +1 -1
- package/src/kit/builder/data-table/types.ts +1 -1
- package/src/kit/builder/form/components/FormBuilder.tsx +43 -237
- package/src/kit/builder/form/components/FormBuilderField.tsx +42 -34
- package/src/kit/builder/form/components/fields/AutocompleteField.tsx +2 -2
- package/src/kit/builder/form/components/fields/types.ts +3 -3
- package/src/kit/builder/form/index.ts +1 -0
- package/src/kit/builder/form/types.ts +198 -0
- package/src/kit/builder/form/utils/common-forms.ts +1 -1
- package/src/kit/builder/form/utils/field-factories.ts +5 -5
- package/src/kit/builder/form/utils/section-factories.ts +10 -10
- package/src/kit/builder/stack-dialog/provider.tsx +2 -1
- package/src/kit/builder/stack-dialog/renderer.tsx +6 -7
- package/src/kit/components/autocomplete/Autocomplete.tsx +33 -25
- package/src/kit/components/autocomplete/types.ts +7 -5
|
@@ -32,10 +32,10 @@ import type {
|
|
|
32
32
|
} from "./types";
|
|
33
33
|
import { useDebounce } from "use-debounce";
|
|
34
34
|
|
|
35
|
-
export type AutocompleteProps = {
|
|
35
|
+
export type AutocompleteProps<T = unknown> = {
|
|
36
36
|
mode: AutocompleteMode;
|
|
37
|
-
options?: AutocompleteOption[];
|
|
38
|
-
fetcher?: AutocompleteFetcher
|
|
37
|
+
options?: AutocompleteOption<T>[];
|
|
38
|
+
fetcher?: AutocompleteFetcher<T>;
|
|
39
39
|
pageSize?: number;
|
|
40
40
|
/**
|
|
41
41
|
* Value can be a single primitive or an array when `multiple` is true
|
|
@@ -46,7 +46,8 @@ export type AutocompleteProps = {
|
|
|
46
46
|
*/
|
|
47
47
|
onChange?: (
|
|
48
48
|
value: string | number | null | Array<string | number>,
|
|
49
|
-
option: AutocompleteOption | AutocompleteOption[] | null,
|
|
49
|
+
option: AutocompleteOption<T> | AutocompleteOption<T>[] | null,
|
|
50
|
+
raw?: T | T[] | null,
|
|
50
51
|
) => void;
|
|
51
52
|
/** Enable selecting multiple values (shows chips) */
|
|
52
53
|
multiple?: boolean;
|
|
@@ -56,7 +57,7 @@ export type AutocompleteProps = {
|
|
|
56
57
|
className?: string;
|
|
57
58
|
emptyText?: string;
|
|
58
59
|
renderOption?: (
|
|
59
|
-
option: AutocompleteOption
|
|
60
|
+
option: AutocompleteOption<T>,
|
|
60
61
|
selected: boolean,
|
|
61
62
|
) => React.ReactNode;
|
|
62
63
|
searchPlaceholder?: string;
|
|
@@ -79,21 +80,21 @@ export type AutocompleteProps = {
|
|
|
79
80
|
* Optional: seed selected labels for edit pages. These options are only used to populate the
|
|
80
81
|
* internal label map so labels render correctly when values are prefilled.
|
|
81
82
|
*/
|
|
82
|
-
initialSelectedOptions?: AutocompleteOption | AutocompleteOption[] | null;
|
|
83
|
+
initialSelectedOptions?: AutocompleteOption<T> | AutocompleteOption<T>[] | null;
|
|
83
84
|
/**
|
|
84
85
|
* Optional: load labels/options for a list of values whose labels are unknown.
|
|
85
86
|
* Useful for edit pages in server mode when only values are available.
|
|
86
87
|
*/
|
|
87
|
-
loadSelected?: (values: Array<string | number>) => Promise<AutocompleteOption[]>;
|
|
88
|
+
loadSelected?: (values: Array<string | number>) => Promise<AutocompleteOption<T>[]>;
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
const DEFAULT_PAGE_SIZE = 20;
|
|
91
92
|
|
|
92
93
|
const EMPTY_OPTIONS: AutocompleteOption[] = [];
|
|
93
94
|
|
|
94
|
-
export function Autocomplete({
|
|
95
|
+
export function Autocomplete<T = unknown>({
|
|
95
96
|
mode,
|
|
96
|
-
options = EMPTY_OPTIONS,
|
|
97
|
+
options = EMPTY_OPTIONS as AutocompleteOption<T>[],
|
|
97
98
|
fetcher,
|
|
98
99
|
pageSize = DEFAULT_PAGE_SIZE,
|
|
99
100
|
value: controlledValue,
|
|
@@ -113,7 +114,7 @@ export function Autocomplete({
|
|
|
113
114
|
clearable = true,
|
|
114
115
|
initialSelectedOptions,
|
|
115
116
|
loadSelected,
|
|
116
|
-
}: AutocompleteProps) {
|
|
117
|
+
}: AutocompleteProps<T>) {
|
|
117
118
|
const [open, setOpen] = useState<boolean>(!!defaultOpen);
|
|
118
119
|
const [search, setSearch] = useState("");
|
|
119
120
|
const [debouncedSearch] = useDebounce(search, 250);
|
|
@@ -135,8 +136,12 @@ export function Autocomplete({
|
|
|
135
136
|
// Keep a map of value -> label to ensure we can render chips/labels even if the option
|
|
136
137
|
// is not present in the current page (especially in server mode or for custom values)
|
|
137
138
|
const labelMapRef = useRef<Map<string | number, string>>(new Map());
|
|
138
|
-
const
|
|
139
|
+
const rawMapRef = useRef<Map<string | number, T>>(new Map());
|
|
140
|
+
const addToLabelMap = useCallback((opt: AutocompleteOption<T>) => {
|
|
139
141
|
labelMapRef.current.set(opt.value, opt.label);
|
|
142
|
+
if (Object.prototype.hasOwnProperty.call(opt, "raw") && (opt as AutocompleteOption<T>).raw !== undefined) {
|
|
143
|
+
rawMapRef.current.set(opt.value, (opt as AutocompleteOption<T>).raw as T);
|
|
144
|
+
}
|
|
140
145
|
}, []);
|
|
141
146
|
// Tick to force re-render when labels hydrate via async
|
|
142
147
|
const [labelTick, setLabelTick] = useState(0);
|
|
@@ -149,7 +154,7 @@ export function Autocomplete({
|
|
|
149
154
|
);
|
|
150
155
|
|
|
151
156
|
const handleSelect = useCallback(
|
|
152
|
-
(next: AutocompleteOption) => {
|
|
157
|
+
(next: AutocompleteOption<T>) => {
|
|
153
158
|
addToLabelMap(next);
|
|
154
159
|
if (isMultiple) {
|
|
155
160
|
const prevValues = Array.isArray(value) ? value : [];
|
|
@@ -159,16 +164,18 @@ export function Autocomplete({
|
|
|
159
164
|
: [...prevValues, next.value];
|
|
160
165
|
|
|
161
166
|
if (controlledValue === undefined) setValue(newValues);
|
|
162
|
-
const selectedOptions: AutocompleteOption[] = newValues.map((v) => ({
|
|
167
|
+
const selectedOptions: AutocompleteOption<T>[] = newValues.map((v) => ({
|
|
163
168
|
value: v,
|
|
164
169
|
label: getLabel(v),
|
|
170
|
+
raw: rawMapRef.current.get(v),
|
|
165
171
|
}));
|
|
166
|
-
|
|
172
|
+
const raws = selectedOptions.map((o) => o.raw as T);
|
|
173
|
+
onChange?.(newValues, selectedOptions, raws);
|
|
167
174
|
// Keep open for multi-select
|
|
168
175
|
} else {
|
|
169
176
|
const newValue = next.value;
|
|
170
177
|
if (controlledValue === undefined) setValue(newValue);
|
|
171
|
-
onChange?.(newValue, next);
|
|
178
|
+
onChange?.(newValue, next, (next as AutocompleteOption<T>).raw as T | undefined ?? null);
|
|
172
179
|
setOpen(false);
|
|
173
180
|
}
|
|
174
181
|
},
|
|
@@ -176,7 +183,7 @@ export function Autocomplete({
|
|
|
176
183
|
);
|
|
177
184
|
|
|
178
185
|
// Data state (shared for both modes)
|
|
179
|
-
const [items, setItems] = useState<AutocompleteOption[]>([]);
|
|
186
|
+
const [items, setItems] = useState<AutocompleteOption<T>[]>([]);
|
|
180
187
|
const [loading, setLoading] = useState(false);
|
|
181
188
|
const [hasMore, setHasMore] = useState(false);
|
|
182
189
|
const [nextCursor, setNextCursor] = useState<
|
|
@@ -197,7 +204,7 @@ export function Autocomplete({
|
|
|
197
204
|
if (!fetcher) return;
|
|
198
205
|
setLoading(true);
|
|
199
206
|
try {
|
|
200
|
-
const res: AutocompleteFetchResult = await fetcher({
|
|
207
|
+
const res: AutocompleteFetchResult<T> = await fetcher({
|
|
201
208
|
search: debouncedSearch,
|
|
202
209
|
cursor: nextCursor ?? null,
|
|
203
210
|
page,
|
|
@@ -334,24 +341,23 @@ export function Autocomplete({
|
|
|
334
341
|
return placeholder;
|
|
335
342
|
}, [isMultiple, mode, options, selectedOption, value, placeholder, labelTick]);
|
|
336
343
|
|
|
337
|
-
|
|
338
344
|
const selectedValues: Array<string | number> = useMemo(
|
|
339
345
|
() => (isMultiple && Array.isArray(value) ? value : []),
|
|
340
346
|
[isMultiple, value],
|
|
341
347
|
);
|
|
342
348
|
// biome-ignore lint/correctness/useExhaustiveDependencies: labelTick intentionally triggers recompute when labelMap hydrates
|
|
343
|
-
const selectedOptionsMulti: AutocompleteOption[] = useMemo(
|
|
344
|
-
() => selectedValues.map((v) => ({ value: v, label: getLabel(v) })),
|
|
349
|
+
const selectedOptionsMulti: AutocompleteOption<T>[] = useMemo(
|
|
350
|
+
() => selectedValues.map((v) => ({ value: v, label: getLabel(v), raw: rawMapRef.current.get(v) })),
|
|
345
351
|
[getLabel, selectedValues, labelTick],
|
|
346
352
|
);
|
|
347
353
|
|
|
348
354
|
const handleClear = useCallback(() => {
|
|
349
355
|
if (isMultiple) {
|
|
350
356
|
if (controlledValue === undefined) setValue([]);
|
|
351
|
-
onChange?.([], []);
|
|
357
|
+
onChange?.([], [], []);
|
|
352
358
|
} else {
|
|
353
359
|
if (controlledValue === undefined) setValue(null);
|
|
354
|
-
onChange?.(null, null);
|
|
360
|
+
onChange?.(null, null, null);
|
|
355
361
|
}
|
|
356
362
|
}, [controlledValue, isMultiple, onChange]);
|
|
357
363
|
|
|
@@ -360,7 +366,7 @@ export function Autocomplete({
|
|
|
360
366
|
(text: string) => {
|
|
361
367
|
const t = text.trim();
|
|
362
368
|
if (!t) return;
|
|
363
|
-
const created: AutocompleteOption = { value: t, label: t };
|
|
369
|
+
const created: AutocompleteOption<T> = { value: t, label: t };
|
|
364
370
|
addToLabelMap(created);
|
|
365
371
|
if (isMultiple) {
|
|
366
372
|
const prevValues = Array.isArray(value) ? value : [];
|
|
@@ -370,12 +376,14 @@ export function Autocomplete({
|
|
|
370
376
|
const newOptions = newValues.map((v) => ({
|
|
371
377
|
value: v,
|
|
372
378
|
label: getLabel(v),
|
|
379
|
+
raw: rawMapRef.current.get(v),
|
|
373
380
|
}));
|
|
374
|
-
|
|
381
|
+
const raws = newOptions.map((o) => o.raw as T);
|
|
382
|
+
onChange?.(newValues, newOptions, raws);
|
|
375
383
|
setSearch("");
|
|
376
384
|
} else {
|
|
377
385
|
if (controlledValue === undefined) setValue(created.value);
|
|
378
|
-
onChange?.(created.value, created);
|
|
386
|
+
onChange?.(created.value, created, (created.raw as T | undefined) ?? null);
|
|
379
387
|
setSearch("");
|
|
380
388
|
setOpen(false);
|
|
381
389
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
export type AutocompleteOption = {
|
|
1
|
+
export type AutocompleteOption<T = unknown> = {
|
|
2
2
|
value: string | number
|
|
3
3
|
label: string
|
|
4
|
+
/** Optional original object returned by the fetcher/static source */
|
|
5
|
+
raw?: T
|
|
4
6
|
}
|
|
5
7
|
|
|
6
8
|
export type AutocompleteFetchParams = {
|
|
@@ -10,15 +12,15 @@ export type AutocompleteFetchParams = {
|
|
|
10
12
|
pageSize: number
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
export type AutocompleteFetchResult = {
|
|
14
|
-
items: AutocompleteOption[]
|
|
15
|
+
export type AutocompleteFetchResult<T = unknown> = {
|
|
16
|
+
items: AutocompleteOption<T>[]
|
|
15
17
|
nextCursor?: string | number | null
|
|
16
18
|
hasMore: boolean
|
|
17
19
|
total?: number
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
export type AutocompleteFetcher = (
|
|
22
|
+
export type AutocompleteFetcher<T = unknown> = (
|
|
21
23
|
params: AutocompleteFetchParams,
|
|
22
|
-
) => Promise<AutocompleteFetchResult
|
|
24
|
+
) => Promise<AutocompleteFetchResult<T>>
|
|
23
25
|
|
|
24
26
|
export type AutocompleteMode = 'client' | 'server'
|