@syncfusion/ej2-react-form-renderer 0.1.0-beta

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 (48) hide show
  1. package/README.md +148 -0
  2. package/index.d.ts +6 -0
  3. package/index.js +6 -0
  4. package/license +13 -0
  5. package/package.json +49 -0
  6. package/src/CheckboxGroup.d.ts +12 -0
  7. package/src/CheckboxGroup.js +48 -0
  8. package/src/CustomTabComponent.d.ts +13 -0
  9. package/src/CustomTabComponent.js +35 -0
  10. package/src/DataGridComponent.d.ts +29 -0
  11. package/src/DataGridComponent.js +160 -0
  12. package/src/FormRenderer.d.ts +63 -0
  13. package/src/FormRenderer.js +567 -0
  14. package/src/FormValidator.d.ts +479 -0
  15. package/src/FormValidator.js +579 -0
  16. package/src/StaticHtmlRenderer.d.ts +8 -0
  17. package/src/StaticHtmlRenderer.js +21 -0
  18. package/src/index.d.ts +6 -0
  19. package/src/index.js +6 -0
  20. package/src/json-converter.d.ts +170 -0
  21. package/src/json-converter.js +1180 -0
  22. package/src/parser.d.ts +99 -0
  23. package/src/parser.js +749 -0
  24. package/src/renderFormField.d.ts +19 -0
  25. package/src/renderFormField.js +202 -0
  26. package/src/types/FormSchema.d.ts +177 -0
  27. package/src/types/FormSchema.js +1 -0
  28. package/src/utils.js +60 -0
  29. package/styles/bootstrap-dark.css +26 -0
  30. package/styles/bootstrap.css +26 -0
  31. package/styles/bootstrap4.css +26 -0
  32. package/styles/bootstrap5-dark.css +26 -0
  33. package/styles/bootstrap5.3-dark.css +26 -0
  34. package/styles/bootstrap5.3.css +26 -0
  35. package/styles/bootstrap5.css +26 -0
  36. package/styles/fluent-dark.css +26 -0
  37. package/styles/fluent.css +26 -0
  38. package/styles/fluent2-dark.css +26 -0
  39. package/styles/fluent2.css +26 -0
  40. package/styles/form-renderer.base.css +473 -0
  41. package/styles/material-dark.css +26 -0
  42. package/styles/material.css +26 -0
  43. package/styles/material3-dark.css +26 -0
  44. package/styles/material3.css +26 -0
  45. package/styles/tailwind-dark.css +26 -0
  46. package/styles/tailwind.css +26 -0
  47. package/styles/tailwind3-dark.css +10 -0
  48. package/styles/tailwind3.css +26 -0
