@alepha/ui 0.10.6 → 0.10.7
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/AlephaMantineProvider-EemOtraW.js +3 -0
- package/dist/AlephaMantineProvider-WfiC2EH6.js +95 -0
- package/dist/AlephaMantineProvider-WfiC2EH6.js.map +1 -0
- package/dist/index.d.ts +236 -36
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +520 -81
- package/dist/index.js.map +1 -1
- package/package.json +11 -6
- package/src/RootRouter.ts +8 -0
- package/src/components/Action.tsx +134 -134
- package/src/components/AlephaMantineProvider.tsx +34 -31
- package/src/components/Control.tsx +383 -229
- package/src/components/ControlDate.tsx +112 -0
- package/src/components/ControlSelect.tsx +134 -0
- package/src/components/DarkModeButton.tsx +75 -0
- package/src/components/Omnibar.tsx +76 -0
- package/src/components/TypeForm.tsx +158 -0
- package/src/hooks/useToast.ts +14 -0
- package/src/index.ts +25 -9
- package/src/services/ToastService.tsx +71 -0
- package/src/utils/icons.tsx +121 -0
- package/src/utils/string.ts +21 -0
|
@@ -1,275 +1,429 @@
|
|
|
1
|
-
import { TypeBoxError } from "@alepha/core";
|
|
2
|
-
import { type InputField, useFormState } from "@alepha/react-form";
|
|
1
|
+
import { type TObject, TypeBoxError } from "@alepha/core";
|
|
3
2
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
3
|
+
type InputField,
|
|
4
|
+
type UseFormStateReturn,
|
|
5
|
+
useFormState,
|
|
6
|
+
} from "@alepha/react-form";
|
|
7
|
+
import {
|
|
8
|
+
Autocomplete,
|
|
9
|
+
type AutocompleteProps,
|
|
10
|
+
ColorInput,
|
|
11
|
+
type ColorInputProps,
|
|
12
|
+
FileInput,
|
|
13
|
+
type FileInputProps,
|
|
14
|
+
Flex,
|
|
15
|
+
Input,
|
|
16
|
+
NumberInput,
|
|
17
|
+
type NumberInputProps,
|
|
18
|
+
PasswordInput,
|
|
19
|
+
type PasswordInputProps,
|
|
20
|
+
SegmentedControl,
|
|
21
|
+
type SegmentedControlProps,
|
|
22
|
+
type SelectProps,
|
|
23
|
+
Switch,
|
|
24
|
+
type SwitchProps,
|
|
25
|
+
Textarea,
|
|
26
|
+
type TextareaProps,
|
|
27
|
+
TextInput,
|
|
28
|
+
type TextInputProps,
|
|
20
29
|
} from "@mantine/core";
|
|
30
|
+
import type {
|
|
31
|
+
DateInputProps,
|
|
32
|
+
DateTimePickerProps,
|
|
33
|
+
TimeInputProps,
|
|
34
|
+
} from "@mantine/dates";
|
|
21
35
|
import type { ComponentType, ReactNode } from "react";
|
|
36
|
+
import { getDefaultIcon } from "../utils/icons.tsx";
|
|
37
|
+
import { prettyName } from "../utils/string.ts";
|
|
38
|
+
import ControlDate from "./ControlDate";
|
|
39
|
+
import ControlSelect from "./ControlSelect";
|
|
22
40
|
|
|
23
|
-
export interface ControlProps {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
custom?: ComponentType<CustomControlProps>;
|
|
41
|
+
export interface ControlProps extends GenericControlProps {
|
|
42
|
+
text?: TextInputProps;
|
|
43
|
+
area?: boolean | TextareaProps;
|
|
44
|
+
select?: boolean | SelectProps;
|
|
45
|
+
autocomplete?: boolean | AutocompleteProps;
|
|
46
|
+
password?: boolean | PasswordInputProps;
|
|
47
|
+
switch?: boolean | SwitchProps;
|
|
48
|
+
segmented?: boolean | Partial<SegmentedControlProps>;
|
|
49
|
+
number?: boolean | NumberInputProps;
|
|
50
|
+
file?: boolean | FileInputProps;
|
|
51
|
+
color?: boolean | ColorInputProps;
|
|
52
|
+
date?: boolean | DateInputProps;
|
|
53
|
+
datetime?: boolean | DateTimePickerProps;
|
|
54
|
+
time?: boolean | TimeInputProps;
|
|
55
|
+
custom?: ComponentType<CustomControlProps>;
|
|
40
56
|
}
|
|
41
57
|
|
|
42
58
|
/**
|
|
43
59
|
* Generic form control that renders the appropriate input based on the schema and props.
|
|
44
60
|
*
|
|
45
61
|
* Supports:
|
|
46
|
-
* - TextInput
|
|
62
|
+
* - TextInput (with format detection: email, url, tel)
|
|
47
63
|
* - Textarea
|
|
64
|
+
* - NumberInput (for number/integer types)
|
|
65
|
+
* - FileInput
|
|
66
|
+
* - ColorInput (for color format)
|
|
48
67
|
* - Select (for enum types)
|
|
49
68
|
* - Autocomplete
|
|
50
69
|
* - PasswordInput
|
|
51
70
|
* - Switch (for boolean types)
|
|
52
71
|
* - SegmentedControl (for enum types)
|
|
72
|
+
* - DateInput (for date format)
|
|
73
|
+
* - DateTimePicker (for date-time format)
|
|
74
|
+
* - TimeInput (for time format)
|
|
53
75
|
* - Custom component
|
|
54
76
|
*
|
|
55
|
-
* Automatically handles labels, descriptions, error messages, and
|
|
77
|
+
* Automatically handles labels, descriptions, error messages, required state, and default icons.
|
|
56
78
|
*/
|
|
57
79
|
const Control = (props: ControlProps) => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
80
|
+
const form = useFormState(props.input);
|
|
81
|
+
const { inputProps, id, icon } = parseInput(props, form);
|
|
82
|
+
if (!props.input?.props) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Extract format once to avoid redeclaration
|
|
87
|
+
const format =
|
|
88
|
+
props.input.schema &&
|
|
89
|
+
"format" in props.input.schema &&
|
|
90
|
+
typeof props.input.schema.format === "string"
|
|
91
|
+
? props.input.schema.format
|
|
92
|
+
: undefined;
|
|
62
93
|
|
|
63
|
-
|
|
94
|
+
//region <Custom/>
|
|
95
|
+
if (props.custom) {
|
|
96
|
+
const Custom = props.custom;
|
|
97
|
+
return (
|
|
98
|
+
<Input.Wrapper {...inputProps}>
|
|
99
|
+
<Flex flex={1} mt={"calc(var(--mantine-spacing-xs) / 2)"}>
|
|
100
|
+
<Custom
|
|
101
|
+
defaultValue={props.input.props.defaultValue}
|
|
102
|
+
onChange={(value) => {
|
|
103
|
+
props.input.set(value);
|
|
104
|
+
}}
|
|
105
|
+
/>
|
|
106
|
+
</Flex>
|
|
107
|
+
</Input.Wrapper>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
//endregion
|
|
64
111
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
112
|
+
//region <NumberInput/>
|
|
113
|
+
if (
|
|
114
|
+
props.number ||
|
|
115
|
+
(props.input.schema &&
|
|
116
|
+
"type" in props.input.schema &&
|
|
117
|
+
(props.input.schema.type === "number" ||
|
|
118
|
+
props.input.schema.type === "integer"))
|
|
119
|
+
) {
|
|
120
|
+
const numberInputProps =
|
|
121
|
+
typeof props.number === "object" ? props.number : {};
|
|
122
|
+
const { type, ...inputPropsWithoutType } = props.input.props;
|
|
123
|
+
return (
|
|
124
|
+
<NumberInput
|
|
125
|
+
{...inputProps}
|
|
126
|
+
id={id}
|
|
127
|
+
leftSection={icon}
|
|
128
|
+
{...inputPropsWithoutType}
|
|
129
|
+
{...numberInputProps}
|
|
130
|
+
/>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
//endregion
|
|
86
134
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
135
|
+
//region <FileInput/>
|
|
136
|
+
if (props.file) {
|
|
137
|
+
const fileInputProps = typeof props.file === "object" ? props.file : {};
|
|
138
|
+
return (
|
|
139
|
+
<FileInput
|
|
140
|
+
{...inputProps}
|
|
141
|
+
id={id}
|
|
142
|
+
leftSection={icon}
|
|
143
|
+
onChange={(file) => {
|
|
144
|
+
props.input.set(file);
|
|
145
|
+
}}
|
|
146
|
+
{...fileInputProps}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
//endregion
|
|
94
151
|
|
|
95
|
-
|
|
152
|
+
//region <ColorInput/>
|
|
153
|
+
if (props.color || format === "color") {
|
|
154
|
+
const colorInputProps = typeof props.color === "object" ? props.color : {};
|
|
155
|
+
return (
|
|
156
|
+
<ColorInput
|
|
157
|
+
{...inputProps}
|
|
158
|
+
id={id}
|
|
159
|
+
leftSection={icon}
|
|
160
|
+
{...props.input.props}
|
|
161
|
+
{...colorInputProps}
|
|
162
|
+
/>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
//endregion
|
|
96
166
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
167
|
+
//region <SegmentedControl/>
|
|
168
|
+
if (props.segmented) {
|
|
169
|
+
const segmentedControlProps: Partial<SegmentedControlProps> =
|
|
170
|
+
typeof props.segmented === "object" ? props.segmented : {};
|
|
171
|
+
const data =
|
|
172
|
+
segmentedControlProps.data ??
|
|
173
|
+
(props.input.schema &&
|
|
174
|
+
"enum" in props.input.schema &&
|
|
175
|
+
Array.isArray(props.input.schema.enum)
|
|
176
|
+
? props.input.schema.enum?.map((value: string) => ({
|
|
177
|
+
value,
|
|
178
|
+
label: value,
|
|
179
|
+
}))
|
|
180
|
+
: []);
|
|
181
|
+
return (
|
|
182
|
+
<Input.Wrapper {...inputProps}>
|
|
183
|
+
<Flex mt={"calc(var(--mantine-spacing-xs) / 2)"}>
|
|
184
|
+
<SegmentedControl
|
|
185
|
+
disabled={inputProps.disabled}
|
|
186
|
+
defaultValue={String(props.input.props.defaultValue)}
|
|
187
|
+
{...segmentedControlProps}
|
|
188
|
+
onChange={(value) => {
|
|
189
|
+
props.input.set(value);
|
|
190
|
+
}}
|
|
191
|
+
data={data}
|
|
192
|
+
/>
|
|
193
|
+
</Flex>
|
|
194
|
+
</Input.Wrapper>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
//endregion
|
|
112
198
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const data =
|
|
118
|
-
segmentedControlProps.data ??
|
|
119
|
-
(props.input.schema &&
|
|
120
|
-
"enum" in props.input.schema &&
|
|
121
|
-
Array.isArray(props.input.schema.enum)
|
|
122
|
-
? props.input.schema.enum?.map((value: string) => ({
|
|
123
|
-
value,
|
|
124
|
-
label: value,
|
|
125
|
-
}))
|
|
126
|
-
: []);
|
|
127
|
-
return (
|
|
128
|
-
<Input.Wrapper {...inputProps}>
|
|
129
|
-
<Flex mt={"calc(var(--mantine-spacing-xs) / 2)"}>
|
|
130
|
-
<SegmentedControl
|
|
131
|
-
disabled={disabled}
|
|
132
|
-
defaultValue={String(props.input.props.defaultValue)}
|
|
133
|
-
{...segmentedControlProps}
|
|
134
|
-
onChange={(value) => {
|
|
135
|
-
props.input.set(value);
|
|
136
|
-
}}
|
|
137
|
-
data={data}
|
|
138
|
-
/>
|
|
139
|
-
</Flex>
|
|
140
|
-
</Input.Wrapper>
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
// endregion
|
|
199
|
+
//region <Autocomplete/>
|
|
200
|
+
if (props.autocomplete) {
|
|
201
|
+
const autocompleteProps =
|
|
202
|
+
typeof props.autocomplete === "object" ? props.autocomplete : {};
|
|
144
203
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
204
|
+
return (
|
|
205
|
+
<Autocomplete
|
|
206
|
+
{...inputProps}
|
|
207
|
+
id={id}
|
|
208
|
+
leftSection={icon}
|
|
209
|
+
{...props.input.props}
|
|
210
|
+
{...autocompleteProps}
|
|
211
|
+
/>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
//endregion
|
|
149
215
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
// endregion
|
|
216
|
+
//region <ControlSelect/>
|
|
217
|
+
// Handle: single enum, array of enum, array of strings, or explicit select/multi/tags props
|
|
218
|
+
const isEnum =
|
|
219
|
+
props.input.schema &&
|
|
220
|
+
"enum" in props.input.schema &&
|
|
221
|
+
props.input.schema.enum;
|
|
222
|
+
const isArray =
|
|
223
|
+
props.input.schema &&
|
|
224
|
+
"type" in props.input.schema &&
|
|
225
|
+
props.input.schema.type === "array";
|
|
161
226
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
value,
|
|
175
|
-
label: value,
|
|
176
|
-
}))
|
|
177
|
-
: [];
|
|
227
|
+
if (isEnum || isArray || props.select) {
|
|
228
|
+
return (
|
|
229
|
+
<ControlSelect
|
|
230
|
+
input={props.input}
|
|
231
|
+
title={props.title}
|
|
232
|
+
description={props.description}
|
|
233
|
+
icon={icon}
|
|
234
|
+
select={props.select}
|
|
235
|
+
/>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
//endregion
|
|
178
239
|
|
|
179
|
-
|
|
240
|
+
//region <Switch/>
|
|
241
|
+
if (
|
|
242
|
+
(props.input.schema &&
|
|
243
|
+
"type" in props.input.schema &&
|
|
244
|
+
props.input.schema.type === "boolean") ||
|
|
245
|
+
props.switch
|
|
246
|
+
) {
|
|
247
|
+
const switchProps = typeof props.switch === "object" ? props.switch : {};
|
|
180
248
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
249
|
+
return (
|
|
250
|
+
<Switch
|
|
251
|
+
{...inputProps}
|
|
252
|
+
id={id}
|
|
253
|
+
color={"blue"}
|
|
254
|
+
defaultChecked={props.input.props.defaultValue}
|
|
255
|
+
{...props.input.props}
|
|
256
|
+
{...switchProps}
|
|
257
|
+
/>
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
//endregion
|
|
193
261
|
|
|
194
|
-
|
|
262
|
+
//region <PasswordInput/>
|
|
263
|
+
if (props.password || props.input.props.name?.includes("password")) {
|
|
264
|
+
const passwordInputProps =
|
|
265
|
+
typeof props.password === "object" ? props.password : {};
|
|
266
|
+
return (
|
|
267
|
+
<PasswordInput
|
|
268
|
+
{...inputProps}
|
|
269
|
+
id={id}
|
|
270
|
+
leftSection={icon}
|
|
271
|
+
{...props.input.props}
|
|
272
|
+
{...passwordInputProps}
|
|
273
|
+
/>
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
//endregion
|
|
195
277
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
278
|
+
//region <Textarea/>
|
|
279
|
+
if (props.area) {
|
|
280
|
+
const textAreaProps = typeof props.area === "object" ? props.area : {};
|
|
281
|
+
return (
|
|
282
|
+
<Textarea
|
|
283
|
+
{...inputProps}
|
|
284
|
+
id={id}
|
|
285
|
+
leftSection={icon}
|
|
286
|
+
{...props.input.props}
|
|
287
|
+
{...textAreaProps}
|
|
288
|
+
/>
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
//endregion
|
|
203
292
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
293
|
+
//region <ControlDate/>
|
|
294
|
+
// Handle: date, date-time, and time formats
|
|
295
|
+
if (
|
|
296
|
+
props.date ||
|
|
297
|
+
props.datetime ||
|
|
298
|
+
props.time ||
|
|
299
|
+
format === "date" ||
|
|
300
|
+
format === "date-time" ||
|
|
301
|
+
format === "time"
|
|
302
|
+
) {
|
|
303
|
+
return (
|
|
304
|
+
<ControlDate
|
|
305
|
+
input={props.input}
|
|
306
|
+
title={props.title}
|
|
307
|
+
description={props.description}
|
|
308
|
+
icon={icon}
|
|
309
|
+
date={props.date}
|
|
310
|
+
datetime={props.datetime}
|
|
311
|
+
time={props.time}
|
|
312
|
+
/>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
//endregion
|
|
216
316
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const passwordInputProps =
|
|
220
|
-
typeof props.password === "object" ? props.password : {};
|
|
221
|
-
return (
|
|
222
|
-
<PasswordInput
|
|
223
|
-
{...inputProps}
|
|
224
|
-
id={id}
|
|
225
|
-
leftSection={icon}
|
|
226
|
-
{...props.input.props}
|
|
227
|
-
{...passwordInputProps}
|
|
228
|
-
/>
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
//endregion
|
|
317
|
+
//region <TextInput/> with format detection
|
|
318
|
+
const textInputProps = typeof props.text === "object" ? props.text : {};
|
|
232
319
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
320
|
+
// Detect HTML5 input type from format
|
|
321
|
+
const getInputType = (): string | undefined => {
|
|
322
|
+
switch (format) {
|
|
323
|
+
case "email":
|
|
324
|
+
return "email";
|
|
325
|
+
case "url":
|
|
326
|
+
case "uri":
|
|
327
|
+
return "url";
|
|
328
|
+
case "tel":
|
|
329
|
+
case "phone":
|
|
330
|
+
return "tel";
|
|
331
|
+
default:
|
|
332
|
+
return undefined;
|
|
333
|
+
}
|
|
334
|
+
};
|
|
247
335
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
//endregion
|
|
336
|
+
return (
|
|
337
|
+
<TextInput
|
|
338
|
+
{...inputProps}
|
|
339
|
+
id={id}
|
|
340
|
+
leftSection={icon}
|
|
341
|
+
type={getInputType()}
|
|
342
|
+
{...props.input.props}
|
|
343
|
+
{...textInputProps}
|
|
344
|
+
/>
|
|
345
|
+
);
|
|
346
|
+
//endregion
|
|
260
347
|
};
|
|
261
348
|
|
|
262
349
|
export default Control;
|
|
263
350
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
351
|
+
// =============================================================================
|
|
352
|
+
// Helper Types and Functions
|
|
353
|
+
// =============================================================================
|
|
354
|
+
|
|
355
|
+
export interface GenericControlProps {
|
|
356
|
+
input: InputField;
|
|
357
|
+
title?: string;
|
|
358
|
+
description?: string;
|
|
359
|
+
icon?: ReactNode;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export const parseInput = (
|
|
363
|
+
props: GenericControlProps,
|
|
364
|
+
form: UseFormStateReturn<TObject>,
|
|
365
|
+
) => {
|
|
366
|
+
const disabled = false; // form.loading;
|
|
367
|
+
const id = props.input.props.id;
|
|
368
|
+
const label =
|
|
369
|
+
props.title ??
|
|
370
|
+
("title" in props.input.schema &&
|
|
371
|
+
typeof props.input.schema.title === "string"
|
|
372
|
+
? props.input.schema.title
|
|
373
|
+
: undefined) ??
|
|
374
|
+
prettyName(props.input.path);
|
|
375
|
+
const description =
|
|
376
|
+
props.description ??
|
|
377
|
+
("description" in props.input.schema &&
|
|
378
|
+
typeof props.input.schema.description === "string"
|
|
379
|
+
? props.input.schema.description
|
|
380
|
+
: undefined);
|
|
381
|
+
const error =
|
|
382
|
+
form.error && form.error instanceof TypeBoxError
|
|
383
|
+
? form.error.value.message
|
|
384
|
+
: undefined;
|
|
385
|
+
|
|
386
|
+
// Auto-generate icon if not provided
|
|
387
|
+
const icon =
|
|
388
|
+
props.icon ??
|
|
389
|
+
getDefaultIcon({
|
|
390
|
+
type:
|
|
391
|
+
props.input.schema && "type" in props.input.schema
|
|
392
|
+
? String(props.input.schema.type)
|
|
393
|
+
: undefined,
|
|
394
|
+
format:
|
|
395
|
+
props.input.schema &&
|
|
396
|
+
"format" in props.input.schema &&
|
|
397
|
+
typeof props.input.schema.format === "string"
|
|
398
|
+
? props.input.schema.format
|
|
399
|
+
: undefined,
|
|
400
|
+
name: props.input.props.name,
|
|
401
|
+
isEnum:
|
|
402
|
+
props.input.schema &&
|
|
403
|
+
"enum" in props.input.schema &&
|
|
404
|
+
Boolean(props.input.schema.enum),
|
|
405
|
+
isArray:
|
|
406
|
+
props.input.schema &&
|
|
407
|
+
"type" in props.input.schema &&
|
|
408
|
+
props.input.schema.type === "array",
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
const required = props.input.required;
|
|
267
412
|
|
|
268
|
-
|
|
269
|
-
|
|
413
|
+
return {
|
|
414
|
+
id,
|
|
415
|
+
icon,
|
|
416
|
+
inputProps: {
|
|
417
|
+
label,
|
|
418
|
+
description,
|
|
419
|
+
error,
|
|
420
|
+
required,
|
|
421
|
+
disabled,
|
|
422
|
+
},
|
|
423
|
+
};
|
|
270
424
|
};
|
|
271
425
|
|
|
272
426
|
export type CustomControlProps = {
|
|
273
|
-
|
|
274
|
-
|
|
427
|
+
defaultValue: any;
|
|
428
|
+
onChange: (value: any) => void;
|
|
275
429
|
};
|