@pdfme/ui 5.3.11-dev.9 → 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 +8359 -8310
- package/dist/index.umd.js +114 -114
- package/dist/types/src/contexts.d.ts +1 -1
- package/package.json +3 -3
- package/src/components/AppContextProvider.tsx +8 -2
- package/src/components/Designer/Canvas/Moveable.tsx +8 -4
- package/src/components/Designer/Canvas/Selecto.tsx +4 -1
- package/src/components/Designer/Canvas/index.tsx +50 -18
- package/src/components/Designer/PluginIcon.tsx +10 -9
- package/src/components/Designer/RightSidebar/DetailView/AlignWidget.tsx +77 -66
- package/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.tsx +5 -6
- package/src/components/Designer/RightSidebar/DetailView/index.tsx +147 -68
- package/src/components/Designer/RightSidebar/ListView/Item.tsx +89 -91
- package/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.tsx +18 -17
- package/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.tsx +16 -15
- package/src/components/Designer/index.tsx +1 -1
- package/src/components/Preview.tsx +1 -1
- package/src/components/Renderer.tsx +2 -2
- package/src/contexts.ts +1 -1
- package/src/helper.ts +34 -29
@@ -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
|
);
|
@@ -102,22 +109,17 @@ const DetailView = (props: DetailViewProps) => {
|
|
102
109
|
// Reference to a function that validates schema name uniqueness
|
103
110
|
const uniqueSchemaName = useRef(
|
104
111
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
105
|
-
(_unused: string): boolean => true
|
112
|
+
(_unused: string): boolean => true,
|
106
113
|
);
|
107
114
|
|
108
115
|
// Use proper type for validator function parameter
|
109
|
-
const validateUniqueSchemaName = (
|
110
|
-
|
111
|
-
value: string
|
112
|
-
): boolean => uniqueSchemaName.current(value);
|
116
|
+
const validateUniqueSchemaName = (_: unknown, value: string): boolean =>
|
117
|
+
uniqueSchemaName.current(value);
|
113
118
|
|
114
119
|
// Use explicit type for debounce function that matches the expected signature
|
115
|
-
const handleWatch = debounce(function(...args: unknown[]) {
|
120
|
+
const handleWatch = debounce(function (...args: unknown[]) {
|
116
121
|
const formSchema = args[0] as Record<string, unknown>;
|
117
|
-
const formAndSchemaValuesDiffer = (
|
118
|
-
formValue: unknown,
|
119
|
-
schemaValue: unknown
|
120
|
-
): boolean => {
|
122
|
+
const formAndSchemaValuesDiffer = (formValue: unknown, schemaValue: unknown): boolean => {
|
121
123
|
if (typeof formValue === 'object' && formValue !== null) {
|
122
124
|
return JSON.stringify(formValue) !== JSON.stringify(schemaValue);
|
123
125
|
}
|
@@ -170,18 +172,19 @@ const DetailView = (props: DetailViewProps) => {
|
|
170
172
|
}, 100);
|
171
173
|
|
172
174
|
// Find the active plugin with proper type safety
|
173
|
-
const activePlugin = Object.values(pluginsRegistry).find(
|
174
|
-
(plugin)
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
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
|
+
});
|
185
188
|
|
186
189
|
// Safely access the propPanel schema
|
187
190
|
const activePropPanelSchema = activePlugin?.propPanel?.schema;
|
@@ -191,32 +194,77 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
191
194
|
}
|
192
195
|
|
193
196
|
// Create type-safe options for the type dropdown
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
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]) => {
|
198
202
|
// Skip invalid plugins
|
199
|
-
if (!value || typeof value !== 'object')
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
+
|
203
222
|
// Safely extract the type
|
204
223
|
const defaultSchema = value.propPanel.defaultSchema as Record<string, unknown>;
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
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 });
|
210
231
|
});
|
232
|
+
// Create a safe empty schema as fallback
|
233
|
+
const emptySchema: Record<string, unknown> = {};
|
234
|
+
|
211
235
|
// Safely access the default schema with proper null checking
|
212
|
-
const defaultSchema = activePlugin?.propPanel?.defaultSchema
|
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
|
+
}
|
213
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
|
214
262
|
const propPanelSchema: PropPanelSchema = {
|
215
263
|
type: 'object',
|
216
264
|
column: 2,
|
217
265
|
properties: {
|
218
266
|
type: {
|
219
|
-
title:
|
267
|
+
title: typedI18n('type'),
|
220
268
|
type: 'string',
|
221
269
|
widget: 'select',
|
222
270
|
props: { options: typeOptions },
|
@@ -224,32 +272,32 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
224
272
|
span: 12,
|
225
273
|
},
|
226
274
|
name: {
|
227
|
-
title:
|
275
|
+
title: typedI18n('fieldName'),
|
228
276
|
type: 'string',
|
229
277
|
required: true,
|
230
278
|
span: 12,
|
231
279
|
rules: [
|
232
280
|
{
|
233
281
|
validator: validateUniqueSchemaName,
|
234
|
-
message:
|
282
|
+
message: typedI18n('validation.uniqueName'),
|
235
283
|
},
|
236
284
|
],
|
237
285
|
props: { autoComplete: 'off' },
|
238
286
|
},
|
239
287
|
editable: {
|
240
|
-
title:
|
288
|
+
title: typedI18n('editable'),
|
241
289
|
type: 'boolean',
|
242
290
|
span: 8,
|
243
|
-
hidden: typeof
|
291
|
+
hidden: typeof defaultSchema.readOnly !== 'undefined',
|
244
292
|
},
|
245
293
|
required: {
|
246
|
-
title:
|
294
|
+
title: typedI18n('required'),
|
247
295
|
type: 'boolean',
|
248
296
|
span: 16,
|
249
297
|
hidden: '{{!formData.editable}}',
|
250
298
|
},
|
251
299
|
'-': { type: 'void', widget: 'Divider' },
|
252
|
-
align: { title:
|
300
|
+
align: { title: typedI18n('align'), type: 'void', widget: 'AlignWidget' },
|
253
301
|
position: {
|
254
302
|
type: 'object',
|
255
303
|
widget: 'card',
|
@@ -259,7 +307,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
259
307
|
},
|
260
308
|
},
|
261
309
|
width: {
|
262
|
-
title:
|
310
|
+
title: typedI18n('width'),
|
263
311
|
type: 'number',
|
264
312
|
widget: 'inputNumber',
|
265
313
|
required: true,
|
@@ -267,7 +315,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
267
315
|
props: { min: 0 },
|
268
316
|
},
|
269
317
|
height: {
|
270
|
-
title:
|
318
|
+
title: typedI18n('height'),
|
271
319
|
type: 'number',
|
272
320
|
widget: 'inputNumber',
|
273
321
|
required: true,
|
@@ -275,48 +323,79 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
275
323
|
props: { min: 0 },
|
276
324
|
},
|
277
325
|
rotate: {
|
278
|
-
title:
|
326
|
+
title: typedI18n('rotate'),
|
279
327
|
type: 'number',
|
280
328
|
widget: 'inputNumber',
|
281
|
-
disabled: typeof
|
329
|
+
disabled: typeof defaultSchema.rotate === 'undefined',
|
282
330
|
max: 360,
|
283
331
|
props: { min: 0 },
|
284
332
|
span: 6,
|
285
333
|
},
|
286
334
|
opacity: {
|
287
|
-
title:
|
335
|
+
title: typedI18n('opacity'),
|
288
336
|
type: 'number',
|
289
337
|
widget: 'inputNumber',
|
290
|
-
disabled: typeof
|
338
|
+
disabled: typeof defaultSchema.opacity === 'undefined',
|
291
339
|
props: { step: 0.1, min: 0, max: 1 },
|
292
340
|
span: 6,
|
293
341
|
},
|
294
342
|
},
|
295
343
|
};
|
296
344
|
|
345
|
+
// Create a safe copy of the properties
|
346
|
+
const safeProperties = { ...propPanelSchema.properties };
|
347
|
+
|
297
348
|
if (typeof activePropPanelSchema === 'function') {
|
298
349
|
// Create a new object without the schemasList property
|
299
|
-
const { size, schemas, pageSize, changeSchemas, activeElements, deselectSchema, activeSchema } =
|
300
|
-
|
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
|
+
};
|
301
361
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
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
|
309
378
|
propPanelSchema.properties = {
|
310
|
-
...
|
311
|
-
...(
|
312
|
-
...apps,
|
379
|
+
...safeProperties,
|
380
|
+
...(dividerObj as Record<string, Partial<Schema>>),
|
381
|
+
...(apps as Record<string, Partial<Schema>>),
|
313
382
|
};
|
314
383
|
} else {
|
315
|
-
|
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
|
316
395
|
propPanelSchema.properties = {
|
317
|
-
...
|
318
|
-
...(
|
319
|
-
...apps,
|
396
|
+
...safeProperties,
|
397
|
+
...(dividerObj as Record<string, Partial<Schema>>),
|
398
|
+
...(apps as Record<string, Partial<Schema>>),
|
320
399
|
};
|
321
400
|
}
|
322
401
|
|
@@ -335,7 +414,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
335
414
|
icon={<Menu strokeWidth={1.5} size={20} />}
|
336
415
|
/>
|
337
416
|
<Text strong style={{ textAlign: 'center', width: '100%' }}>
|
338
|
-
{
|
417
|
+
{typedI18n('editField')}
|
339
418
|
</Text>
|
340
419
|
</div>
|
341
420
|
<Divider style={{ marginTop: token.marginXS, marginBottom: token.marginXS }} />
|
@@ -47,111 +47,109 @@ interface Props {
|
|
47
47
|
// Using TypeScript interface for prop validation instead of PropTypes
|
48
48
|
const Item = React.memo(
|
49
49
|
/* eslint-disable react/prop-types */
|
50
|
-
React.forwardRef<HTMLLIElement, Props>(
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
) {
|
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
|
+
) {
|
77
76
|
/* eslint-enable react/prop-types */
|
78
|
-
|
77
|
+
const i18n = useContext(I18nContext);
|
79
78
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
useEffect(() => {
|
80
|
+
if (!dragOverlay) {
|
81
|
+
return;
|
82
|
+
}
|
84
83
|
|
85
|
-
|
84
|
+
document.body.style.cursor = 'grabbing';
|
86
85
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
return () => {
|
87
|
+
document.body.style.cursor = '';
|
88
|
+
};
|
89
|
+
}, [dragOverlay]);
|
91
90
|
|
92
|
-
|
91
|
+
const { x, y, scaleX, scaleY } = transform || { x: 0, y: 0, scaleX: 1, scaleY: 1 };
|
93
92
|
|
94
|
-
|
95
|
-
|
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
|
96
105
|
style={{
|
97
|
-
|
98
|
-
|
99
|
-
|
106
|
+
display: 'flex',
|
107
|
+
alignItems: 'center',
|
108
|
+
cursor: 'pointer',
|
109
|
+
gap: '0.5rem',
|
110
|
+
...style,
|
100
111
|
}}
|
101
|
-
|
102
|
-
|
103
|
-
ref={ref}
|
112
|
+
{...props}
|
113
|
+
onClick={() => onClick && onClick()}
|
104
114
|
>
|
105
|
-
<
|
115
|
+
<Button
|
116
|
+
{...listeners}
|
106
117
|
style={{
|
107
118
|
display: 'flex',
|
108
119
|
alignItems: 'center',
|
109
|
-
|
110
|
-
|
111
|
-
|
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%',
|
112
134
|
}}
|
113
|
-
{
|
114
|
-
onClick={() => onClick && onClick()}
|
135
|
+
title={title || ''}
|
115
136
|
>
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
whiteSpace: 'nowrap',
|
133
|
-
textOverflow: 'ellipsis',
|
134
|
-
width: '100%',
|
135
|
-
}}
|
136
|
-
title={title || ''}
|
137
|
-
>
|
138
|
-
{status === undefined ? (
|
139
|
-
value
|
140
|
-
) : (
|
141
|
-
<span style={{ display: 'flex', alignItems: 'center' }}>
|
142
|
-
<CircleAlert size={15} style={{ marginRight: '0.25rem' }} />
|
143
|
-
{status === 'is-warning' ? i18n('noKeyName') : value}
|
144
|
-
{status === 'is-danger' ? i18n('notUniq') : ''}
|
145
|
-
</span>
|
146
|
-
)}
|
147
|
-
</Text>
|
148
|
-
{readOnly && <Lock size={15} style={{ marginRight: '0.5rem' }} />}
|
149
|
-
{required && <span style={{ color: 'red', marginRight: '0.5rem' }}>*</span>}
|
150
|
-
</div>
|
151
|
-
</li>
|
152
|
-
);
|
153
|
-
},
|
154
|
-
),
|
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
|
+
}),
|
155
153
|
);
|
156
154
|
|
157
155
|
// Set display name for debugging
|
@@ -62,27 +62,28 @@ const SelectableSortableContainer = (
|
|
62
62
|
// Get schema by ID or use directly
|
63
63
|
const thisSchema =
|
64
64
|
typeof inSchema === 'string' ? schemas.find((schema) => schema.id === inSchema) : inSchema;
|
65
|
-
|
65
|
+
|
66
66
|
if (!thisSchema) return <></>;
|
67
|
-
|
67
|
+
|
68
68
|
// Safely extract schema type
|
69
69
|
const schemaType = typeof thisSchema.type === 'string' ? thisSchema.type : '';
|
70
|
-
|
70
|
+
|
71
71
|
// Find matching plugin with type-safe approach
|
72
|
-
const pluginEntry = Object.entries(pluginsRegistry).find(
|
73
|
-
(
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
+
|
86
87
|
const [pluginLabel, activePlugin] = pluginEntry || ['', undefined];
|
87
88
|
|
88
89
|
if (!activePlugin) {
|
@@ -44,22 +44,23 @@ const SelectableSortableItem = ({
|
|
44
44
|
|
45
45
|
// Safely extract schema type
|
46
46
|
const schemaType = typeof schema.type === 'string' ? schema.type : '';
|
47
|
-
|
47
|
+
|
48
48
|
// Find matching plugin with type-safe approach
|
49
|
-
const pluginEntry = Object.entries(pluginsRegistry).find(
|
50
|
-
(
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
+
|
63
64
|
const [pluginLabel, thisPlugin] = pluginEntry || ['', undefined];
|
64
65
|
|
65
66
|
let status: undefined | 'is-warning' | 'is-danger';
|
@@ -20,7 +20,7 @@ import { FontContext } from '../contexts.js';
|
|
20
20
|
import { template2SchemasList, getPagesScrollTopByIndex, useMaxZoom } from '../helper.js';
|
21
21
|
import { theme } from 'antd';
|
22
22
|
|
23
|
-
const _cache = new Map();
|
23
|
+
const _cache = new Map<string | number, unknown>();
|
24
24
|
|
25
25
|
const Preview = ({
|
26
26
|
template,
|