@@ -0,0 +1,579 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import { forwardRef, useEffect, useCallback, useRef, useImperativeHandle, createContext } from 'react';
4
+ import { L10n } from '@syncfusion/ej2-base';
5
+ export const VALIDATION_REGEX = {
6
+ EMAIL: /^(?!.*\.\.)[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/,
7
+ // eslint-disable-next-line security/detect-unsafe-regex
8
+ URL: /^(https?:\/\/)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(\/[^\s]*)?$/,
9
+ DATE_ISO: /^([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/,
10
+ DIGITS: /^[0-9]*$/,
11
+ PHONE: /^[+]?[0-9]{9,13}$/,
12
+ CREDIT_CARD: /^\d{13,16}$/
13
+ };
14
+ const FormContext = createContext(null);
15
+ const FormProvider = FormContext.Provider;
16
+ /**
17
+ * Provides a form component with built-in validation functionality. Manages form state tracking,
18
+ * field validation, and submission handling.
19
+ *
20
+ * ```typescript
21
+ * import { Form, FormField, FormState } from '@syncfusion/react-inputs';
22
+ *
23
+ * const [formState, setFormState] = useState<FormState>();
24
+ *
25
+ * <Form
26
+ * rules={{ username: { required: [true, 'Username is required'] } }}
27
+ * onSubmit={data => console.log(data)}
28
+ * onFormStateChange={setFormState} >
29
+ * <FormField name="username">
30
+ * <input
31
+ * name="username"
32
+ * value={(formState?.values.username || '') as string}
33
+ * onChange={(e) => formState?.onChange('username', { value: e.target.value })}
34
+ * onBlur={() => formState?.onBlur('username')}
35
+ * onFocus={() => formState?.onFocus('username')}
36
+ * />
37
+ * {formState?.errors?.username && (<div className="error">{formState.errors.username}</div>)}
38
+ * </FormField>
39
+ * <button type="submit">Submit</button>
40
+ * </Form>
41
+ * ```
42
+ */
43
+ export const Form = forwardRef((props, ref) => {
44
+ const { rules, onSubmit, onReset, children, onFormStateChange, initialValues = {}, validateOnChange = false, className = '', ...otherProps } = props;
45
+ const formRef = useRef(null);
46
+ const stateRef = useRef({
47
+ values: { ...initialValues },
48
+ errors: {},
49
+ touched: {},
50
+ visited: {},
51
+ modified: {},
52
+ submitted: false,
53
+ validated: {}
54
+ });
55
+ const notifyStateChange = useCallback(() => {
56
+ if (onFormStateChange) {
57
+ formStateRef.current = getFormState();
58
+ onFormStateChange(formStateRef.current);
59
+ }
60
+ }, [onFormStateChange]);
61
+ const setFieldValue = useCallback((field, value) => {
62
+ stateRef.current = {
63
+ ...stateRef.current,
64
+ values: {
65
+ ...stateRef.current.values,
66
+ [field]: value
67
+ },
68
+ modified: {
69
+ ...stateRef.current.modified,
70
+ [field]: true
71
+ }
72
+ };
73
+ }, []);
74
+ const setFieldTouched = useCallback((field) => {
75
+ stateRef.current = {
76
+ ...stateRef.current,
77
+ touched: {
78
+ ...stateRef.current.touched,
79
+ [field]: true
80
+ }
81
+ };
82
+ }, []);
83
+ const setFieldVisited = useCallback((field) => {
84
+ stateRef.current = {
85
+ ...stateRef.current,
86
+ visited: {
87
+ ...stateRef.current.visited,
88
+ [field]: true
89
+ }
90
+ };
91
+ }, []);
92
+ const setFieldError = useCallback((field, error) => {
93
+ const errors = { ...stateRef.current.errors };
94
+ if (error) {
95
+ errors[field] = error;
96
+ }
97
+ else {
98
+ delete errors[field];
99
+ }
100
+ stateRef.current = {
101
+ ...stateRef.current,
102
+ errors
103
+ };
104
+ }, []);
105
+ const setSubmitted = useCallback((value) => {
106
+ stateRef.current = {
107
+ ...stateRef.current,
108
+ submitted: value
109
+ };
110
+ }, []);
111
+ const resetForm = useCallback((values) => {
112
+ stateRef.current = {
113
+ values,
114
+ errors: {},
115
+ touched: {},
116
+ visited: {},
117
+ modified: {},
118
+ submitted: false,
119
+ validated: {}
120
+ };
121
+ notifyStateChange();
122
+ }, [notifyStateChange]);
123
+ const touchAllFields = useCallback(() => {
124
+ const allTouched = {};
125
+ Object.keys(stateRef.current.values).forEach((field) => {
126
+ allTouched[field] = true;
127
+ });
128
+ stateRef.current = {
129
+ ...stateRef.current,
130
+ touched: allTouched
131
+ };
132
+ }, []);
133
+ const visitAllFields = useCallback(() => {
134
+ const allVisited = {};
135
+ Object.keys(stateRef.current.values).forEach((field) => {
136
+ allVisited[field] = true;
137
+ });
138
+ stateRef.current = {
139
+ ...stateRef.current,
140
+ visited: allVisited
141
+ };
142
+ }, []);
143
+ const setBulkErrors = useCallback((errors) => {
144
+ const newErrors = { ...stateRef.current.errors };
145
+ Object.entries(errors).forEach(([field, error]) => {
146
+ if (error) {
147
+ newErrors[field] = error;
148
+ }
149
+ else {
150
+ delete newErrors[field];
151
+ }
152
+ });
153
+ stateRef.current = {
154
+ ...stateRef.current,
155
+ errors: newErrors
156
+ };
157
+ notifyStateChange();
158
+ }, [notifyStateChange]);
159
+ const rulesRef = useRef(rules);
160
+ const fieldLevelRulesRef = useRef({});
161
+ const formStateRef = useRef(null);
162
+ const l10nRef = useRef(null);
163
+ const defaultErrorMessages = {
164
+ required: 'This field is required.',
165
+ email: 'Please enter a valid email address.',
166
+ url: 'Please enter a valid URL.',
167
+ date: 'Please enter a valid date.',
168
+ dateIso: 'Please enter a valid date (ISO).',
169
+ creditCard: 'Please enter valid card number.',
170
+ number: 'Please enter a valid number.',
171
+ digits: 'Please enter only digits.',
172
+ maxLength: 'Please enter no more than {0} characters.',
173
+ minLength: 'Please enter at least {0} characters.',
174
+ rangeLength: 'Please enter a value between {0} and {1} characters long.',
175
+ range: 'Please enter a value between {0} and {1}.',
176
+ max: 'Please enter a value less than or equal to {0}.',
177
+ min: 'Please enter a value greater than or equal to {0}.',
178
+ regex: 'Please enter a correct value.',
179
+ tel: 'Please enter a valid phone number.',
180
+ equalTo: 'Please enter the same value again.'
181
+ };
182
+ const registeredFields = useRef({});
183
+ const registerField = (fieldName, rules) => {
184
+ registeredFields.current[fieldName] = true;
185
+ if (rules) {
186
+ fieldLevelRulesRef.current[fieldName] = rules;
187
+ }
188
+ };
189
+ const getMergedRulesForField = (fieldName) => {
190
+ const formLevelRules = rulesRef.current[fieldName];
191
+ const fieldLevelRules = fieldLevelRulesRef.current[fieldName];
192
+ if (!formLevelRules && !fieldLevelRules) {
193
+ return undefined;
194
+ }
195
+ return {
196
+ ...formLevelRules,
197
+ ...fieldLevelRules
198
+ };
199
+ };
200
+ const getAllFieldNames = () => {
201
+ const names = new Set([
202
+ ...Object.keys(rulesRef.current || {}),
203
+ ...Object.keys(fieldLevelRulesRef.current || {})
204
+ ]);
205
+ return Array.from(names);
206
+ };
207
+ useEffect(() => {
208
+ l10nRef.current = new L10n('formValidator', defaultErrorMessages);
209
+ return () => {
210
+ l10nRef.current = null;
211
+ };
212
+ }, []);
213
+ useEffect(() => {
214
+ notifyStateChange();
215
+ validateInitialValues();
216
+ return () => {
217
+ l10nRef.current = null;
218
+ rulesRef.current = {};
219
+ fieldLevelRulesRef.current = {};
220
+ registeredFields.current = {};
221
+ if (formRef.current) {
222
+ formRef.current = null;
223
+ }
224
+ formStateRef.current = null;
225
+ };
226
+ }, []);
227
+ useEffect(() => {
228
+ rulesRef.current = rules;
229
+ }, [rules]);
230
+ const validateInitialValues = () => {
231
+ if (Object.keys(initialValues).length > 0) {
232
+ const errors = {};
233
+ for (const fieldName in initialValues) {
234
+ if (Object.prototype.hasOwnProperty.call(initialValues, fieldName) &&
235
+ Object.prototype.hasOwnProperty.call(rulesRef.current, fieldName)) {
236
+ const error = validateFieldValue(fieldName, initialValues[fieldName]);
237
+ if (error) {
238
+ errors[fieldName] = error;
239
+ }
240
+ else {
241
+ errors[fieldName] = null;
242
+ }
243
+ }
244
+ }
245
+ if (Object.keys(errors).length > 0) {
246
+ setBulkErrors(errors);
247
+ }
248
+ }
249
+ };
250
+ const formatErrorMessage = (ruleName, params) => {
251
+ let formattedMessage = l10nRef.current?.getConstant(ruleName);
252
+ if (Array.isArray(params)) {
253
+ params.forEach((value, index) => {
254
+ const placeholder = `{${index}}`;
255
+ if (formattedMessage.includes(placeholder)) {
256
+ formattedMessage = formattedMessage.replace(placeholder, String(value));
257
+ }
258
+ });
259
+ }
260
+ else {
261
+ formattedMessage = formattedMessage.replace('{0}', String(params));
262
+ }
263
+ return formattedMessage;
264
+ };
265
+ const validateCreditCard = (value) => {
266
+ if (!VALIDATION_REGEX.CREDIT_CARD.test(value)) {
267
+ return false;
268
+ }
269
+ const cardNumber = value.replace(/[\s-]/g, '');
270
+ let sum = 0;
271
+ let shouldDouble = false;
272
+ for (let i = cardNumber.length - 1; i >= 0; i--) {
273
+ let digit = parseInt(cardNumber.charAt(i), 10);
274
+ if (shouldDouble) {
275
+ digit *= 2;
276
+ if (digit > 9) {
277
+ digit -= 9;
278
+ }
279
+ }
280
+ sum += digit;
281
+ shouldDouble = !shouldDouble;
282
+ }
283
+ return (sum % 10) === 0;
284
+ };
285
+ const validateFieldValue = (fieldName, value) => {
286
+ const fieldRules = getMergedRulesForField(fieldName);
287
+ if (!fieldRules || !registeredFields.current[fieldName]) {
288
+ return null;
289
+ }
290
+ const isValueEmpty = value === undefined || value === null || value.toString().trim() === '';
291
+ const isRequired = fieldRules.required != null && fieldRules.required[0] !== false;
292
+ if (isValueEmpty && !isRequired) {
293
+ return null;
294
+ }
295
+ for (const ruleName in fieldRules) {
296
+ if (Object.prototype.hasOwnProperty.call(fieldRules, ruleName)) {
297
+ const ruleValue = fieldRules[ruleName];
298
+ if (!ruleValue) {
299
+ continue;
300
+ }
301
+ let isValid = true;
302
+ let param = null;
303
+ let errorMessage;
304
+ if (ruleName === 'customValidator' && typeof ruleValue === 'function') {
305
+ const customError = ruleValue(value);
306
+ if (customError) {
307
+ return customError;
308
+ }
309
+ continue;
310
+ }
311
+ if (Array.isArray(ruleValue)) {
312
+ param = ruleValue[0];
313
+ errorMessage = ruleValue[1];
314
+ if (ruleName === 'required' && param === false) {
315
+ continue;
316
+ }
317
+ }
318
+ if (ruleName !== 'required' && (value === '' || value === null || value === undefined)) {
319
+ continue;
320
+ }
321
+ switch (ruleName) {
322
+ case 'required':
323
+ isValid = !isValueEmpty;
324
+ break;
325
+ case 'email':
326
+ isValid = VALIDATION_REGEX.EMAIL.test(value);
327
+ break;
328
+ case 'url':
329
+ isValid = VALIDATION_REGEX.URL.test(value);
330
+ break;
331
+ case 'date':
332
+ isValid = !isNaN(Date.parse(value));
333
+ break;
334
+ case 'dateIso':
335
+ isValid = VALIDATION_REGEX.DATE_ISO.test(value);
336
+ break;
337
+ case 'number':
338
+ isValid = !isNaN(Number(value)) && String(value).indexOf(' ') === -1;
339
+ break;
340
+ case 'digits':
341
+ isValid = VALIDATION_REGEX.DIGITS.test(value);
342
+ break;
343
+ case 'creditCard':
344
+ isValid = validateCreditCard(value);
345
+ break;
346
+ case 'minLength':
347
+ isValid = String(value).length >= Number(param);
348
+ break;
349
+ case 'maxLength':
350
+ isValid = String(value).length <= Number(param);
351
+ break;
352
+ case 'rangeLength':
353
+ if (Array.isArray(param)) {
354
+ isValid = String(value).length >= param[0] && String(value).length <= param[1];
355
+ }
356
+ break;
357
+ case 'min':
358
+ isValid = Number(value) >= Number(param);
359
+ break;
360
+ case 'max':
361
+ isValid = Number(value) <= Number(param);
362
+ break;
363
+ case 'range':
364
+ if (Array.isArray(param)) {
365
+ isValid = Number(value) >= param[0] && Number(value) <= param[1];
366
+ }
367
+ break;
368
+ case 'regex':
369
+ if (param instanceof RegExp) {
370
+ isValid = param.test(value);
371
+ }
372
+ else if (typeof param === 'string') {
373
+ // eslint-disable-next-line security/detect-non-literal-regexp
374
+ isValid = new RegExp(param).test(value);
375
+ }
376
+ break;
377
+ case 'tel':
378
+ isValid = VALIDATION_REGEX.PHONE.test(value);
379
+ break;
380
+ case 'equalTo':
381
+ if (typeof param === 'string') {
382
+ isValid = value === stateRef.current.values[param];
383
+ }
384
+ break;
385
+ }
386
+ if (!isValid) {
387
+ if (errorMessage) {
388
+ return errorMessage;
389
+ }
390
+ else {
391
+ return formatErrorMessage(ruleName, param);
392
+ }
393
+ }
394
+ }
395
+ }
396
+ return null;
397
+ };
398
+ const validateForm = () => {
399
+ const errors = {};
400
+ const fields = getAllFieldNames();
401
+ for (const field of fields) {
402
+ const error = validateFieldValue(field, stateRef.current.values[field]);
403
+ if (!stateRef.current.values[field]) {
404
+ setFieldValue(field, stateRef.current.values[field]);
405
+ }
406
+ if (error) {
407
+ errors[field] = error;
408
+ }
409
+ }
410
+ return errors;
411
+ };
412
+ const validate = () => {
413
+ const formErrors = validateForm();
414
+ for (const field in formErrors) {
415
+ if (Object.prototype.hasOwnProperty.call(formErrors, field)) {
416
+ setFieldError(field, formErrors[field]);
417
+ }
418
+ }
419
+ const fields = getAllFieldNames();
420
+ for (const field of fields) {
421
+ if (!formErrors[field]) {
422
+ setFieldError(field, null);
423
+ }
424
+ }
425
+ if (Object.keys(formErrors).length === 0) {
426
+ stateRef.current = {
427
+ ...stateRef.current,
428
+ errors: {},
429
+ touched: {},
430
+ visited: {},
431
+ modified: {},
432
+ submitted: false,
433
+ validated: {}
434
+ };
435
+ }
436
+ notifyStateChange();
437
+ return Object.keys(formErrors).length === 0;
438
+ };
439
+ const handleSubmit = (event) => {
440
+ event?.preventDefault();
441
+ const isValid = validate();
442
+ touchAllFields();
443
+ visitAllFields();
444
+ setSubmitted(true);
445
+ notifyStateChange();
446
+ if (isValid) {
447
+ onSubmit?.(stateRef.current.values);
448
+ }
449
+ };
450
+ const handleChange = (name, { value }) => {
451
+ setFieldValue(name, value);
452
+ if (validateOnChange) {
453
+ const error = validateFieldValue(name, value);
454
+ setFieldError(name, error);
455
+ }
456
+ notifyStateChange();
457
+ };
458
+ const handleBlur = (fieldName) => {
459
+ setFieldTouched(fieldName);
460
+ const error = validateFieldValue(fieldName, stateRef.current.values[fieldName]);
461
+ setFieldError(fieldName, error);
462
+ notifyStateChange();
463
+ };
464
+ const handleFormReset = (args) => {
465
+ resetForm({ ...initialValues });
466
+ onReset?.(args);
467
+ };
468
+ const reset = () => {
469
+ handleFormReset();
470
+ };
471
+ const getFormState = () => {
472
+ const state = stateRef.current;
473
+ const fields = getAllFieldNames();
474
+ return {
475
+ values: state.values,
476
+ errors: state.errors,
477
+ submitted: state.submitted,
478
+ touched: state.touched,
479
+ visited: state.visited,
480
+ modified: state.modified,
481
+ valid: fields.reduce((acc, fieldName) => {
482
+ acc[fieldName] = !state.errors[fieldName];
483
+ return acc;
484
+ }, {}),
485
+ allowSubmit: Object.keys(state.errors).length === 0,
486
+ onChange: handleChange,
487
+ onBlur: handleBlur,
488
+ onFocus: handleFocus,
489
+ onFormReset: handleFormReset,
490
+ onSubmit: handleSubmit,
491
+ fieldNames: Object.keys(registeredFields.current).reduce((acc, fieldName) => {
492
+ acc[fieldName] = fieldName;
493
+ return acc;
494
+ }, {})
495
+ };
496
+ };
497
+ const validateField = (fieldName) => {
498
+ const error = validateFieldValue(fieldName, stateRef.current.values[fieldName]);
499
+ setFieldError(fieldName, error);
500
+ notifyStateChange();
501
+ return !error;
502
+ };
503
+ const publicAPI = React.useMemo(() => ({
504
+ rules,
505
+ initialValues,
506
+ validateOnChange
507
+ }), [rules, initialValues, validateOnChange]);
508
+ useImperativeHandle(ref, () => ({
509
+ ...publicAPI,
510
+ validate,
511
+ reset,
512
+ validateField,
513
+ element: formRef.current
514
+ }), [publicAPI]);
515
+ const formClassName = React.useMemo(() => {
516
+ return [
517
+ 'sf-control sf-form-validator',
518
+ className
519
+ ].filter(Boolean).join(' ');
520
+ }, [className]);
521
+ const handleFocus = (fieldName) => {
522
+ setFieldVisited(fieldName);
523
+ notifyStateChange();
524
+ };
525
+ const formContextValue = {
526
+ registerField: registerField
527
+ };
528
+ return (_jsx(FormProvider, { value: formContextValue, children: _jsx("form", { ref: formRef, className: formClassName, onSubmit: handleSubmit, onReset: handleFormReset, noValidate: true, ...otherProps, children: children }) }));
529
+ });
530
+ Form.displayName = 'Form';
531
+ /**
532
+ * Specifies a component that connects form inputs with validation rules. The FormField component provides
533
+ * an easy way to integrate form controls with the Form validation system, handling state management and
534
+ * validation automatically.
535
+ *
536
+ * ```typescript
537
+ * const [formState, setFormState] = useState<FormState>();
538
+ *
539
+ * <Form
540
+ * rules={{
541
+ * username: { required: [true, 'Username is required'] }
542
+ * }}
543
+ * onSubmit={data => console.log(data)}
544
+ * onFormStateChange={setFormState}
545
+ * >
546
+ * <FormField name="username">
547
+ * <input
548
+ * name="username"
549
+ * value={formState?.values.username || ''}
550
+ * onChange={(e) => formState?.onChange('username', { value: e.target.value })}
551
+ * onBlur={() => formState?.onBlur('username')}
552
+ * onFocus={() => formState?.onFocus('username')}
553
+ * />
554
+ * {formState?.touched?.username && formState?.errors?.username && (
555
+ * <div className="error">{formState.errors.username}</div>
556
+ * )}
557
+ * </FormField>
558
+ * <button type="submit">Submit</button>
559
+ * </Form>
560
+ * ```
561
+ *
562
+ * @param {IFormFieldProps} props - Specifies the form field configuration properties
563
+ * @returns {React.ReactNode} - Returns the children with access to form validation context
564
+ */
565
+ export const FormField = (props) => {
566
+ const { name, children, rules } = props;
567
+ if (!name) {
568
+ return null;
569
+ }
570
+ const formContext = React.useContext(FormContext);
571
+ if (!formContext) {
572
+ return null;
573
+ }
574
+ React.useEffect(() => {
575
+ formContext?.registerField?.(name, rules);
576
+ }, [name, rules, formContext]);
577
+ return _jsx(_Fragment, { children: children });
578
+ };
579
+ FormField.displayName = 'FormField';
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export interface StaticHtmlRendererProps {
3
+ content: string;
4
+ id?: string;
5
+ enableHtmlSanitizer?: boolean;
6
+ }
7
+ export declare const StaticHtmlRenderer: React.FC<StaticHtmlRendererProps>;
8
+ export default StaticHtmlRenderer;
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { SanitizeHtmlHelper } from '@syncfusion/ej2-base';
3
+ export const StaticHtmlRenderer = ({ content, id, enableHtmlSanitizer }) => {
4
+ const sanitizedHtml = React.useMemo(() => {
5
+ try {
6
+ if (enableHtmlSanitizer) {
7
+ return SanitizeHtmlHelper.sanitize(content);
8
+ }
9
+ return content;
10
+ }
11
+ catch (error) {
12
+ console.error('HTML sanitization error:', error);
13
+ return '';
14
+ }
15
+ }, [content]);
16
+ return React.createElement('div', {
17
+ id,
18
+ dangerouslySetInnerHTML: { __html: sanitizedHtml }
19
+ });
20
+ };
21
+ export default StaticHtmlRenderer;
package/src/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @syncfusion/ej2-react-form-renderer
3
+ * Form Renderer Component - Dynamic JSON-driven forms
4
+ */
5
+
6
+ export { FormRenderer, FormLayout, FormRendererProps, ChangeEventArgs, SubmitEventArgs, UISchema, DataSchema } from './FormRenderer.js';
package/src/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @syncfusion/ej2-react-form-renderer
3
+ * Form Renderer Component - Dynamic JSON-driven forms
4
+ */
5
+
6
+ export { FormRenderer, FormLayout } from './FormRenderer.js';