@vendure/dashboard 3.4.1-master-202508200231 → 3.4.1

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.
Files changed (58) hide show
  1. package/package.json +152 -152
  2. package/src/app/routes/_authenticated/_orders/components/order-modification-preview-dialog.tsx +2 -1
  3. package/src/app/routes/_authenticated/_products/components/add-product-variant-dialog.tsx +1 -0
  4. package/src/lib/components/data-input/affixed-input.tsx +19 -5
  5. package/src/lib/components/data-input/boolean-input.tsx +9 -0
  6. package/src/lib/components/data-input/checkbox-input.tsx +8 -0
  7. package/src/lib/components/data-input/combination-mode-input.tsx +11 -2
  8. package/src/lib/components/data-input/configurable-operation-list-input.tsx +26 -401
  9. package/src/lib/components/data-input/custom-field-list-input.tsx +18 -25
  10. package/src/lib/components/data-input/customer-group-input.tsx +7 -11
  11. package/src/lib/components/data-input/datetime-input.tsx +9 -13
  12. package/src/lib/components/data-input/default-relation-input.tsx +29 -9
  13. package/src/lib/components/data-input/facet-value-input.tsx +15 -13
  14. package/src/lib/components/data-input/index.ts +2 -2
  15. package/src/lib/components/data-input/money-input.tsx +27 -20
  16. package/src/lib/components/data-input/number-input.tsx +48 -0
  17. package/src/lib/components/data-input/password-input.tsx +16 -0
  18. package/src/lib/components/data-input/{product-multi-selector.tsx → product-multi-selector-input.tsx} +8 -15
  19. package/src/lib/components/data-input/relation-input.tsx +7 -6
  20. package/src/lib/components/data-input/rich-text-input.tsx +10 -13
  21. package/src/lib/components/data-input/select-with-options.tsx +29 -17
  22. package/src/lib/components/data-input/struct-form-input.tsx +54 -59
  23. package/src/lib/components/data-input/text-input.tsx +9 -0
  24. package/src/lib/components/data-input/textarea-input.tsx +16 -0
  25. package/src/lib/components/data-table/filters/data-table-number-filter.tsx +3 -0
  26. package/src/lib/components/data-table/use-generated-columns.tsx +16 -5
  27. package/src/lib/components/shared/configurable-operation-arg-input.tsx +3 -10
  28. package/src/lib/components/shared/configurable-operation-input.tsx +1 -6
  29. package/src/lib/components/shared/configurable-operation-multi-selector.tsx +8 -5
  30. package/src/lib/components/shared/configurable-operation-selector.tsx +5 -5
  31. package/src/lib/components/shared/custom-fields-form.tsx +20 -49
  32. package/src/lib/components/shared/multi-select.tsx +1 -1
  33. package/src/lib/framework/component-registry/component-registry.tsx +9 -32
  34. package/src/lib/framework/component-registry/display-component.tsx +28 -0
  35. package/src/lib/framework/extension-api/display-component-extensions.tsx +0 -14
  36. package/src/lib/framework/extension-api/input-component-extensions.tsx +52 -34
  37. package/src/lib/framework/extension-api/logic/data-table.ts +4 -27
  38. package/src/lib/framework/extension-api/logic/form-components.ts +3 -2
  39. package/src/lib/framework/extension-api/types/detail-forms.ts +2 -38
  40. package/src/lib/framework/extension-api/types/form-components.ts +2 -4
  41. package/src/lib/framework/form-engine/custom-form-component-extensions.ts +0 -23
  42. package/src/lib/framework/form-engine/custom-form-component.tsx +8 -25
  43. package/src/lib/framework/form-engine/default-input-for-type.tsx +35 -0
  44. package/src/lib/framework/form-engine/form-control-adapter.tsx +192 -0
  45. package/src/lib/framework/form-engine/form-engine-types.ts +163 -0
  46. package/src/lib/framework/form-engine/form-schema-tools.ts +55 -71
  47. package/src/lib/framework/form-engine/overridden-form-component.tsx +2 -2
  48. package/src/lib/framework/form-engine/utils.ts +223 -0
  49. package/src/lib/{components/shared → framework/form-engine}/value-transformers.ts +9 -9
  50. package/src/lib/framework/registry/registry-types.ts +3 -5
  51. package/src/lib/graphql/graphql-env.d.ts +11 -7
  52. package/src/lib/index.ts +28 -1
  53. package/src/lib/providers/server-config.tsx +1 -0
  54. package/src/lib/components/shared/direct-form-component-map.tsx +0 -393
  55. package/src/lib/components/shared/universal-field-definition.ts +0 -118
  56. package/src/lib/components/shared/universal-form-input.tsx +0 -175
  57. package/src/lib/components/shared/universal-input-components.tsx +0 -291
  58. package/src/lib/framework/component-registry/dynamic-component.tsx +0 -58
