@pdfme/ui 5.3.11 → 5.3.12-dev.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.
- package/dist/index.es.js +9116 -8977
- package/dist/index.umd.js +125 -125
- package/dist/types/src/components/Designer/Canvas/Guides.d.ts +3 -9
- package/dist/types/src/components/Designer/Canvas/Moveable.d.ts +2 -49
- package/dist/types/src/components/Designer/Canvas/Selecto.d.ts +5 -16
- package/dist/types/src/components/Designer/PluginIcon.d.ts +2 -2
- package/dist/types/src/components/Designer/RightSidebar/ListView/Item.d.ts +17 -0
- package/dist/types/src/components/Renderer.d.ts +1 -10
- package/dist/types/src/constants.d.ts +1 -1
- package/dist/types/src/contexts.d.ts +1 -1
- package/dist/types/src/helper.d.ts +3 -4
- package/package.json +3 -3
- package/src/components/AppContextProvider.tsx +23 -10
- package/src/components/CtlBar.tsx +2 -2
- package/src/components/Designer/Canvas/Guides.tsx +4 -13
- package/src/components/Designer/Canvas/Moveable.tsx +21 -76
- package/src/components/Designer/Canvas/Selecto.tsx +12 -24
- package/src/components/Designer/Canvas/index.tsx +51 -72
- package/src/components/Designer/LeftSidebar.tsx +2 -2
- package/src/components/Designer/PluginIcon.tsx +15 -3
- package/src/components/Designer/RightSidebar/DetailView/AlignWidget.tsx +105 -19
- package/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.tsx +14 -11
- package/src/components/Designer/RightSidebar/DetailView/index.tsx +170 -48
- package/src/components/Designer/RightSidebar/ListView/Item.tsx +114 -88
- package/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.tsx +23 -3
- package/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.tsx +21 -4
- package/src/components/Designer/index.tsx +14 -9
- package/src/components/Preview.tsx +5 -5
- package/src/components/Renderer.tsx +43 -37
- package/src/components/Root.tsx +1 -1
- package/src/constants.ts +1 -1
- package/src/contexts.ts +1 -1
- package/src/helper.ts +136 -38
- package/src/types/react-guides.d.ts +0 -22
- package/src/types/react-selecto.d.ts +0 -35
@@ -1,11 +1,12 @@
|
|
1
1
|
import { useForm } from 'form-render';
|
2
2
|
import React, { useRef, useContext, useState, useEffect } from 'react';
|
3
3
|
import type {
|
4
|
-
ChangeSchemaItem,
|
5
4
|
Dict,
|
5
|
+
ChangeSchemaItem,
|
6
6
|
SchemaForUI,
|
7
7
|
PropPanelWidgetProps,
|
8
8
|
PropPanelSchema,
|
9
|
+
Schema,
|
9
10
|
} from '@pdfme/common';
|
10
11
|
import type { SidebarProps } from '../../../../types.js';
|
11
12
|
import { Menu } from 'lucide-react';
|
@@ -45,6 +46,12 @@ const DetailView = (props: DetailViewProps) => {
|
|
45
46
|
const pluginsRegistry = useContext(PluginsRegistry);
|
46
47
|
const options = useContext(OptionsContext);
|
47
48
|
|
49
|
+
// Define a type-safe i18n function that accepts string keys
|
50
|
+
const typedI18n = (key: string): string => {
|
51
|
+
// Use a type assertion to handle the union type constraint
|
52
|
+
return typeof i18n === 'function' ? i18n(key as keyof Dict) : key;
|
53
|
+
};
|
54
|
+
|
48
55
|
const [widgets, setWidgets] = useState<{
|
49
56
|
[key: string]: (props: PropPanelWidgetProps) => React.JSX.Element;
|
50
57
|
}>({});
|
@@ -66,7 +73,7 @@ const DetailView = (props: DetailViewProps) => {
|
|
66
73
|
{...props}
|
67
74
|
options={options}
|
68
75
|
theme={token}
|
69
|
-
i18n={
|
76
|
+
i18n={typedI18n}
|
70
77
|
widget={widgetValue}
|
71
78
|
/>
|
72
79
|
);
|
@@ -76,8 +83,11 @@ const DetailView = (props: DetailViewProps) => {
|
|
76
83
|
}, [activeSchema, pluginsRegistry, JSON.stringify(options)]);
|
77
84
|
|
78
85
|
useEffect(() => {
|
79
|
-
|
80
|
-
values
|
86
|
+
// Create a type-safe copy of the schema with editable property
|
87
|
+
const values: Record<string, unknown> = { ...activeSchema };
|
88
|
+
// Safely access and set properties
|
89
|
+
const readOnly = typeof values.readOnly === 'boolean' ? values.readOnly : false;
|
90
|
+
values.editable = !readOnly;
|
81
91
|
form.setValues(values);
|
82
92
|
}, [activeSchema, form]);
|
83
93
|
|
@@ -96,14 +106,21 @@ const DetailView = (props: DetailViewProps) => {
|
|
96
106
|
};
|
97
107
|
}, [schemasList, activeSchema]);
|
98
108
|
|
99
|
-
|
109
|
+
// Reference to a function that validates schema name uniqueness
|
110
|
+
const uniqueSchemaName = useRef(
|
111
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
112
|
+
(_unused: string): boolean => true,
|
113
|
+
);
|
100
114
|
|
101
|
-
|
115
|
+
// Use proper type for validator function parameter
|
116
|
+
const validateUniqueSchemaName = (_: unknown, value: string): boolean =>
|
102
117
|
uniqueSchemaName.current(value);
|
103
118
|
|
104
|
-
|
105
|
-
|
106
|
-
|
119
|
+
// Use explicit type for debounce function that matches the expected signature
|
120
|
+
const handleWatch = debounce(function (...args: unknown[]) {
|
121
|
+
const formSchema = args[0] as Record<string, unknown>;
|
122
|
+
const formAndSchemaValuesDiffer = (formValue: unknown, schemaValue: unknown): boolean => {
|
123
|
+
if (typeof formValue === 'object' && formValue !== null) {
|
107
124
|
return JSON.stringify(formValue) !== JSON.stringify(schemaValue);
|
108
125
|
}
|
109
126
|
return formValue !== schemaValue;
|
@@ -114,7 +131,7 @@ const DetailView = (props: DetailViewProps) => {
|
|
114
131
|
if (['id', 'content'].includes(key)) continue;
|
115
132
|
|
116
133
|
let value = formSchema[key];
|
117
|
-
if (formAndSchemaValuesDiffer(value, (activeSchema as
|
134
|
+
if (formAndSchemaValuesDiffer(value, (activeSchema as Record<string, unknown>)[key])) {
|
118
135
|
// FIXME memo: https://github.com/pdfme/pdfme/pull/367#issuecomment-1857468274
|
119
136
|
if (value === null && ['rotate', 'opacity'].includes(key)) {
|
120
137
|
value = undefined;
|
@@ -154,28 +171,100 @@ const DetailView = (props: DetailViewProps) => {
|
|
154
171
|
}
|
155
172
|
}, 100);
|
156
173
|
|
157
|
-
|
158
|
-
|
159
|
-
|
174
|
+
// Find the active plugin with proper type safety
|
175
|
+
const activePlugin = Object.values(pluginsRegistry).find((plugin) => {
|
176
|
+
if (!plugin || typeof plugin !== 'object') return false;
|
177
|
+
if (!plugin.propPanel || typeof plugin.propPanel !== 'object') return false;
|
178
|
+
if (!plugin.propPanel.defaultSchema || typeof plugin.propPanel.defaultSchema !== 'object')
|
179
|
+
return false;
|
180
|
+
|
181
|
+
const defaultSchema = plugin.propPanel.defaultSchema as Record<string, unknown>;
|
182
|
+
return (
|
183
|
+
'type' in defaultSchema &&
|
184
|
+
typeof defaultSchema.type === 'string' &&
|
185
|
+
defaultSchema.type === activeSchema.type
|
186
|
+
);
|
187
|
+
});
|
160
188
|
|
161
|
-
|
189
|
+
// Safely access the propPanel schema
|
190
|
+
const activePropPanelSchema = activePlugin?.propPanel?.schema;
|
162
191
|
if (!activePropPanelSchema) {
|
163
192
|
console.error(`[@pdfme/ui] No propPanel.schema for ${activeSchema.type}.
|
164
193
|
Check this document: https://pdfme.com/docs/custom-schemas`);
|
165
194
|
}
|
166
195
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
196
|
+
// Create type-safe options for the type dropdown
|
197
|
+
// Create a type-safe options array for the dropdown
|
198
|
+
const typeOptions: Array<{ label: string; value: string | undefined }> = [];
|
199
|
+
|
200
|
+
// Safely populate the options array
|
201
|
+
Object.entries(pluginsRegistry).forEach(([label, value]) => {
|
202
|
+
// Skip invalid plugins
|
203
|
+
if (!value || typeof value !== 'object') {
|
204
|
+
typeOptions.push({ label, value: undefined });
|
205
|
+
return;
|
206
|
+
}
|
207
|
+
|
208
|
+
if (!('propPanel' in value) || !value.propPanel || typeof value.propPanel !== 'object') {
|
209
|
+
typeOptions.push({ label, value: undefined });
|
210
|
+
return;
|
211
|
+
}
|
212
|
+
|
213
|
+
if (
|
214
|
+
!('defaultSchema' in value.propPanel) ||
|
215
|
+
!value.propPanel.defaultSchema ||
|
216
|
+
typeof value.propPanel.defaultSchema !== 'object'
|
217
|
+
) {
|
218
|
+
typeOptions.push({ label, value: undefined });
|
219
|
+
return;
|
220
|
+
}
|
221
|
+
|
222
|
+
// Safely extract the type
|
223
|
+
const defaultSchema = value.propPanel.defaultSchema as Record<string, unknown>;
|
224
|
+
let schemaType: string | undefined = undefined;
|
225
|
+
|
226
|
+
if ('type' in defaultSchema && typeof defaultSchema.type === 'string') {
|
227
|
+
schemaType = defaultSchema.type;
|
228
|
+
}
|
229
|
+
|
230
|
+
typeOptions.push({ label, value: schemaType });
|
231
|
+
});
|
232
|
+
// Create a safe empty schema as fallback
|
233
|
+
const emptySchema: Record<string, unknown> = {};
|
172
234
|
|
235
|
+
// Safely access the default schema with proper null checking
|
236
|
+
const defaultSchema: Record<string, unknown> = activePlugin?.propPanel?.defaultSchema
|
237
|
+
? // Create a safe copy of the schema
|
238
|
+
(() => {
|
239
|
+
// First check if the defaultSchema is an object
|
240
|
+
if (
|
241
|
+
typeof activePlugin.propPanel.defaultSchema !== 'object' ||
|
242
|
+
activePlugin.propPanel.defaultSchema === null
|
243
|
+
) {
|
244
|
+
return emptySchema;
|
245
|
+
}
|
246
|
+
|
247
|
+
// Create a safe copy
|
248
|
+
const result: Record<string, unknown> = {};
|
249
|
+
|
250
|
+
// Only copy properties that exist on the object
|
251
|
+
for (const key in activePlugin.propPanel.defaultSchema) {
|
252
|
+
if (Object.prototype.hasOwnProperty.call(activePlugin.propPanel.defaultSchema, key)) {
|
253
|
+
result[key] = (activePlugin.propPanel.defaultSchema as Record<string, unknown>)[key];
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
return result;
|
258
|
+
})()
|
259
|
+
: emptySchema;
|
260
|
+
|
261
|
+
// Create a type-safe schema object
|
173
262
|
const propPanelSchema: PropPanelSchema = {
|
174
263
|
type: 'object',
|
175
264
|
column: 2,
|
176
265
|
properties: {
|
177
266
|
type: {
|
178
|
-
title:
|
267
|
+
title: typedI18n('type'),
|
179
268
|
type: 'string',
|
180
269
|
widget: 'select',
|
181
270
|
props: { options: typeOptions },
|
@@ -183,32 +272,32 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
183
272
|
span: 12,
|
184
273
|
},
|
185
274
|
name: {
|
186
|
-
title:
|
275
|
+
title: typedI18n('fieldName'),
|
187
276
|
type: 'string',
|
188
277
|
required: true,
|
189
278
|
span: 12,
|
190
279
|
rules: [
|
191
280
|
{
|
192
281
|
validator: validateUniqueSchemaName,
|
193
|
-
message:
|
282
|
+
message: typedI18n('validation.uniqueName'),
|
194
283
|
},
|
195
284
|
],
|
196
285
|
props: { autoComplete: 'off' },
|
197
286
|
},
|
198
287
|
editable: {
|
199
|
-
title:
|
288
|
+
title: typedI18n('editable'),
|
200
289
|
type: 'boolean',
|
201
290
|
span: 8,
|
202
|
-
hidden: defaultSchema
|
291
|
+
hidden: typeof defaultSchema.readOnly !== 'undefined',
|
203
292
|
},
|
204
293
|
required: {
|
205
|
-
title:
|
294
|
+
title: typedI18n('required'),
|
206
295
|
type: 'boolean',
|
207
296
|
span: 16,
|
208
297
|
hidden: '{{!formData.editable}}',
|
209
298
|
},
|
210
299
|
'-': { type: 'void', widget: 'Divider' },
|
211
|
-
align: { title:
|
300
|
+
align: { title: typedI18n('align'), type: 'void', widget: 'AlignWidget' },
|
212
301
|
position: {
|
213
302
|
type: 'object',
|
214
303
|
widget: 'card',
|
@@ -218,7 +307,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
218
307
|
},
|
219
308
|
},
|
220
309
|
width: {
|
221
|
-
title:
|
310
|
+
title: typedI18n('width'),
|
222
311
|
type: 'number',
|
223
312
|
widget: 'inputNumber',
|
224
313
|
required: true,
|
@@ -226,7 +315,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
226
315
|
props: { min: 0 },
|
227
316
|
},
|
228
317
|
height: {
|
229
|
-
title:
|
318
|
+
title: typedI18n('height'),
|
230
319
|
type: 'number',
|
231
320
|
widget: 'inputNumber',
|
232
321
|
required: true,
|
@@ -234,46 +323,79 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
234
323
|
props: { min: 0 },
|
235
324
|
},
|
236
325
|
rotate: {
|
237
|
-
title:
|
326
|
+
title: typedI18n('rotate'),
|
238
327
|
type: 'number',
|
239
328
|
widget: 'inputNumber',
|
240
|
-
disabled: defaultSchema
|
329
|
+
disabled: typeof defaultSchema.rotate === 'undefined',
|
241
330
|
max: 360,
|
242
331
|
props: { min: 0 },
|
243
332
|
span: 6,
|
244
333
|
},
|
245
334
|
opacity: {
|
246
|
-
title:
|
335
|
+
title: typedI18n('opacity'),
|
247
336
|
type: 'number',
|
248
337
|
widget: 'inputNumber',
|
249
|
-
disabled: defaultSchema
|
338
|
+
disabled: typeof defaultSchema.opacity === 'undefined',
|
250
339
|
props: { step: 0.1, min: 0, max: 1 },
|
251
340
|
span: 6,
|
252
341
|
},
|
253
342
|
},
|
254
343
|
};
|
255
344
|
|
345
|
+
// Create a safe copy of the properties
|
346
|
+
const safeProperties = { ...propPanelSchema.properties };
|
347
|
+
|
256
348
|
if (typeof activePropPanelSchema === 'function') {
|
257
|
-
|
349
|
+
// Create a new object without the schemasList property
|
350
|
+
const { size, schemas, pageSize, changeSchemas, activeElements, deselectSchema, activeSchema } =
|
351
|
+
props;
|
352
|
+
const propPanelProps = {
|
353
|
+
size,
|
354
|
+
schemas,
|
355
|
+
pageSize,
|
356
|
+
changeSchemas,
|
357
|
+
activeElements,
|
358
|
+
deselectSchema,
|
359
|
+
activeSchema,
|
360
|
+
};
|
258
361
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
362
|
+
// Use the typedI18n function to avoid type issues
|
363
|
+
const functionResult = activePropPanelSchema({
|
364
|
+
...propPanelProps,
|
365
|
+
options,
|
366
|
+
theme: token,
|
367
|
+
i18n: typedI18n,
|
368
|
+
});
|
369
|
+
|
370
|
+
// Safely handle the result
|
371
|
+
const apps = functionResult && typeof functionResult === 'object' ? functionResult : {};
|
372
|
+
|
373
|
+
// Create a divider if needed
|
374
|
+
const dividerObj =
|
375
|
+
Object.keys(apps).length === 0 ? {} : { '--': { type: 'void', widget: 'Divider' } };
|
376
|
+
|
377
|
+
// Assign properties safely - use type assertion to satisfy TypeScript
|
266
378
|
propPanelSchema.properties = {
|
267
|
-
...
|
268
|
-
...(
|
269
|
-
...apps,
|
379
|
+
...safeProperties,
|
380
|
+
...(dividerObj as Record<string, Partial<Schema>>),
|
381
|
+
...(apps as Record<string, Partial<Schema>>),
|
270
382
|
};
|
271
383
|
} else {
|
272
|
-
|
384
|
+
// Handle non-function case
|
385
|
+
const apps =
|
386
|
+
activePropPanelSchema && typeof activePropPanelSchema === 'object'
|
387
|
+
? activePropPanelSchema
|
388
|
+
: {};
|
389
|
+
|
390
|
+
// Create a divider if needed
|
391
|
+
const dividerObj =
|
392
|
+
Object.keys(apps).length === 0 ? {} : { '--': { type: 'void', widget: 'Divider' } };
|
393
|
+
|
394
|
+
// Assign properties safely - use type assertion to satisfy TypeScript
|
273
395
|
propPanelSchema.properties = {
|
274
|
-
...
|
275
|
-
...(
|
276
|
-
...apps,
|
396
|
+
...safeProperties,
|
397
|
+
...(dividerObj as Record<string, Partial<Schema>>),
|
398
|
+
...(apps as Record<string, Partial<Schema>>),
|
277
399
|
};
|
278
400
|
}
|
279
401
|
|
@@ -292,7 +414,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
292
414
|
icon={<Menu strokeWidth={1.5} size={20} />}
|
293
415
|
/>
|
294
416
|
<Text strong style={{ textAlign: 'center', width: '100%' }}>
|
295
|
-
{
|
417
|
+
{typedI18n('editField')}
|
296
418
|
</Text>
|
297
419
|
</div>
|
298
420
|
<Divider style={{ marginTop: token.marginXS, marginBottom: token.marginXS }} />
|
@@ -6,127 +6,153 @@ import { Button, Typography } from 'antd';
|
|
6
6
|
|
7
7
|
const { Text } = Typography;
|
8
8
|
|
9
|
+
// Define prop types for Item component
|
9
10
|
interface Props {
|
11
|
+
/** Content to display in the item */
|
10
12
|
value: React.ReactNode;
|
13
|
+
/** Optional icon to display */
|
11
14
|
icon?: React.ReactNode;
|
15
|
+
/** Custom styles for the item */
|
12
16
|
style?: React.CSSProperties;
|
17
|
+
/** Status indicator for the item */
|
13
18
|
status?: 'is-warning' | 'is-danger';
|
19
|
+
/** Title attribute for the item */
|
14
20
|
title?: string;
|
21
|
+
/** Whether the item is required */
|
15
22
|
required?: boolean;
|
23
|
+
/** Whether the item is read-only */
|
16
24
|
readOnly?: boolean;
|
25
|
+
/** Whether the item is being dragged as an overlay */
|
17
26
|
dragOverlay?: boolean;
|
27
|
+
/** Click handler for the item */
|
18
28
|
onClick?: () => void;
|
29
|
+
/** Mouse enter handler */
|
19
30
|
onMouseEnter?: () => void;
|
31
|
+
/** Mouse leave handler */
|
20
32
|
onMouseLeave?: () => void;
|
33
|
+
/** Whether the item is currently being dragged */
|
21
34
|
dragging?: boolean;
|
35
|
+
/** Whether items are being sorted */
|
22
36
|
sorting?: boolean;
|
37
|
+
/** CSS transition value */
|
23
38
|
transition?: string;
|
39
|
+
/** Transform data for the item */
|
24
40
|
transform?: { x: number; y: number; scaleX: number; scaleY: number } | null;
|
41
|
+
/** Whether to fade the item in */
|
25
42
|
fadeIn?: boolean;
|
43
|
+
/** Drag listeners from dnd-kit */
|
26
44
|
listeners?: DraggableSyntheticListeners;
|
27
45
|
}
|
46
|
+
// Using React.memo and forwardRef for optimized rendering
|
47
|
+
// Using TypeScript interface for prop validation instead of PropTypes
|
28
48
|
const Item = React.memo(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
/* eslint-disable react/prop-types */
|
50
|
+
React.forwardRef<HTMLLIElement, Props>(function Item(
|
51
|
+
{
|
52
|
+
icon,
|
53
|
+
value,
|
54
|
+
status,
|
55
|
+
title,
|
56
|
+
required,
|
57
|
+
readOnly,
|
58
|
+
style,
|
59
|
+
dragOverlay,
|
60
|
+
onClick,
|
61
|
+
onMouseEnter,
|
62
|
+
onMouseLeave,
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
64
|
+
dragging,
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
66
|
+
fadeIn,
|
67
|
+
listeners,
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
69
|
+
sorting,
|
70
|
+
transition,
|
71
|
+
transform,
|
72
|
+
...props
|
73
|
+
},
|
74
|
+
ref,
|
75
|
+
) {
|
76
|
+
/* eslint-enable react/prop-types */
|
77
|
+
const i18n = useContext(I18nContext);
|
54
78
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
79
|
+
useEffect(() => {
|
80
|
+
if (!dragOverlay) {
|
81
|
+
return;
|
82
|
+
}
|
59
83
|
|
60
|
-
|
84
|
+
document.body.style.cursor = 'grabbing';
|
61
85
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
86
|
+
return () => {
|
87
|
+
document.body.style.cursor = '';
|
88
|
+
};
|
89
|
+
}, [dragOverlay]);
|
66
90
|
|
67
|
-
|
91
|
+
const { x, y, scaleX, scaleY } = transform || { x: 0, y: 0, scaleX: 1, scaleY: 1 };
|
68
92
|
|
69
|
-
|
70
|
-
|
93
|
+
return (
|
94
|
+
<li
|
95
|
+
style={{
|
96
|
+
marginTop: 10,
|
97
|
+
transition,
|
98
|
+
transform: `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`,
|
99
|
+
}}
|
100
|
+
onMouseEnter={onMouseEnter}
|
101
|
+
onMouseLeave={onMouseLeave}
|
102
|
+
ref={ref}
|
103
|
+
>
|
104
|
+
<div
|
71
105
|
style={{
|
72
|
-
|
73
|
-
|
74
|
-
|
106
|
+
display: 'flex',
|
107
|
+
alignItems: 'center',
|
108
|
+
cursor: 'pointer',
|
109
|
+
gap: '0.5rem',
|
110
|
+
...style,
|
75
111
|
}}
|
76
|
-
|
77
|
-
|
78
|
-
ref={ref}
|
112
|
+
{...props}
|
113
|
+
onClick={() => onClick && onClick()}
|
79
114
|
>
|
80
|
-
<
|
115
|
+
<Button
|
116
|
+
{...listeners}
|
81
117
|
style={{
|
82
118
|
display: 'flex',
|
83
119
|
alignItems: 'center',
|
84
|
-
|
85
|
-
|
86
|
-
|
120
|
+
background: 'none',
|
121
|
+
boxShadow: 'none',
|
122
|
+
border: 'none',
|
123
|
+
paddingLeft: '0.25rem',
|
124
|
+
}}
|
125
|
+
icon={<GripVertical size={15} style={{ cursor: 'grab' }} />}
|
126
|
+
/>
|
127
|
+
{icon}
|
128
|
+
<Text
|
129
|
+
style={{
|
130
|
+
overflow: 'hidden',
|
131
|
+
whiteSpace: 'nowrap',
|
132
|
+
textOverflow: 'ellipsis',
|
133
|
+
width: '100%',
|
87
134
|
}}
|
88
|
-
{
|
89
|
-
onClick={() => onClick && onClick()}
|
135
|
+
title={title || ''}
|
90
136
|
>
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
whiteSpace: 'nowrap',
|
108
|
-
textOverflow: 'ellipsis',
|
109
|
-
width: '100%',
|
110
|
-
}}
|
111
|
-
title={title || ''}
|
112
|
-
>
|
113
|
-
{status === undefined ? (
|
114
|
-
value
|
115
|
-
) : (
|
116
|
-
<span style={{ display: 'flex', alignItems: 'center' }}>
|
117
|
-
<CircleAlert size={15} style={{ marginRight: '0.25rem' }} />
|
118
|
-
{status === 'is-warning' ? i18n('noKeyName') : value}
|
119
|
-
{status === 'is-danger' ? i18n('notUniq') : ''}
|
120
|
-
</span>
|
121
|
-
)}
|
122
|
-
</Text>
|
123
|
-
{readOnly && <Lock size={15} style={{ marginRight: '0.5rem' }} />}
|
124
|
-
{required && <span style={{ color: 'red', marginRight: '0.5rem' }}>*</span>}
|
125
|
-
</div>
|
126
|
-
</li>
|
127
|
-
);
|
128
|
-
},
|
129
|
-
),
|
137
|
+
{status === undefined ? (
|
138
|
+
value
|
139
|
+
) : (
|
140
|
+
<span style={{ display: 'flex', alignItems: 'center' }}>
|
141
|
+
<CircleAlert size={15} style={{ marginRight: '0.25rem' }} />
|
142
|
+
{status === 'is-warning' ? i18n('noKeyName') : value}
|
143
|
+
{status === 'is-danger' ? i18n('notUniq') : ''}
|
144
|
+
</span>
|
145
|
+
)}
|
146
|
+
</Text>
|
147
|
+
{readOnly && <Lock size={15} style={{ marginRight: '0.5rem' }} />}
|
148
|
+
{required && <span style={{ color: 'red', marginRight: '0.5rem' }}>*</span>}
|
149
|
+
</div>
|
150
|
+
</li>
|
151
|
+
);
|
152
|
+
}),
|
130
153
|
);
|
131
154
|
|
155
|
+
// Set display name for debugging
|
156
|
+
Item.displayName = 'Item';
|
157
|
+
|
132
158
|
export default Item;
|
@@ -59,12 +59,32 @@ const SelectableSortableContainer = (
|
|
59
59
|
};
|
60
60
|
|
61
61
|
const getPluginIcon = (inSchema: string | SchemaForUI): ReactNode => {
|
62
|
+
// Get schema by ID or use directly
|
62
63
|
const thisSchema =
|
63
64
|
typeof inSchema === 'string' ? schemas.find((schema) => schema.id === inSchema) : inSchema;
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
if (!thisSchema) return <></>;
|
67
|
+
|
68
|
+
// Safely extract schema type
|
69
|
+
const schemaType = typeof thisSchema.type === 'string' ? thisSchema.type : '';
|
70
|
+
|
71
|
+
// Find matching plugin with type-safe approach
|
72
|
+
const pluginEntry = Object.entries(pluginsRegistry).find(([, plugin]) => {
|
73
|
+
if (!plugin || typeof plugin !== 'object') return false;
|
74
|
+
if (!plugin.propPanel || typeof plugin.propPanel !== 'object') return false;
|
75
|
+
if (!plugin.propPanel.defaultSchema || typeof plugin.propPanel.defaultSchema !== 'object')
|
76
|
+
return false;
|
77
|
+
|
78
|
+
// Use Record<string, unknown> to safely access properties
|
79
|
+
const defaultSchema = plugin.propPanel.defaultSchema as Record<string, unknown>;
|
80
|
+
return (
|
81
|
+
'type' in defaultSchema &&
|
82
|
+
typeof defaultSchema.type === 'string' &&
|
83
|
+
defaultSchema.type === schemaType
|
84
|
+
);
|
85
|
+
});
|
86
|
+
|
87
|
+
const [pluginLabel, activePlugin] = pluginEntry || ['', undefined];
|
68
88
|
|
69
89
|
if (!activePlugin) {
|
70
90
|
return <></>;
|
@@ -39,12 +39,29 @@ const SelectableSortableItem = ({
|
|
39
39
|
|
40
40
|
const newListeners = {
|
41
41
|
...listeners,
|
42
|
-
onClick: (event:
|
42
|
+
onClick: (event: React.MouseEvent) => onSelect(schema.id, event.shiftKey),
|
43
43
|
};
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
// Safely extract schema type
|
46
|
+
const schemaType = typeof schema.type === 'string' ? schema.type : '';
|
47
|
+
|
48
|
+
// Find matching plugin with type-safe approach
|
49
|
+
const pluginEntry = Object.entries(pluginsRegistry).find(([, plugin]) => {
|
50
|
+
if (!plugin || typeof plugin !== 'object') return false;
|
51
|
+
if (!plugin.propPanel || typeof plugin.propPanel !== 'object') return false;
|
52
|
+
if (!plugin.propPanel.defaultSchema || typeof plugin.propPanel.defaultSchema !== 'object')
|
53
|
+
return false;
|
54
|
+
|
55
|
+
// Use Record<string, unknown> to safely access properties
|
56
|
+
const defaultSchema = plugin.propPanel.defaultSchema as Record<string, unknown>;
|
57
|
+
return (
|
58
|
+
'type' in defaultSchema &&
|
59
|
+
typeof defaultSchema.type === 'string' &&
|
60
|
+
defaultSchema.type === schemaType
|
61
|
+
);
|
62
|
+
});
|
63
|
+
|
64
|
+
const [pluginLabel, thisPlugin] = pluginEntry || ['', undefined];
|
48
65
|
|
49
66
|
let status: undefined | 'is-warning' | 'is-danger';
|
50
67
|
if (!schema.name) {
|