@syncfusion/ej2-react-form-renderer 0.1.0-beta → 0.1.1-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.
@@ -33,14 +33,14 @@ const normalizeAttributes = (attributes) => {
33
33
  /**
34
34
  * Renders a single form field component
35
35
  */
36
- export const renderFormField = ({ component, value, onChange, onBlur, ref, hasError = false, onClick }) => {
36
+ export const renderFormField = ({ component, value, onChange, onBlur, ref, hasError = false, onClick, locale }) => {
37
37
  const commonProps = {
38
38
  floatLabelType: (component.floatLabelType || 'Never'),
39
39
  placeholder: component.placeholder || '',
40
40
  enabled: !component.disabled,
41
41
  };
42
42
  const createValidationHandlers = (getValue) => {
43
- const validateOn = component.validateOn || 'Blur';
43
+ const validateOn = component.validateOn || 'Change';
44
44
  const handlers = {};
45
45
  // If validateOn is 'Change' or undefined, add change and blur handlers
46
46
  if (!validateOn || validateOn === 'Change') {
@@ -56,45 +56,45 @@ export const renderFormField = ({ component, value, onChange, onBlur, ref, hasEr
56
56
  };
57
57
  const htmlAttrs = normalizeAttributes(component.htmlAttributes);
58
58
  const errorClass = hasError ? 'e-error' : '';
59
- const cssClass = `${component.cssClass || ''} ${errorClass}`.trim();
59
+ const cssClass = `${component.cssClass || ''} ${errorClass} ${component.size === 'Small' ? ' e-small' : component.size === 'Bigger' ? ' e-bigger' : ''}`.trim();
60
60
  switch (component.type) {
61
61
  case 'textbox':
62
- return (_jsx(TextBoxComponent, { id: component.id, type: component.multiline ? 'hidden' : component.textboxType ? component.textboxType : 'text', name: component.id, ...commonProps, value: value !== undefined ? value : (component.defaultValue || ''), multiline: component.multiline, showClearButton: component.showClearButton, autocomplete: component.autocomplete === false ? 'off' : 'on', readonly: component.readOnly || false, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
62
+ return (_jsx(TextBoxComponent, { id: component.id, type: component.multiline ? 'hidden' : component.textboxType ? component.textboxType : 'text', name: component.id, locale: locale, ...commonProps, value: value !== undefined ? value : (component.defaultValue || ''), multiline: component.multiline, showClearButton: component.showClearButton, autocomplete: component.autocomplete === false ? 'off' : 'on', readonly: component.readOnly || false, cssClass: cssClass, htmlAttributes: htmlAttrs, appendTemplate: component.suffix, prependTemplate: component.prefix, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
63
63
  case 'textarea':
64
- return (_jsx(TextAreaComponent, { id: component.id, name: component.id, ...commonProps, value: value !== undefined ? value : (component.defaultValue || ''), cols: component.cols || 200, rows: component.textareaRows || 4, showClearButton: component.showClearButton || false, readonly: component.readOnly || false, maxLength: component?.maxLength || 255, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
64
+ return (_jsx(TextAreaComponent, { id: component.id, name: component.id, locale: locale, ...commonProps, value: value !== undefined ? value : (component.defaultValue || ''), cols: component.cols || 200, rows: component.textareaRows || 4, showClearButton: component.showClearButton || false, readonly: component.readOnly || false, maxLength: component?.maxLength || 255, cssClass: cssClass, htmlAttributes: htmlAttrs, appendTemplate: component.suffix, prependTemplate: component.prefix, resizeMode: 'Vertical', ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
65
65
  case 'number':
66
- return (_jsx(NumericTextBoxComponent, { id: component.id, name: component.id, ...commonProps, value: value !== undefined ? value : (component.defaultValue || 0), decimals: component.decimals || 2, currency: component.currency, format: component.format || 'n2', step: component.step || 1, min: component.minValue || undefined, max: component.maxValue || undefined, readonly: component.readOnly || false, showClearButton: component.showClearButton || false, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
66
+ return (_jsx(NumericTextBoxComponent, { id: component.id, name: component.id, locale: locale, ...commonProps, value: value !== undefined ? value : (component.defaultValue || 0), decimals: component.decimals || 2, currency: component.currency, format: component.numberFormat || 'n2', step: component.step || 1, min: component.minValue || undefined, max: component.maxValue || undefined, readonly: component.readOnly || false, showClearButton: component.showClearButton || false, cssClass: cssClass, htmlAttributes: htmlAttrs, appendTemplate: component.suffix, prependTemplate: component.prefix, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
67
67
  case 'checkbox':
68
68
  const checkboxLabel = component.label && component.required
69
69
  ? `${component.label} *`
70
70
  : component.label;
71
- return (_jsx(CheckBoxComponent, { id: component.id, name: component.id, label: checkboxLabel, labelPosition: component.checkboxLabelPosition, checked: component.defaultValue ?? (component.checked ?? false), indeterminate: component.indeterminate || false, disabled: component.disabled, cssClass: cssClass, htmlAttributes: htmlAttrs, change: (args) => onChange(args.checked), ref: ref }, component.id));
72
- case 'checkboxgroup':
71
+ return (_jsx(CheckBoxComponent, { id: component.id, locale: locale, name: component.id, label: checkboxLabel, labelPosition: component.checkboxLabelPosition, checked: component.defaultValue ?? (component.checked ?? false), indeterminate: component.indeterminate || false, disabled: component.disabled, cssClass: cssClass, htmlAttributes: htmlAttrs, change: (args) => onChange(args.checked), ref: ref }, component.id));
72
+ case 'checkboxGroup':
73
73
  return (_jsx(CheckboxGroup, { component: component, value: value, onChange: (v) => onChange(v), optionRef: ref }, component.id));
74
74
  case 'radio':
75
75
  return (_jsx("div", { id: `${component.id}-group`, className: `e-radio-group ${errorClass}`, children: (component.options || ['Option 1']).map((option, idx) => {
76
76
  const optionValue = option;
77
77
  const optionText = option;
78
- return (_jsx("div", { style: { marginBottom: '8px' }, children: _jsx(RadioButtonComponent, { id: `${component.id}_${idx}_${optionValue}`, name: component.id, label: optionText, disabled: component.disabled, value: optionValue, htmlAttributes: htmlAttrs, labelPosition: component.fieldLabelPosition, checked: component.defaultValue === optionValue, cssClass: component.cssClass, change: (args) => {
78
+ return (_jsx("div", { style: { marginBottom: '8px' }, children: _jsx(RadioButtonComponent, { id: `${component.id}_${idx}_${optionValue}`, name: component.id, label: optionText, locale: locale, disabled: component.disabled, value: optionValue, htmlAttributes: htmlAttrs, labelPosition: component.fieldLabelPosition, checked: component.defaultValue === optionValue, cssClass: cssClass, change: (args) => {
79
79
  if (args.value === optionValue) {
80
80
  onChange(optionValue);
81
81
  }
82
82
  }, ref: ref ? (el) => ref(el, idx) : undefined }, component.id) }, idx));
83
83
  }) }));
84
84
  case 'dropdown':
85
- return (_jsx(DropDownListComponent, { id: component.id, name: component.id, ...commonProps, cssClass: cssClass, dataSource: component.options || ["Option 1"], value: value !== undefined ? value : (component.defaultValue ?? null), showClearButton: component.showClearButton || false, readonly: component.readOnly || false, enableVirtualization: component.enableVirtualization || false, popupHeight: component.popupHeight || '300px', popupWidth: component.popupWidth || '100%', htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
85
+ return (_jsx(DropDownListComponent, { id: component.id, name: component.id, ...commonProps, locale: locale, cssClass: cssClass, dataSource: component.options || ["Option 1"], value: value !== undefined ? value : (component.defaultValue ?? null), showClearButton: component.showClearButton || false, readonly: component.readOnly || false, enableVirtualization: component.enableVirtualization || false, popupHeight: component.popupHeight || '300px', popupWidth: component.popupWidth || '100%', htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
86
86
  case 'multiselect':
87
- return (_jsx(MultiSelectComponent, { id: component.id, name: component.id, ...commonProps, value: value !== undefined ? value : (component.defaultValue ?? null), placeholder: component.placeholder, dataSource: component.options || ["Option 1"], fields: { text: 'text', value: 'value' }, showClearButton: component.showClearButton || false, readonly: component.readOnly || false, allowCustomValue: component.allowCustomValue || false, addTagOnBlur: component.addTagOnBlur || false, delimiterChar: component.delimiterChar || ',', showSelectAll: component.showSelectAll || false, mode: component.showSelectAll ? 'CheckBox' : undefined, selectAllText: component.selectAllText, unSelectAllText: component.unSelectAllText, showDropDownIcon: component.showDropDownIcon !== false, enableVirtualization: component.enableVirtualization || false, popupHeight: component.popupHeight || '300px', popupWidth: component.popupWidth || '100%', cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref, children: _jsx(Inject, { services: [CheckBoxSelection] }) }, component.id));
88
- case 'datepicker':
89
- return (_jsx(DatePickerComponent, { ...commonProps, id: component.id, name: component.id, value: value !== undefined ? value : (component.defaultValue ?? null), floatLabelType: component.floatLabelType || 'Never', format: component.format || 'MM/dd/yyyy', placeholder: component.placeholder || '', readOnly: component.readOnly || false, showClearButton: component.showClearButton !== false ? true : false, showTodayButton: component.showTodayButton !== false ? true : false, calendarMode: component.calendarMode || 'Gregorian', dayHeaderFormat: component.dayHeaderFormat || 'Short', depth: component.depth || 'Month', start: component.start || 'Month', firstDayOfWeek: component.firstDayOfWeek || 0, min: component?.minDate ? new Date(component.minDate) : undefined, max: component?.maxDate ? new Date(component.maxDate) : undefined, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref, children: _jsx(Inject, { services: [Islamic] }) }, component.id));
90
- case 'datetimepicker':
91
- return (_jsx(DateTimePickerComponent, { ...commonProps, id: component.id, name: component.id, floatLabelType: component.floatLabelType || 'Never', dayHeaderFormat: component.dayHeaderFormat || 'Short', value: value !== undefined ? value : (component.defaultValue ?? null), format: component.format || 'MM/dd/yyyy hh:mm a', showClearButton: component.showClearButton !== false, showTodayButton: component.showTodayButton || false, depth: component.depth || 'Month', start: component.start || 'Month', step: component.step || 1, readonly: component.readOnly || false, min: component?.minDate ? new Date(component.minDate) : undefined, max: component?.maxDate ? new Date(component.maxDate) : undefined, minTime: component?.minTime ? new Date(`2000-01-01 ${component.minTime}`) : undefined, maxTime: component?.maxTime ? new Date(`2000-01-01 ${component.maxTime}`) : undefined, enableMask: false, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref, children: _jsx(Inject, { services: [Islamic] }) }, component.id));
92
- case 'timepicker':
93
- return (_jsx(TimePickerComponent, { id: component.id, name: component.id, floatLabelType: component.floatLabelType || 'Never', placeholder: component.placeholder || '', enabled: !component.disabled, value: value !== undefined ? value : (component.defaultValue ?? null), format: component.format || 'hh:mm a', showClearButton: component.showClearButton !== false, step: component.step || 30, readonly: component.readOnly || false, min: component?.minTime ? new Date(`2000-01-01 ${component.minTime}`) : undefined, max: component?.maxTime ? new Date(`2000-01-01 ${component.maxTime}`) : undefined, enableMask: false, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
94
- case 'daterange':
95
- return (_jsx(DateRangePickerComponent, { id: component.id, name: component.id, floatLabelType: component.floatLabelType || 'Never', dayHeaderFormat: component.dayHeaderFormat || 'Short', placeholder: component.placeholder || '', enabled: !component.disabled, value: value !== undefined ? value : (component.defaultValue ?? null), depth: component.depth || 'Month', start: component.start || 'Month', min: component?.minDate ? new Date(component.minDate) : undefined, max: component?.maxDate ? new Date(component.maxDate) : undefined, format: component.format || 'MM/dd/yyyy', separator: component.separator || ' - ', showClearButton: component.showClearButton !== false, readonly: component.readOnly || false, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
87
+ return (_jsx(MultiSelectComponent, { id: component.id, name: component.id, locale: locale, ...commonProps, value: value !== undefined ? value : (component.defaultValue ?? null), placeholder: component.placeholder, dataSource: component.options || ["Option 1"], fields: { text: 'text', value: 'value' }, showClearButton: component.showClearButton || false, readonly: component.readOnly || false, allowCustomValue: component.allowCustomValue || false, addTagOnBlur: component.addTagOnBlur || false, delimiterChar: component.delimiterChar || ',', showSelectAll: component.showSelectAll || false, mode: component.showSelectAll ? 'CheckBox' : undefined, selectAllText: component.selectAllText, unSelectAllText: component.unSelectAllText, showDropDownIcon: component.showDropDownIcon !== false, enableVirtualization: component.enableVirtualization || false, popupHeight: component.popupHeight || '300px', popupWidth: component.popupWidth || '100%', cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref, children: _jsx(Inject, { services: [CheckBoxSelection] }) }, component.id));
88
+ case 'date':
89
+ return (_jsx(DatePickerComponent, { ...commonProps, id: component.id, name: component.id, locale: locale, value: value !== undefined ? value : (component.defaultValue ?? null), floatLabelType: component.floatLabelType || 'Never', format: component.format || 'MM/dd/yyyy', placeholder: component.placeholder || '', readOnly: component.readOnly || false, showClearButton: component.showClearButton !== false ? true : false, showTodayButton: component.showTodayButton !== false ? true : false, calendarMode: component.calendarMode || 'Gregorian', dayHeaderFormat: component.dayHeaderFormat || 'Short', depth: component.depth || 'Month', start: component.start || 'Month', firstDayOfWeek: component.firstDayOfWeek || 0, min: component?.minDate ? new Date(component.minDate) : undefined, max: component?.maxDate ? new Date(component.maxDate) : undefined, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref, children: _jsx(Inject, { services: [Islamic] }) }, component.id));
90
+ case 'dateTime':
91
+ return (_jsx(DateTimePickerComponent, { ...commonProps, id: component.id, locale: locale, name: component.id, floatLabelType: component.floatLabelType || 'Never', dayHeaderFormat: component.dayHeaderFormat || 'Short', value: value !== undefined ? value : (component.defaultValue ?? null), format: component.format || 'MM/dd/yyyy hh:mm a', showClearButton: component.showClearButton !== false, showTodayButton: component.showTodayButton !== false ? true : false, depth: component.depth || 'Month', start: component.start || 'Month', step: component.step || 1, readonly: component.readOnly || false, min: component?.minDate ? new Date(component.minDate) : undefined, max: component?.maxDate ? new Date(component.maxDate) : undefined, minTime: component?.minTime ? new Date(`2000-01-01 ${component.minTime}`) : undefined, maxTime: component?.maxTime ? new Date(`2000-01-01 ${component.maxTime}`) : undefined, enableMask: false, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref, children: _jsx(Inject, { services: [Islamic] }) }, component.id));
92
+ case 'time':
93
+ return (_jsx(TimePickerComponent, { id: component.id, locale: locale, name: component.id, floatLabelType: component.floatLabelType || 'Never', placeholder: component.placeholder || '', enabled: !component.disabled, value: value !== undefined ? value : (component.defaultValue ?? null), format: component.format || 'hh:mm a', showClearButton: component.showClearButton !== false, step: component.step || 30, readonly: component.readOnly || false, min: component?.minTime ? new Date(`2000-01-01 ${component.minTime}`) : undefined, max: component?.maxTime ? new Date(`2000-01-01 ${component.maxTime}`) : undefined, enableMask: false, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
94
+ case 'dateRange':
95
+ return (_jsx(DateRangePickerComponent, { id: component.id, locale: locale, name: component.id, floatLabelType: component.floatLabelType || 'Never', dayHeaderFormat: component.dayHeaderFormat || 'Short', placeholder: component.placeholder || '', enabled: !component.disabled, value: value !== undefined ? value : (component.defaultValue ?? null), depth: component.depth || 'Month', start: component.start || 'Month', min: component?.minDate ? new Date(component.minDate) : undefined, max: component?.maxDate ? new Date(component.maxDate) : undefined, format: component.format || 'MM/dd/yyyy', separator: component.separator || ' - ', showClearButton: component.showClearButton !== false, readonly: component.readOnly || false, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
96
96
  case 'switch':
97
- return (_jsx(SwitchComponent, { id: component.id, value: component.defaultValue, name: component.id, checked: component.checked, disabled: component.disabled, onLabel: component.onLabel || '', offLabel: component.offLabel || '', cssClass: cssClass, htmlAttributes: htmlAttrs, change: (args) => onChange(args.checked), ref: ref }, component.id));
97
+ return (_jsx(SwitchComponent, { id: component.id, locale: locale, value: component.defaultValue, name: component.id, checked: component.defaultValue ?? (component.checked ?? false), disabled: component.disabled, onLabel: component.onLabel || '', offLabel: component.offLabel || '', cssClass: cssClass, htmlAttributes: htmlAttrs, change: (args) => onChange(args.checked), ref: ref }, component.id));
98
98
  case 'button':
99
99
  // If buttonsGroups is provided, render a button group in-place of a single button
100
100
  const groupButtons = (component.buttonsGroups || component.buttons || []);
@@ -107,12 +107,12 @@ export const renderFormField = ({ component, value, onChange, onBlur, ref, hasEr
107
107
  justifyContent: mapPositionToJustifyContent(component.position),
108
108
  width: component.width || undefined,
109
109
  };
110
- return (_jsx("div", { id: component.id, role: "group", "aria-label": component.label || 'Button Group', className: component.cssClass, style: groupStyleObj, children: groupButtons.map((btn, idx) => {
110
+ return (_jsx("div", { id: component.id, role: "group", "aria-label": component.label || 'Button Group', className: cssClass, style: groupStyleObj, children: groupButtons.map((btn, idx) => {
111
111
  const btnId = `${component.id}_${idx}`;
112
112
  const btnCssClass = [
113
113
  mapButtonStyleToClass(btn.style)
114
114
  ].filter(Boolean).join(' ');
115
- return (_jsx(ButtonComponent, { id: String(btnId), name: String(btnId), type: resolveButtonType(btn.type), cssClass: btnCssClass, disabled: btn.disabled || false, content: btn.label || `Button ${idx + 1}`, iconCss: btn.iconCss, iconPosition: btn.iconPosition, onClick: (event) => {
115
+ return (_jsx(ButtonComponent, { id: String(btnId), name: String(btnId), locale: locale, type: resolveButtonType(btn.type), cssClass: btnCssClass, disabled: btn.disabled || false, content: btn.label || `Button ${idx + 1}`, iconCss: btn.iconCss, iconPosition: btn.iconPosition, onClick: (event) => {
116
116
  if (onClick) {
117
117
  onClick(event);
118
118
  }
@@ -129,19 +129,20 @@ export const renderFormField = ({ component, value, onChange, onBlur, ref, hasEr
129
129
  mapButtonStyleToClass(component.style),
130
130
  resolvedButtonType === 'submit' ? 'submit-btn form-submit-type' : '',
131
131
  resolvedButtonType === 'reset' ? 'form-reset-type' : '',
132
- component.cssClass || 'e-primary'
132
+ component.cssClass || 'e-primary',
133
+ component.size === 'Small' ? ' e-small' : component.size === 'Bigger' ? ' e-bigger' : ''
133
134
  ].filter(Boolean).join(' ') || 'e-primary';
134
135
  const buttonContainerStyle = {
135
136
  display: 'flex',
136
137
  justifyContent: mapPositionToJustifyContent(component.position),
137
138
  width: component.width || '100%',
138
139
  };
139
- return (_jsx("div", { id: `${component.id}-container`, style: buttonContainerStyle, children: _jsx(ButtonComponent, { id: component.id, type: resolvedButtonType, cssClass: buttonCssClassList, disabled: component.disabled, iconCss: component.iconCss, iconPosition: component.iconPosition, onClick: (event) => {
140
+ return (_jsx("div", { id: `${component.id}-container`, style: buttonContainerStyle, children: _jsx(ButtonComponent, { id: component.id, type: resolvedButtonType, locale: locale, cssClass: buttonCssClassList, disabled: component.disabled, iconCss: component.iconCss, iconPosition: component.iconPosition, onClick: (event) => {
140
141
  if (onClick) {
141
142
  onClick(event);
142
143
  }
143
144
  }, ref: ref, children: component.label }, component.id) }, `form-${component.type}-${component.id}`));
144
- case 'splitbutton':
145
+ case 'splitButton':
145
146
  const splitButtonCssClassList = [
146
147
  component.style === 'primary' ? 'e-primary' : '',
147
148
  component.style === 'flat' ? '' : '',
@@ -155,7 +156,7 @@ export const renderFormField = ({ component, value, onChange, onBlur, ref, hasEr
155
156
  display: 'flex',
156
157
  justifyContent: mapPositionToJustifyContent(component.position)
157
158
  };
158
- return (_jsx("div", { id: `${component.id}-container`, "aria-label": 'Splitbutton', style: splitButtonContainerStyle, children: _jsx(SplitButtonComponent, { id: component.id, content: component.label || 'Split Button', items: component.options?.map((option, index) => ({
159
+ return (_jsx("div", { id: `${component.id}-container`, "aria-label": 'Splitbutton', style: splitButtonContainerStyle, children: _jsx(SplitButtonComponent, { id: component.id, locale: locale, content: component.label || 'Split Button', items: component.options?.map((option, index) => ({
159
160
  text: option,
160
161
  id: `${component.id}_option_${index}`
161
162
  })) || [{ text: 'Option 1', id: `${component.id}_option_0` }], cssClass: splitButtonCssClassList, disabled: component.disabled, iconCss: component.iconCss, iconPosition: component.iconPosition || 'Left', onClick: (event) => {
@@ -168,34 +169,34 @@ export const renderFormField = ({ component, value, onChange, onBlur, ref, hasEr
168
169
  }
169
170
  }, ref: ref }, component.id) }, `form-${component.type}-${component.id}`));
170
171
  case 'signature':
171
- return (_jsx(SignatureComponent, { id: component.id, backgroundColor: component.backgroundColor || '', strokeColor: component.strokeColor || '', maxStrokeWidth: component.maxValue, minStrokeWidth: component.minValue, velocity: component.velocity, disabled: component.disabled, change: (args) => onChange(args.value), ref: ref }, component.id));
172
+ return (_jsx(SignatureComponent, { id: component.id, className: cssClass, locale: locale, backgroundColor: component.backgroundColor || '', strokeColor: component.strokeColor || '', maxStrokeWidth: component.maxValue, minStrokeWidth: component.minValue, velocity: component.velocity, disabled: component.disabled, change: (args) => onChange(args.value), ref: ref }, component.id));
172
173
  case 'rating':
173
- return (_jsx(RatingComponent, { id: component.id, name: component.id, value: value !== undefined ? value : (component.defaultValue || 0), disabled: component.disabled, cssClass: component.cssClass, allowReset: component.allowReset, itemsCount: component.itemsCount, min: component?.minValue, precision: component.precision, readOnly: component.readOnly, showTooltip: component.showRatingTooltip || false, showLabel: component.showRatingLabel, labelPosition: component.showRatingLabel ? component.ratingLabelPosition : undefined, valueChanged: (args) => onChange(args.value), ref: ref }, component.id));
174
- case 'colorpicker':
175
- return (_jsx(ColorPickerComponent, { id: component.id, value: value !== undefined ? value : (component.defaultValue || ''), disabled: component.disabled, enableOpacity: component.enableOpacity, showButtons: component.showButtons, showRecentColors: component.showRecentColors, noColor: component.showNoColor, cssClass: cssClass, change: (args) => onChange(args.value), ref: ref }, component.id));
176
- case 'inputmask':
177
- return (_jsx(MaskedTextBoxComponent, { id: component.id, name: component.id, ...commonProps, value: value !== undefined ? value : (component.defaultValue || ''), floatLabelType: component.floatLabelType || 'Never', placeholder: component.placeholder || '', enabled: !component.disabled, mask: component.mask || '000-000-0000', promptChar: component.promptChar || '_', customCharacters: component.customCharacters, readOnly: component.readOnly || false, showClearButton: component.showClearButton !== false, cssClass: cssClass, htmlAttributes: htmlAttrs, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
178
- case 'rangeslider':
179
- return (_jsx(SliderComponent, { id: component.id, value: value !== undefined ? value : (component.defaultValue ?? 0), min: component.minValue || 0, max: component.maxValue || 100, step: component.step || 1, disabled: component.disabled, cssClass: cssClass, enabled: !component.disabled, showButtons: component.showButtons, change: (args) => onChange(args.value), ref: ref }, component.id));
180
- case 'fileupload':
181
- return (_jsx(UploaderComponent, { id: component.id, name: component.id, type: 'file', enabled: !component.disabled, allowedExtensions: component.allowExtensions, asyncSettings: { saveUrl: component.saveUrl, removeUrl: component.removeUrl }, buttons: component.buttons || {
174
+ return (_jsx(RatingComponent, { id: component.id, name: component.id, locale: locale, value: value !== undefined ? value : (component.defaultValue || 0), disabled: component.disabled, cssClass: cssClass, allowReset: component.allowReset, itemsCount: component.itemsCount, min: component?.minValue, precision: component.precision, readOnly: component.readOnly, showTooltip: component.showRatingTooltip || false, showLabel: component.showRatingLabel, labelPosition: component.showRatingLabel ? component.ratingLabelPosition : undefined, valueChanged: (args) => onChange(args.value), ref: ref }, component.id));
175
+ case 'colorPicker':
176
+ return (_jsx(ColorPickerComponent, { id: component.id, locale: locale, value: value !== undefined ? value : (component.defaultValue || ''), disabled: component.disabled, enableOpacity: component.enableOpacity, showButtons: component.showButtons, showRecentColors: component.showRecentColors, noColor: component.showNoColor, cssClass: cssClass, change: (args) => onChange(args.value), ref: ref }, component.id));
177
+ case 'inputMask':
178
+ return (_jsx(MaskedTextBoxComponent, { id: component.id, name: component.id, ...commonProps, locale: locale, value: value !== undefined ? value : (component.defaultValue || ''), floatLabelType: component.floatLabelType || 'Never', placeholder: component.placeholder || '', enabled: !component.disabled, mask: component.mask || '000-000-0000', promptChar: component.promptChar || '_', customCharacters: component.customCharacters, readOnly: component.readOnly || false, showClearButton: component.showClearButton !== false, cssClass: cssClass, htmlAttributes: htmlAttrs, appendTemplate: component.suffix, prependTemplate: component.prefix, ...createValidationHandlers((args) => args.value || ''), ref: ref }, component.id));
179
+ case 'rangeSlider':
180
+ return (_jsx(SliderComponent, { id: component.id, locale: locale, value: value !== undefined ? value : (component.defaultValue ?? 0), min: component.minValue || 0, max: component.maxValue || 100, step: component.step || 1, disabled: component.disabled, cssClass: cssClass, enabled: !component.disabled, showButtons: component.showButtons, change: (args) => onChange(args.value), ref: ref }, component.id));
181
+ case 'fileUpload':
182
+ return (_jsx(UploaderComponent, { id: component.id, name: component.id, locale: locale, type: 'file', enabled: !component.disabled, allowedExtensions: component.allowExtensions, asyncSettings: { saveUrl: component.saveUrl, removeUrl: component.removeUrl }, buttons: component.buttons || {
182
183
  "browse": "Choose File",
183
184
  "clear": "Clear All",
184
185
  "upload": "Upload All"
185
186
  }, maxFileSize: component?.maxValue, minFileSize: component?.minValue, multiple: component.allowMultiple, showFileList: component.showFileList, htmlAttributes: htmlAttrs, cssClass: cssClass, change: (args) => onChange(args.filesData), ref: ref }, component.id));
186
- case 'imageeditor':
187
- return (_jsx(ImageEditorComponent, { id: component.id, disabled: component.disabled, cssClass: component.cssClass, height: (component.height || '350px').toString(), width: (component.width || '100%').toString(), ref: ref }, component.id));
187
+ case 'imageEditor':
188
+ return (_jsx(ImageEditorComponent, { id: component.id, locale: locale, disabled: component.disabled, cssClass: cssClass, height: (component.height || '350px').toString(), width: (component.width || '100%').toString(), ref: ref }, component.id));
188
189
  case 'message':
189
- return (_jsx(MessageComponent, { id: component.id, severity: component.severity || component.messageType || 'info', variant: component.variant, content: component.content || 'Message', showCloseIcon: component.showCloseIcon || false, showIcon: component.showIcon || false, disabled: component.disabled, cssClass: component.cssClass, ref: ref }, component.id));
190
- case 'datagrid':
190
+ return (_jsx(MessageComponent, { id: component.id, locale: locale, severity: component.severity || component.messageType || 'info', variant: component.variant, content: component.content || 'Message', showCloseIcon: component.showCloseIcon, showIcon: (component.showIcon === undefined ? false : component.showIcon) || false, disabled: component.disabled, cssClass: cssClass, ref: ref }, component.id));
191
+ case 'dataGrid':
191
192
  const dg = component;
192
- return (_jsx("div", { id: dg.id, className: dg.cssClass, children: _jsx(DataGridComponent, { id: dg.id, type: 'datagrid', label: dg.label || '', columns: dg.columns || [], dataSource: value !== undefined ? value : (dg.dataSource ?? dg.dataSource ?? []), height: dg.height || '200px', width: dg.width || '100%', pageSize: dg.pageSize || 6, allowPaging: dg.allowPaging !== false, allowAdding: dg.allowAdding !== false, allowEditing: dg.allowEditing !== false, allowDeleting: dg.allowDeleting !== false, onDataChange: (data) => onChange(data), ref: ref }) }, dg.id));
193
- case 'richtexteditor':
193
+ return (_jsx("div", { id: dg.id, className: dg.cssClass, children: _jsx(DataGridComponent, { id: dg.id, type: 'dataGrid', locale: locale, label: dg.label || '', name: dg.name || '', columns: dg.columns || [], dataSource: value !== undefined ? value : (dg.dataSource ?? dg.dataSource ?? []), height: dg.height || '200px', width: dg.width || '100%', pageSize: dg.pageSize || 6, allowPaging: dg.allowPaging !== false, allowAdding: dg.allowAdding !== false, allowEditing: dg.allowEditing !== false, allowDeleting: dg.allowDeleting !== false, onDataChange: (data) => onChange(data), cssClass: cssClass, ref: ref }) }, dg.id));
194
+ case 'richTextEditor':
194
195
  const toolbarSettings = {
195
196
  items: ['Undo', 'Redo', '|', 'Bold', 'Italic', 'Underline', 'StrikeThrough', 'InlineCode', '|', 'CreateLink', 'Blockquote', '|', 'BulletFormatList', 'NumberFormatList', '|', 'Formats', 'Alignments', '|', 'Outdent', 'Indent', '|',
196
197
  'FontColor', 'BackgroundColor', 'FontName', 'FontSize', '|', 'LowerCase', 'UpperCase', '|', 'SourceCode']
197
198
  };
198
- return (_jsx(RichTextEditorComponent, { id: component.id, name: component.id, toolbarSettings: toolbarSettings, value: value !== undefined ? value : (component.defaultValue || ''), placeholder: component.placeholder || '', enabled: !component.disabled, readonly: component.readOnly || false, maxLength: component.maxLength || 1000, cssClass: cssClass || undefined, height: component.height || '300px', width: component.width || '100%', htmlAttributes: htmlAttrs, ref: ref, children: _jsx(RTEInject, { services: [Toolbar, Link, HtmlEditor, QuickToolbar] }) }, `${component.id}`));
199
+ return (_jsx(RichTextEditorComponent, { id: component.id, locale: locale, name: component.id, toolbarSettings: toolbarSettings, value: value !== undefined ? value : (component.defaultValue || ''), placeholder: component.placeholder || '', enabled: !component.disabled, readonly: component.readOnly || false, maxLength: component.maxLength || 1000, cssClass: cssClass || undefined, height: component.height || '300px', width: component.width || '100%', htmlAttributes: htmlAttrs, ref: ref, children: _jsx(RTEInject, { services: [Toolbar, Link, HtmlEditor, QuickToolbar] }) }, `${component.id}`));
199
200
  default:
200
201
  return (_jsxs("div", { className: "unsupported-component", children: ["Unsupported component type: ", component.type] }));
201
202
  }
@@ -8,6 +8,28 @@ export interface ButtonClickEventArgs {
8
8
  buttonLabel: string;
9
9
  event: React.MouseEvent<HTMLButtonElement>;
10
10
  }
11
+ export type ConditionalOperator = 'equal' | 'notEqual' | 'greaterThan' | 'lessThan' | 'greaterThanOrEqual' | 'lessThanOrEqual' | 'in' | 'notIn' | 'contains' | 'notContains';
12
+ export interface ConditionalRule {
13
+ field: string;
14
+ operator: ConditionalOperator;
15
+ value: any;
16
+ }
17
+ export interface CompositeConditionalRule {
18
+ condition: 'and' | 'or';
19
+ rules: (ConditionalRule | CompositeConditionalRule)[];
20
+ }
21
+ export type ConditionType = ConditionalRule | CompositeConditionalRule;
22
+ export interface FormComponentConditions {
23
+ visibleWhen?: ConditionType;
24
+ hideWhen?: ConditionType;
25
+ readOnlyWhen?: ConditionType;
26
+ disabledWhen?: ConditionType;
27
+ requiredWhen?: ConditionType;
28
+ setValueWhen?: {
29
+ condition: ConditionType;
30
+ value: any;
31
+ };
32
+ }
11
33
  export interface FormSchema {
12
34
  version: string;
13
35
  theme: string;
@@ -15,10 +37,13 @@ export interface FormSchema {
15
37
  }
16
38
  export interface FormComponent {
17
39
  id: string;
18
- type: 'textbox' | 'textarea' | 'number' | 'email' | 'url' | 'phone' | 'password' | 'checkbox' | 'checkboxgroup' | 'radio' | 'dropdown' | 'multiselect' | 'button' | 'datepicker' | 'datetimepicker' | 'timepicker' | 'daterange' | 'switch' | 'signature' | 'rating' | 'imageeditor' | 'fileupload' | 'rangeslider' | 'colorpicker' | 'inputmask' | 'message' | 'panel' | 'table' | 'tabs' | 'datagrid' | 'card' | 'splitbutton' | 'richtexteditor' | 'statichtml';
40
+ type: 'textbox' | 'textarea' | 'number' | 'email' | 'url' | 'phone' | 'password' | 'checkbox' | 'checkboxGroup' | 'radio' | 'dropdown' | 'multiselect' | 'button' | 'date' | 'dateTime' | 'time' | 'dateRange' | 'switch' | 'signature' | 'rating' | 'imageEditor' | 'fileUpload' | 'rangeSlider' | 'colorPicker' | 'inputMask' | 'message' | 'panel' | 'table' | 'tabs' | 'dataGrid' | 'card' | 'splitButton' | 'richTextEditor' | 'staticHtml';
19
41
  textboxType?: string;
20
42
  label: string;
21
43
  name: string;
44
+ description?: string | undefined;
45
+ prefix?: string | undefined;
46
+ suffix?: string | undefined;
22
47
  placeholder?: string;
23
48
  defaultValue?: any;
24
49
  disabled?: boolean;
@@ -59,6 +84,7 @@ export interface FormComponent {
59
84
  decimals?: number;
60
85
  currency?: string;
61
86
  format?: string;
87
+ numberFormat?: string;
62
88
  allowReset?: boolean;
63
89
  itemsCount?: number;
64
90
  precision?: number | string;
@@ -108,6 +134,7 @@ export interface FormComponent {
108
134
  showDropDownIcon?: boolean;
109
135
  validateOn?: 'Change' | 'Blur';
110
136
  pageSize?: number;
137
+ size?: string;
111
138
  allowPaging?: boolean;
112
139
  allowAdding?: boolean;
113
140
  allowEditing?: boolean;
@@ -153,6 +180,7 @@ export interface FormComponent {
153
180
  tableCells?: FormComponent[][][];
154
181
  parentPath?: string;
155
182
  properties?: Record<string, any>;
183
+ conditions?: FormComponentConditions;
156
184
  _configured?: boolean;
157
185
  }
158
186
  export interface ValidationRules {
package/src/utils.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { Internationalization } from '@syncfusion/ej2-base';
1
2
  /**
2
3
  * Maps button style to Syncfusion CSS classes
3
4
  * @param style - Button style ('primary' | 'flat' | 'information' | 'error' | 'success' | 'warning')
@@ -58,3 +59,88 @@ export function splitWidths(input) {
58
59
  // Convert any NaN (shouldn't remain) to 0 and round knowns
59
60
  return result.map(v => (isNaN(v) ? 0 : Math.round(v)));
60
61
  }
62
+ export function extractAllDescendantIds(component) {
63
+ const childIds = [];
64
+ function traverse(comps) {
65
+ for (const comp of comps) {
66
+ childIds.push(comp.id);
67
+ // Recursively traverse nested structures
68
+ if (comp.children && Array.isArray(comp.children)) {
69
+ traverse(comp.children);
70
+ }
71
+ // Handle table cells
72
+ if (comp.tableCells && Array.isArray(comp.tableCells)) {
73
+ comp.tableCells.forEach((row) => {
74
+ if (Array.isArray(row)) {
75
+ row.forEach((cell) => {
76
+ if (Array.isArray(cell)) {
77
+ traverse(cell);
78
+ }
79
+ });
80
+ }
81
+ });
82
+ }
83
+ // Handle tab items
84
+ if (comp.tabItems && Array.isArray(comp.tabItems)) {
85
+ comp.tabItems.forEach((tabItem) => {
86
+ if (tabItem.content && Array.isArray(tabItem.content)) {
87
+ traverse(tabItem.content);
88
+ }
89
+ });
90
+ }
91
+ }
92
+ }
93
+ // Start with direct children
94
+ if (component.children && Array.isArray(component.children)) {
95
+ traverse(component.children);
96
+ }
97
+ // Handle table cells
98
+ if (component.tableCells && Array.isArray(component.tableCells)) {
99
+ component.tableCells.forEach((row) => {
100
+ if (Array.isArray(row)) {
101
+ row.forEach((cell) => {
102
+ if (Array.isArray(cell)) {
103
+ traverse(cell);
104
+ }
105
+ });
106
+ }
107
+ });
108
+ }
109
+ // Handle tab items
110
+ if (component.tabItems && Array.isArray(component.tabItems)) {
111
+ component.tabItems.forEach((tabItem) => {
112
+ if (tabItem.content && Array.isArray(tabItem.content)) {
113
+ traverse(tabItem.content);
114
+ }
115
+ });
116
+ }
117
+ return childIds;
118
+ }
119
+ export function formatDateValues(component, value) {
120
+ let intl = new Internationalization();
121
+ let dFormatter = intl.getDateFormat({
122
+ format: 'MM/dd/yyyy',
123
+ type: 'date'
124
+ });
125
+ if (component.type === 'date') {
126
+ value = dFormatter(new Date(value));
127
+ }
128
+ if (component.type === 'time') {
129
+ dFormatter = intl.getDateFormat({
130
+ format: 'hh:mm a',
131
+ type: 'time'
132
+ });
133
+ value = dFormatter(new Date(value));
134
+ }
135
+ if (component.type === 'dateTime') {
136
+ dFormatter = intl.getDateFormat({
137
+ format: 'MM/dd/yyyy hh:mm a',
138
+ type: 'dateTime'
139
+ });
140
+ value = dFormatter(new Date(value));
141
+ }
142
+ if (component.type === 'dateRange' && Array.isArray(value)) {
143
+ value = value.map(date => date ? dFormatter(new Date(date)) : null);
144
+ }
145
+ return value;
146
+ }
@@ -150,6 +150,22 @@
150
150
  min-width: 0;
151
151
  }
152
152
 
153
+ .field-wrapper:has(.e-small) .field-label {
154
+ font-size: .75rem;
155
+ }
156
+
157
+ .field-wrapper:has(.e-small) .field-description {
158
+ font-size: 0.625rem;
159
+ }
160
+
161
+ .field-wrapper:has(.e-bigger) .field-label {
162
+ font-size: 1rem;
163
+ }
164
+
165
+ .field-wrapper:has(.e-bigger) .field-description {
166
+ font-size: 0.875rem;
167
+ }
168
+
153
169
  /* Label */
154
170
  .field-label {
155
171
  font-size: 0.875rem;
@@ -213,7 +229,6 @@
213
229
  border: none;
214
230
  border-radius: 8px;
215
231
  padding: 0;
216
- margin: 1rem 0;
217
232
  }
218
233
 
219
234
  .form-panel-renderer:has(.panel-legend) {
@@ -268,45 +283,45 @@
268
283
  overflow-y: hidden;
269
284
  }
270
285
 
271
- .form-table-renderer .table-row {
286
+ .form-table-renderer .e-form-table-row {
272
287
  display: table-row;
273
288
  background: transparent;
274
289
  }
275
290
 
276
- .form-table-renderer .table-cell {
291
+ .form-table-renderer .e-form-table-cell {
277
292
  display: table-cell;
278
293
  padding: 12px;
279
294
  vertical-align: top;
280
295
  }
281
296
 
282
- .table-border .table-cell {
297
+ .table-border .e-form-table-cell {
283
298
  border-bottom: 1px solid var(--sf-layout-border-color);
284
299
  border-right: 1px solid var(--sf-layout-border-color);
285
300
  }
286
301
 
287
- .table-cell:last-child {
302
+ .e-form-table-cell:last-child {
288
303
  border-right: none;
289
304
  }
290
305
 
291
- .form-table-renderer .table-row:last-child .table-cell {
306
+ .form-table-renderer .e-form-table-row:last-child .e-form-table-cell {
292
307
  border-bottom: none;
293
308
  }
294
309
 
295
- .table-cell > .form-table-renderer,
296
- .table-cell > .form-tabs-renderer,
297
- .table-cell > .form-card-renderer,
298
- .table-cell > .form-panel-renderer,
299
- .table-cell > .form-group
310
+ .e-form-table-cell > .form-table-renderer,
311
+ .e-form-table-cell > .form-tabs-renderer,
312
+ .e-form-table-cell > .form-card-renderer,
313
+ .e-form-table-cell > .form-panel-renderer,
314
+ .e-form-table-cell > .form-group
300
315
  {
301
- margin-bottom: 0.5rem;
316
+ margin-bottom: 1.5rem;
302
317
  }
303
318
 
304
319
 
305
- .table-cell > .form-table-renderer:last-child,
306
- .table-cell > .form-tabs-renderer:last-child,
307
- .table-cell > .form-card-renderer:last-child,
308
- .table-cell > .form-panel-renderer:last-child,
309
- .table-cell > .form-group:last-child
320
+ .e-form-table-cell > .form-table-renderer:last-child,
321
+ .e-form-table-cell > .form-tabs-renderer:last-child,
322
+ .e-form-table-cell > .form-card-renderer:last-child,
323
+ .e-form-table-cell > .form-panel-renderer:last-child,
324
+ .e-form-table-cell > .form-group:last-child
310
325
  {
311
326
  margin-bottom: 0;
312
327
  }
@@ -342,6 +357,7 @@
342
357
  }
343
358
 
344
359
  .tab-content-renderer {
360
+ padding-top: 10px;
345
361
  display: flex;
346
362
  flex-direction: column;
347
363
  gap: 1rem;
@@ -387,11 +403,11 @@
387
403
  border-color: #3d3d3d;
388
404
  }
389
405
 
390
- [data-theme="dark"] .table-row {
406
+ [data-theme="dark"] .e-form-table-row {
391
407
  border-color: #3d3d3d;
392
408
  }
393
409
 
394
- [data-theme="dark"] .table-cell {
410
+ [data-theme="dark"] .e-form-table-cell {
395
411
  border-color: #3d3d3d;
396
412
  }
397
413
 
@@ -442,7 +458,7 @@
442
458
  width: 100%;
443
459
  }
444
460
 
445
- .form-table-renderer .table-cell {
461
+ .form-table-renderer .e-form-table-cell {
446
462
  display: block;
447
463
  flex: 1 1 auto;
448
464
  min-width: 250px; /* minimum width before wrapping to next row */
@@ -457,17 +473,17 @@
457
473
  flex: 1 1 auto;
458
474
  }
459
475
 
460
- .table-border .table-cell {
476
+ .table-border .e-form-table-cell {
461
477
  border-right: none;
462
478
  border-bottom: 1px solid var(--sf-layout-border-color);
463
479
  border-radius: 4px;
464
480
  }
465
481
 
466
- .form-table-renderer .table-cell:last-child {
482
+ .form-table-renderer .e-form-table-cell:last-child {
467
483
  border-bottom: 1px solid var(--sf-layout-border-color);
468
484
  }
469
485
 
470
- .form-table-renderer .row:last-child .table-cell {
486
+ .form-table-renderer .row:last-child .e-form-table-cell {
471
487
  border-bottom: none;
472
488
  }
473
489
  }