@@ -1,291 +0,0 @@
1
- import React from 'react';
2
- import { ControllerRenderProps } from 'react-hook-form';
3
-
4
- import { AffixedInput } from '../data-input/affixed-input.js';
5
- import { DateTimeInput } from '../data-input/datetime-input.js';
6
- import { DefaultRelationInput } from '../data-input/default-relation-input.js';
7
- import { SelectWithOptions } from '../data-input/select-with-options.js';
8
- import { Input } from '../ui/input.js';
9
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select.js';
10
- import { Switch } from '../ui/switch.js';
11
- import { Textarea } from '../ui/textarea.js';
12
- import { UniversalFieldDefinition } from './universal-field-definition.js';
13
- import { ValueMode, transformValue } from './value-transformers.js';
14
-
15
- export interface UniversalInputComponentProps {
16
- fieldDef: UniversalFieldDefinition;
17
- field: ControllerRenderProps<any, any>;
18
- valueMode: ValueMode;
19
- disabled?: boolean;
20
- }
21
-
22
- // Component renderer interface for cleaner separation
23
- interface ComponentRendererProps {
24
- fieldDef: UniversalFieldDefinition;
25
- field: ControllerRenderProps<any, any>;
26
- valueMode: ValueMode;
27
- isReadonly: boolean;
28
- transformedValue: any;
29
- handleChange: (value: any) => void;
30
- handleNumericChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
31
- handleRegularNumericChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
32
- handleTextareaChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
33
- handleTextChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
34
- }
35
-
36
- /**
37
- * Renders relation input component
38
- */
39
- function renderRelationInput({ fieldDef, field, transformedValue, handleChange, isReadonly }: ComponentRendererProps) {
40
- if (fieldDef.type !== 'relation' || !fieldDef.entity) return null;
41
-
42
- return (
43
- <DefaultRelationInput
44
- fieldDef={{
45
- entity: fieldDef.entity,
46
- list: fieldDef.list,
47
- } as any}
48
- field={{
49
- ...field,
50
- value: transformedValue,
51
- onChange: handleChange,
52
- }}
53
- disabled={isReadonly}
54
- />
55
- );
56
- }
57
-
58
- /**
59
- * Renders string field with options as select dropdown
60
- */
61
- function renderSelectInput({ fieldDef, valueMode, transformedValue, handleChange, isReadonly, field }: ComponentRendererProps) {
62
- if (fieldDef.type !== 'string' || !fieldDef.ui?.options) return null;
63
-
64
- if (valueMode === 'json-string') {
65
- return (
66
- <Select value={transformedValue || ''} onValueChange={handleChange} disabled={isReadonly}>
67
- <SelectTrigger className="bg-background mb-0">
68
- <SelectValue placeholder="Select an option..." />
69
- </SelectTrigger>
70
- <SelectContent>
71
- {fieldDef.ui.options.map((option) => (
72
- <SelectItem key={option.value} value={option.value}>
73
- {typeof option.label === 'string'
74
- ? option.label
75
- : Array.isArray(option.label)
76
- ? option.label[0]?.value || option.value
77
- : option.value}
78
- </SelectItem>
79
- ))}
80
- </SelectContent>
81
- </Select>
82
- );
83
- }
84
-
85
- return (
86
- <SelectWithOptions
87
- field={{
88
- ...field,
89
- value: transformedValue,
90
- onChange: handleChange,
91
- }}
92
- options={fieldDef.ui.options as any}
93
- disabled={isReadonly}
94
- isListField={fieldDef.list}
95
- />
96
- );
97
- }
98
-
99
- /**
100
- * Renders numeric input components (int/float)
101
- */
102
- function renderNumericInput({ fieldDef, valueMode, transformedValue, handleNumericChange, handleRegularNumericChange, isReadonly, field }: ComponentRendererProps) {
103
- if (fieldDef.type !== 'int' && fieldDef.type !== 'float') return null;
104
-
105
- const isFloat = fieldDef.type === 'float';
106
- const min = fieldDef.ui?.min;
107
- const max = fieldDef.ui?.max;
108
- const step = fieldDef.ui?.step || (isFloat ? 0.01 : 1);
109
- const prefix = fieldDef.ui?.prefix;
110
- const suffix = fieldDef.ui?.suffix;
111
-
112
- const shouldUseAffixedInput = prefix || suffix || valueMode === 'json-string';
113
-
114
- if (shouldUseAffixedInput) {
115
- const numericValue = transformedValue !== undefined && transformedValue !== ''
116
- ? (typeof transformedValue === 'number' ? transformedValue : parseFloat(transformedValue) || '')
117
- : '';
118
-
119
- return (
120
- <AffixedInput
121
- type="number"
122
- value={numericValue}
123
- onChange={handleNumericChange}
124
- disabled={isReadonly}
125
- min={min}
126
- max={max}
127
- step={step}
128
- prefix={prefix}
129
- suffix={suffix}
130
- className="bg-background"
131
- />
132
- );
133
- }
134
-
135
- return (
136
- <Input
137
- type="number"
138
- value={transformedValue ?? ''}
139
- onChange={handleRegularNumericChange}
140
- onBlur={field.onBlur}
141
- name={field.name}
142
- disabled={isReadonly}
143
- min={min}
144
- max={max}
145
- step={step}
146
- />
147
- );
148
- }
149
-
150
- /**
151
- * Renders boolean input as switch
152
- */
153
- function renderBooleanInput({ fieldDef, valueMode, transformedValue, handleChange, isReadonly }: ComponentRendererProps) {
154
- if (fieldDef.type !== 'boolean') return null;
155
-
156
- const boolValue = valueMode === 'json-string'
157
- ? (transformedValue === true || transformedValue === 'true')
158
- : transformedValue;
159
-
160
- return (
161
- <Switch
162
- checked={boolValue}
163
- onCheckedChange={handleChange}
164
- disabled={isReadonly}
165
- />
166
- );
167
- }
168
-
169
- /**
170
- * Renders datetime input
171
- */
172
- function renderDateTimeInput({ fieldDef, transformedValue, handleChange, isReadonly }: ComponentRendererProps) {
173
- if (fieldDef.type !== 'datetime') return null;
174
-
175
- return (
176
- <DateTimeInput
177
- value={transformedValue}
178
- onChange={handleChange}
179
- disabled={isReadonly}
180
- />
181
- );
182
- }
183
-
184
- /**
185
- * Renders textarea for specific config args
186
- */
187
- function renderTextareaInput({ fieldDef, valueMode, transformedValue, handleTextareaChange, isReadonly }: ComponentRendererProps) {
188
- if (valueMode !== 'json-string' || fieldDef.ui?.component !== 'textarea-form-input') return null;
189
-
190
- return (
191
- <Textarea
192
- value={transformedValue || ''}
193
- onChange={handleTextareaChange}
194
- disabled={isReadonly}
195
- spellCheck={fieldDef.ui?.spellcheck ?? true}
196
- placeholder="Enter text..."
197
- rows={4}
198
- className="bg-background"
199
- />
200
- );
201
- }
202
-
203
- /**
204
- * Renders default text input
205
- */
206
- function renderTextInput({ valueMode, transformedValue, handleTextChange, isReadonly, field }: ComponentRendererProps) {
207
- return (
208
- <Input
209
- type="text"
210
- value={transformedValue ?? ''}
211
- onChange={handleTextChange}
212
- onBlur={field.onBlur}
213
- name={field.name}
214
- disabled={isReadonly}
215
- placeholder={valueMode === 'json-string' ? "Enter value..." : undefined}
216
- className={valueMode === 'json-string' ? "bg-background" : undefined}
217
- />
218
- );
219
- }
220
-
221
- /**
222
- * Consolidated input component for rendering form inputs based on field type
223
- * This replaces the duplicate implementations in custom fields and config args
224
- */
225
- export function UniversalInputComponent({
226
- fieldDef,
227
- field,
228
- valueMode,
229
- disabled = false,
230
- }: Readonly<UniversalInputComponentProps>) {
231
- const isReadonly = disabled || fieldDef.readonly;
232
-
233
- // Transform the field value for the component
234
- const transformedValue = React.useMemo(() => {
235
- return valueMode === 'json-string'
236
- ? transformValue(field.value, fieldDef, valueMode, 'parse')
237
- : field.value;
238
- }, [field.value, fieldDef, valueMode]);
239
-
240
- // Transform onChange handler for the component
241
- const handleChange = React.useCallback((newValue: any) => {
242
- const serializedValue = valueMode === 'json-string'
243
- ? transformValue(newValue, fieldDef, valueMode, 'serialize')
244
- : newValue;
245
- field.onChange(serializedValue);
246
- }, [field.onChange, fieldDef, valueMode]);
247
-
248
- // Pre-define all change handlers at the top level to follow Rules of Hooks
249
- const handleNumericChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
250
- const val = e.target.valueAsNumber;
251
- handleChange(isNaN(val) ? (valueMode === 'json-string' ? '' : undefined) : val);
252
- }, [handleChange, valueMode]);
253
-
254
- const handleRegularNumericChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
255
- const val = e.target.valueAsNumber;
256
- handleChange(isNaN(val) ? undefined : val);
257
- }, [handleChange]);
258
-
259
- const handleTextareaChange = React.useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
260
- handleChange(e.target.value);
261
- }, [handleChange]);
262
-
263
- const handleTextChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
264
- handleChange(e.target.value);
265
- }, [handleChange]);
266
-
267
- // Create props object for all renderers
268
- const rendererProps: ComponentRendererProps = {
269
- fieldDef,
270
- field,
271
- valueMode,
272
- isReadonly,
273
- transformedValue,
274
- handleChange,
275
- handleNumericChange,
276
- handleRegularNumericChange,
277
- handleTextareaChange,
278
- handleTextChange,
279
- };
280
-
281
- // Try each renderer in order, return the first match
282
- return (
283
- renderRelationInput(rendererProps) ||
284
- renderSelectInput(rendererProps) ||
285
- renderNumericInput(rendererProps) ||
286
- renderBooleanInput(rendererProps) ||
287
- renderDateTimeInput(rendererProps) ||
288
- renderTextareaInput(rendererProps) ||
289
- renderTextInput(rendererProps)
290
- );
291
- }
@@ -1,58 +0,0 @@
1
- import React from "react";
2
- import { useComponentRegistry } from "./component-registry.js";
3
-
4
- export type DisplayComponentProps<
5
- T extends keyof (typeof COMPONENT_REGISTRY)['dataDisplay'] | string,
6
- > = {
7
- id: T;
8
- value: any;
9
- // rest of the props are passed to the component
10
- [key: string]: any;
11
- }
12
-
13
-
14
- export type InputComponentProps<
15
- T extends keyof (typeof COMPONENT_REGISTRY)['dataInput'] | string,
16
- > = {
17
- id: T;
18
- value: any;
19
- // rest of the props are passed to the component
20
- [key: string]: any;
21
- }
22
-
23
- /**
24
- * @description
25
- * This component is used to delegate the rendering of a component to the component registry.
26
- *
27
- * @example
28
- * ```ts
29
- * <Delegate component="money.display.default" value={100} />
30
- * ```
31
- *
32
- * @returns
33
- */
34
- export function DisplayComponent<
35
- T extends keyof (typeof COMPONENT_REGISTRY)['dataDisplay'] | string,
36
- >(props: Readonly<DisplayComponentProps<T>>): React.ReactNode {
37
- const { getDisplayComponent } = useComponentRegistry();
38
- const Component = getDisplayComponent(props.id);
39
- if (!Component) {
40
- throw new Error(`Component with id ${props.id} not found`);
41
- }
42
- const { value, ...rest } = props;
43
- return <Component value={value} {...rest} />;
44
- }
45
-
46
- export function InputComponent<
47
- T extends keyof (typeof COMPONENT_REGISTRY)['dataInput'] | string,
48
- >(props: Readonly<InputComponentProps<T>>): React.ReactNode {
49
- const { getInputComponent } = useComponentRegistry();
50
- const Component = getInputComponent(props.id);
51
- if (!Component) {
52
- throw new Error(`Component with id ${props.id} not found`);
53
- }
54
- const { value, onChange, ...rest } = props;
55
- return <Component value={value} onChange={onChange} {...rest} />;
56
- }
57
-
58
-