@syncfusion/ej2-react-form-builder 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.
- package/Common/CheckboxGroup.d.ts +13 -0
- package/Common/CheckboxGroup.js +50 -0
- package/Common/ConditionalRuleEngine.d.ts +296 -0
- package/Common/ConditionalRuleEngine.js +566 -0
- package/Common/CustomTabComponent.d.ts +17 -0
- package/Common/CustomTabComponent.js +30 -0
- package/Common/CustomValidationEngine.d.ts +58 -0
- package/Common/CustomValidationEngine.js +146 -0
- package/Common/DataGridComponent.d.ts +20 -0
- package/Common/DataGridComponent.js +273 -0
- package/Common/FormValidator.d.ts +485 -0
- package/Common/FormValidator.js +575 -0
- package/Common/MinMaxRuleEngine.d.ts +105 -0
- package/Common/MinMaxRuleEngine.js +365 -0
- package/Common/StaticHtmlRenderer.d.ts +14 -0
- package/Common/StaticHtmlRenderer.js +24 -0
- package/Common/expressions/DependencyTracker.d.ts +30 -0
- package/Common/expressions/DependencyTracker.js +128 -0
- package/Common/expressions/ExpressionEngine.d.ts +95 -0
- package/Common/expressions/ExpressionEngine.js +506 -0
- package/Common/expressions/ExpressionParser.d.ts +41 -0
- package/Common/expressions/ExpressionParser.js +269 -0
- package/Common/expressions/useGridExpressions.d.ts +12 -0
- package/Common/expressions/useGridExpressions.js +71 -0
- package/Common/globalFormId.d.ts +26 -0
- package/Common/globalFormId.js +45 -0
- package/Common/json-converter.d.ts +444 -0
- package/Common/json-converter.js +1184 -0
- package/Common/parser.d.ts +98 -0
- package/Common/parser.js +753 -0
- package/Common/utils.d.ts +130 -0
- package/Common/utils.js +574 -0
- package/README.md +53 -0
- package/index.d.ts +6 -0
- package/index.js +6 -0
- package/license +13 -0
- package/package.json +54 -0
- package/src/FormBuilder.d.ts +211 -0
- package/src/FormBuilder.js +1299 -0
- package/src/components/Database/ConnectionForm.d.ts +8 -0
- package/src/components/Database/ConnectionForm.js +28 -0
- package/src/components/TopBar.d.ts +10 -0
- package/src/components/TopBar.js +7 -0
- package/src/components/icons/ComponentIcons.d.ts +44 -0
- package/src/components/icons/ComponentIcons.js +40 -0
- package/src/components/layout/FormFieldWrapper.d.ts +41 -0
- package/src/components/layout/FormFieldWrapper.js +112 -0
- package/src/components/layout/LeftPane.d.ts +23 -0
- package/src/components/layout/LeftPane.js +310 -0
- package/src/components/layout/ListBoxPane.d.ts +24 -0
- package/src/components/layout/ListBoxPane.js +94 -0
- package/src/components/layout/MainSection.d.ts +39 -0
- package/src/components/layout/MainSection.js +1766 -0
- package/src/components/layout/Preview.d.ts +12 -0
- package/src/components/layout/Preview.js +337 -0
- package/src/components/layout/RightPane.d.ts +22 -0
- package/src/components/layout/RightPane.js +370 -0
- package/src/components/theme/ThemeSwitcher.d.ts +14 -0
- package/src/components/theme/ThemeSwitcher.js +24 -0
- package/src/components/theme/theme-constant.d.ts +37 -0
- package/src/components/theme/theme-constant.js +23 -0
- package/src/config/component-properties.json +4929 -0
- package/src/config/form-setting.json +56 -0
- package/src/config/locale.d.ts +449 -0
- package/src/config/locale.js +449 -0
- package/src/context/FormSchemaContext.d.ts +32 -0
- package/src/context/FormSchemaContext.js +155 -0
- package/src/context/LocalizationContext.d.ts +27 -0
- package/src/context/LocalizationContext.js +43 -0
- package/src/context/ThemeContext.d.ts +23 -0
- package/src/context/ThemeContext.js +161 -0
- package/src/context/contexts.d.ts +6 -0
- package/src/context/contexts.js +6 -0
- package/src/context/defaultFormSchema.d.ts +6 -0
- package/src/context/defaultFormSchema.js +20 -0
- package/src/defaultPalette.d.ts +9 -0
- package/src/defaultPalette.js +45 -0
- package/src/defaultTemplate.d.ts +3 -0
- package/src/defaultTemplate.js +185 -0
- package/src/import/schemaImportUtils.d.ts +24 -0
- package/src/import/schemaImportUtils.js +121 -0
- package/src/index.d.ts +16 -0
- package/src/index.js +6 -0
- package/src/types/ActionButtons.d.ts +44 -0
- package/src/types/ActionButtons.js +27 -0
- package/src/types/ComponentProperties.d.ts +33 -0
- package/src/types/ComponentProperties.js +2 -0
- package/src/types/FormSchema.d.ts +585 -0
- package/src/types/FormSchema.js +147 -0
- package/src/types/connection.d.ts +19 -0
- package/src/types/connection.js +9 -0
- package/src/utils/AttributesEditor.d.ts +13 -0
- package/src/utils/AttributesEditor.js +117 -0
- package/src/utils/ButtonGroupEditor.d.ts +15 -0
- package/src/utils/ButtonGroupEditor.js +141 -0
- package/src/utils/ChoiceBasedFieldEditor.d.ts +16 -0
- package/src/utils/ChoiceBasedFieldEditor.js +87 -0
- package/src/utils/ClipboardHelper.d.ts +26 -0
- package/src/utils/ClipboardHelper.js +83 -0
- package/src/utils/ColumnBuilder.d.ts +11 -0
- package/src/utils/ColumnBuilder.js +153 -0
- package/src/utils/ColumnSpanEditor.d.ts +8 -0
- package/src/utils/ColumnSpanEditor.js +98 -0
- package/src/utils/ConditionDataEditor.d.ts +29 -0
- package/src/utils/ConditionDataEditor.js +177 -0
- package/src/utils/ConditionalEditorUtils.d.ts +27 -0
- package/src/utils/ConditionalEditorUtils.js +310 -0
- package/src/utils/ConditionsEditor.d.ts +20 -0
- package/src/utils/ConditionsEditor.js +571 -0
- package/src/utils/CustomAccordion.d.ts +13 -0
- package/src/utils/CustomAccordion.js +38 -0
- package/src/utils/CustomValidationEditor.d.ts +11 -0
- package/src/utils/CustomValidationEditor.js +208 -0
- package/src/utils/DataSourceCollector.d.ts +3 -0
- package/src/utils/DataSourceCollector.js +252 -0
- package/src/utils/ExpressionEditor.d.ts +13 -0
- package/src/utils/ExpressionEditor.js +99 -0
- package/src/utils/FormSettingsPanel.d.ts +9 -0
- package/src/utils/FormSettingsPanel.js +60 -0
- package/src/utils/LookupConfig.d.ts +11 -0
- package/src/utils/LookupConfig.js +159 -0
- package/src/utils/MinMaxValueEditor.d.ts +25 -0
- package/src/utils/MinMaxValueEditor.js +188 -0
- package/src/utils/OptionsEditor.d.ts +8 -0
- package/src/utils/OptionsEditor.js +79 -0
- package/src/utils/PropertyRenderer.d.ts +22 -0
- package/src/utils/PropertyRenderer.js +210 -0
- package/src/utils/ValueRenderer.d.ts +2 -0
- package/src/utils/ValueRenderer.js +91 -0
- package/src/utils/ej2DbAdaptor.d.ts +6 -0
- package/src/utils/ej2DbAdaptor.js +38 -0
- package/src/utils/mappingHeuristics.d.ts +10 -0
- package/src/utils/mappingHeuristics.js +33 -0
- package/src/utils/renderComponent.d.ts +18 -0
- package/src/utils/renderComponent.js +300 -0
- package/styles/tailwind3.css +67 -0
- package/styles/themes/action-buttons.css +110 -0
- package/styles/themes/datagrid.css +380 -0
- package/styles/themes/drag-reorder.css +248 -0
- package/styles/themes/import-dialog.css +292 -0
- package/styles/themes/index.css +658 -0
- package/styles/themes/left-pane.css +253 -0
- package/styles/themes/options-editor.css +63 -0
- package/styles/themes/preview.css +702 -0
- package/styles/themes/property-dialog.css +371 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useMemo, createContext, useContext } from 'react';
|
|
4
|
+
import { L10n } from '@syncfusion/ej2-base';
|
|
5
|
+
import { defaultLocale } from '../config/locale';
|
|
6
|
+
// Create the Localization context
|
|
7
|
+
export const LocalizationContext = createContext(undefined);
|
|
8
|
+
/**
|
|
9
|
+
* Hook to use Localization context
|
|
10
|
+
* Must be used within LocalizationProvider
|
|
11
|
+
*/
|
|
12
|
+
export const useLocalization = () => {
|
|
13
|
+
const context = useContext(LocalizationContext);
|
|
14
|
+
if (!context) {
|
|
15
|
+
throw new Error('useLocalization must be used within LocalizationProvider');
|
|
16
|
+
}
|
|
17
|
+
return context;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* LocalizationProvider manages the localization state with L10n
|
|
21
|
+
* Provides L10n instance to all components in the tree
|
|
22
|
+
*/
|
|
23
|
+
export const LocalizationProvider = ({ children, locale }) => {
|
|
24
|
+
// State for current locale
|
|
25
|
+
const [currentLocale, setCurrentLocale] = React.useState(() => {
|
|
26
|
+
if (locale && L10n?.locale?.[locale]) {
|
|
27
|
+
return locale;
|
|
28
|
+
}
|
|
29
|
+
return 'en-US';
|
|
30
|
+
});
|
|
31
|
+
// Create L10n instance with current locale
|
|
32
|
+
const l10n = useMemo(() => {
|
|
33
|
+
return new L10n('formbuilder', defaultLocale, currentLocale);
|
|
34
|
+
}, [currentLocale]);
|
|
35
|
+
// Memoize the context value to prevent unnecessary re-renders
|
|
36
|
+
const value = useMemo(() => ({
|
|
37
|
+
l10n,
|
|
38
|
+
locale: locale || 'en-US',
|
|
39
|
+
setLocale: setCurrentLocale
|
|
40
|
+
}), [l10n, currentLocale]);
|
|
41
|
+
return (_jsx(LocalizationContext.Provider, { value: value, children: children }));
|
|
42
|
+
};
|
|
43
|
+
export default LocalizationProvider;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReactNode, type JSX } from 'react';
|
|
2
|
+
import { type ThemeVariant, type ThemeMode, type ThemeConfig } from '../components/theme/theme-constant';
|
|
3
|
+
interface ThemeContextValue {
|
|
4
|
+
currentTheme: ThemeVariant;
|
|
5
|
+
themeMode: ThemeMode;
|
|
6
|
+
setTheme: (variant: ThemeVariant) => void;
|
|
7
|
+
setMode: (mode: ThemeMode) => void;
|
|
8
|
+
setThemeConfig: (config: ThemeConfig) => void;
|
|
9
|
+
}
|
|
10
|
+
interface ThemeProviderProps {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
showTopBar?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* ThemeProvider component - wraps the app and provides theme context
|
|
16
|
+
*/
|
|
17
|
+
export declare function ThemeProvider({ children, showTopBar }: ThemeProviderProps): JSX.Element;
|
|
18
|
+
/**
|
|
19
|
+
* Hook to access theme context
|
|
20
|
+
* @throws Error if used outside ThemeProvider
|
|
21
|
+
*/
|
|
22
|
+
export declare function useTheme(): ThemeContextValue;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ThemeContext - Global theme state management for Syncfusion EJ2 components
|
|
4
|
+
* Manages theme variant selection and light/dark mode with localStorage persistence
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { createContext, useContext, useCallback, useLayoutEffect } from 'react';
|
|
8
|
+
import { DEFAULT_THEME, THEME_STORAGE_KEY } from '../components/theme/theme-constant';
|
|
9
|
+
import TopBar from '../components/TopBar';
|
|
10
|
+
// Import theme CSS files with ?url suffix so Vite processes them correctly for production
|
|
11
|
+
import material3ThemeUrl from '../../styles/material3.css?url';
|
|
12
|
+
import tailwind3ThemeUrl from '../../styles/tailwind3.css?url';
|
|
13
|
+
import bootstrap53ThemeUrl from '../../styles/bootstrap5.3.css?url';
|
|
14
|
+
import fluent2ThemeUrl from '../../styles/fluent2.css?url';
|
|
15
|
+
const ThemeContext = createContext(undefined);
|
|
16
|
+
/**
|
|
17
|
+
* Load theme configuration from localStorage
|
|
18
|
+
*/
|
|
19
|
+
function loadThemeFromStorage() {
|
|
20
|
+
try {
|
|
21
|
+
const stored = localStorage.getItem(THEME_STORAGE_KEY);
|
|
22
|
+
if (stored) {
|
|
23
|
+
const parsed = JSON.parse(stored);
|
|
24
|
+
return {
|
|
25
|
+
variant: parsed.variant || DEFAULT_THEME.variant,
|
|
26
|
+
mode: parsed.mode || DEFAULT_THEME.mode
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const legacy = localStorage.getItem('theme');
|
|
30
|
+
if (legacy === 'light' || legacy === 'dark') {
|
|
31
|
+
return { ...DEFAULT_THEME, mode: legacy };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.warn('Failed to load theme from localStorage:', error);
|
|
36
|
+
}
|
|
37
|
+
// Detect system preference for dark mode
|
|
38
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
39
|
+
return {
|
|
40
|
+
...DEFAULT_THEME,
|
|
41
|
+
mode: prefersDark ? 'dark' : 'light'
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Save theme configuration to localStorage
|
|
46
|
+
*/
|
|
47
|
+
function saveThemeToStorage(config) {
|
|
48
|
+
try {
|
|
49
|
+
localStorage.setItem(THEME_STORAGE_KEY, JSON.stringify(config));
|
|
50
|
+
try {
|
|
51
|
+
localStorage.setItem('theme', config.mode);
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
// ignore
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.warn('Failed to save theme to localStorage:', error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Apply theme variant by updating/creating a link element
|
|
63
|
+
* This ensures only ONE theme is active at a time
|
|
64
|
+
*/
|
|
65
|
+
function applyThemeVariant(variant) {
|
|
66
|
+
const linkId = 'syncfusion-theme-dynamic';
|
|
67
|
+
let linkElement = document.getElementById(linkId);
|
|
68
|
+
if (!linkElement) {
|
|
69
|
+
// Create the link element if it doesn't exist
|
|
70
|
+
linkElement = document.createElement('link');
|
|
71
|
+
linkElement.id = linkId;
|
|
72
|
+
linkElement.rel = 'stylesheet';
|
|
73
|
+
linkElement.type = 'text/css';
|
|
74
|
+
document.head.appendChild(linkElement);
|
|
75
|
+
}
|
|
76
|
+
// Map variant to the actual theme file URL (Vite will handle these correctly in both dev and production)
|
|
77
|
+
const themePathMap = {
|
|
78
|
+
material3: material3ThemeUrl,
|
|
79
|
+
tailwind3: tailwind3ThemeUrl,
|
|
80
|
+
'bootstrap5.3': bootstrap53ThemeUrl,
|
|
81
|
+
fluent2: fluent2ThemeUrl
|
|
82
|
+
};
|
|
83
|
+
// Update href to switch theme (this replaces the old theme)
|
|
84
|
+
linkElement.href = themePathMap[variant];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Apply theme mode (light/dark) and variant by updating data-theme attribute and body classes
|
|
88
|
+
*/
|
|
89
|
+
function applyThemeMode(mode, variant) {
|
|
90
|
+
// Set data-theme attribute on root element
|
|
91
|
+
document.documentElement.setAttribute('data-theme', mode);
|
|
92
|
+
// Update body classes for Syncfusion components
|
|
93
|
+
if (mode === 'dark') {
|
|
94
|
+
document.body.classList.add('e-dark-mode');
|
|
95
|
+
document.body.classList.remove('e-light-mode');
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
document.body.classList.add('e-light-mode');
|
|
99
|
+
document.body.classList.remove('e-dark-mode');
|
|
100
|
+
}
|
|
101
|
+
// Add theme variant class to body if variant is provided
|
|
102
|
+
if (variant) {
|
|
103
|
+
// Remove all existing theme variant classes first
|
|
104
|
+
document.body.classList.remove('theme-material3', 'theme-tailwind3', 'theme-bootstrap5-3', 'theme-fluent2');
|
|
105
|
+
// Add current theme variant class (normalize bootstrap5.3 to bootstrap5-3 for CSS class)
|
|
106
|
+
const themeClass = `theme-${variant.replace('.', '-')}`;
|
|
107
|
+
document.body.classList.add(themeClass);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* ThemeProvider component - wraps the app and provides theme context
|
|
112
|
+
*/
|
|
113
|
+
export function ThemeProvider({ children, showTopBar = true }) {
|
|
114
|
+
const [config, setConfig] = React.useState(() => {
|
|
115
|
+
const loaded = loadThemeFromStorage();
|
|
116
|
+
applyThemeMode(loaded.mode, loaded.variant);
|
|
117
|
+
return loaded;
|
|
118
|
+
});
|
|
119
|
+
// Apply theme when config changes (user switches theme)
|
|
120
|
+
useLayoutEffect(() => {
|
|
121
|
+
applyThemeVariant(config.variant);
|
|
122
|
+
applyThemeMode(config.mode, config.variant);
|
|
123
|
+
saveThemeToStorage(config);
|
|
124
|
+
}, [config]);
|
|
125
|
+
const setTheme = useCallback((variant) => {
|
|
126
|
+
setConfig((prev) => ({ ...prev, variant }));
|
|
127
|
+
}, []);
|
|
128
|
+
const setMode = useCallback((mode) => {
|
|
129
|
+
setConfig((prev) => ({ ...prev, mode }));
|
|
130
|
+
}, []);
|
|
131
|
+
const setThemeConfig = useCallback((newConfig) => {
|
|
132
|
+
setConfig(newConfig);
|
|
133
|
+
}, []);
|
|
134
|
+
const value = {
|
|
135
|
+
currentTheme: config.variant,
|
|
136
|
+
themeMode: config.mode,
|
|
137
|
+
setTheme,
|
|
138
|
+
setMode,
|
|
139
|
+
setThemeConfig
|
|
140
|
+
};
|
|
141
|
+
return (_jsxs(ThemeContext.Provider, { value: value, children: [showTopBar ? (_jsx(TopBar, { themeMode: value.themeMode, currentTheme: value.currentTheme, setMode: value.setMode, setTheme: value.setTheme })) : null, children] }));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Hook to access theme context
|
|
145
|
+
* @throws Error if used outside ThemeProvider
|
|
146
|
+
*/
|
|
147
|
+
export function useTheme() {
|
|
148
|
+
const context = useContext(ThemeContext);
|
|
149
|
+
if (!context) {
|
|
150
|
+
console.warn('useTheme used without ThemeProvider — default theme will be assumed. Wrap your app with ThemeProvider to enable dynamic theming or import the theme CSS manually.');
|
|
151
|
+
const noop = () => { };
|
|
152
|
+
return {
|
|
153
|
+
currentTheme: DEFAULT_THEME.variant,
|
|
154
|
+
themeMode: DEFAULT_THEME.mode,
|
|
155
|
+
setTheme: noop,
|
|
156
|
+
setMode: noop,
|
|
157
|
+
setThemeConfig: noop
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return context;
|
|
161
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export all context-related exports from a single file
|
|
3
|
+
* This provides a clean import path for components
|
|
4
|
+
*/
|
|
5
|
+
export { FormSchemaContext, useFormSchema, FormSchemaProvider } from './FormSchemaContext';
|
|
6
|
+
export { LocalizationContext, useLocalization, LocalizationProvider } from './LocalizationContext';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export all context-related exports from a single file
|
|
3
|
+
* This provides a clean import path for components
|
|
4
|
+
*/
|
|
5
|
+
export { FormSchemaContext, useFormSchema, FormSchemaProvider } from './FormSchemaContext';
|
|
6
|
+
export { LocalizationContext, useLocalization, LocalizationProvider } from './LocalizationContext';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default form schema with a submit button
|
|
3
|
+
* This is used when no saved schema exists in localStorage
|
|
4
|
+
*/
|
|
5
|
+
export const defaultFormSchema = {
|
|
6
|
+
version: '0.1.0',
|
|
7
|
+
components: [{
|
|
8
|
+
id: 'submit_button_initial',
|
|
9
|
+
name: 'defaultFormsubmit',
|
|
10
|
+
type: 'button',
|
|
11
|
+
label: 'Submit',
|
|
12
|
+
style: 'primary',
|
|
13
|
+
buttonType: 'submit',
|
|
14
|
+
disabled: false,
|
|
15
|
+
_configured: true
|
|
16
|
+
}],
|
|
17
|
+
settings: {
|
|
18
|
+
name: 'Untitled Form',
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ComponentCategory, type PaletteItem } from './types/FormSchema';
|
|
2
|
+
export type DefaultPalette = {
|
|
3
|
+
[key in ComponentCategory]?: PaletteItem[];
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Default palette configuration - all available components organized by category
|
|
7
|
+
* Users can override this by providing paletteConfig prop to FormBuilder
|
|
8
|
+
*/
|
|
9
|
+
export declare const defaultPalette: DefaultPalette;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ComponentCategory, FormComponentType } from './types/FormSchema';
|
|
2
|
+
/**
|
|
3
|
+
* Default palette configuration - all available components organized by category
|
|
4
|
+
* Users can override this by providing paletteConfig prop to FormBuilder
|
|
5
|
+
*/
|
|
6
|
+
export const defaultPalette = {
|
|
7
|
+
[ComponentCategory.BASIC]: [
|
|
8
|
+
{ type: FormComponentType.TEXTBOX },
|
|
9
|
+
{ type: FormComponentType.TEXTAREA },
|
|
10
|
+
{ type: FormComponentType.CHECKBOX },
|
|
11
|
+
{ type: FormComponentType.RADIO },
|
|
12
|
+
{ type: FormComponentType.NUMBER },
|
|
13
|
+
{ type: FormComponentType.INPUT_MASK },
|
|
14
|
+
{ type: FormComponentType.DROPDOWN },
|
|
15
|
+
{ type: FormComponentType.MULTISELECT },
|
|
16
|
+
{ type: FormComponentType.DATE },
|
|
17
|
+
{ type: FormComponentType.BUTTON }
|
|
18
|
+
],
|
|
19
|
+
[ComponentCategory.ADVANCED]: [
|
|
20
|
+
{ type: FormComponentType.CHECKBOX_GROUP },
|
|
21
|
+
{ type: FormComponentType.DATE_TIME },
|
|
22
|
+
{ type: FormComponentType.TIME },
|
|
23
|
+
{ type: FormComponentType.DATE_RANGE },
|
|
24
|
+
{ type: FormComponentType.SWITCH },
|
|
25
|
+
{ type: FormComponentType.RATING },
|
|
26
|
+
{ type: FormComponentType.SPLIT_BUTTON },
|
|
27
|
+
{ type: FormComponentType.RANGE_SLIDER },
|
|
28
|
+
{ type: FormComponentType.SIGNATURE },
|
|
29
|
+
{ type: FormComponentType.IMAGE_EDITOR },
|
|
30
|
+
{ type: FormComponentType.FILE_UPLOAD },
|
|
31
|
+
{ type: FormComponentType.COLOR_PICKER },
|
|
32
|
+
// { type: FormComponentType.LOOKUP },
|
|
33
|
+
{ type: FormComponentType.RICH_TEXT_EDITOR },
|
|
34
|
+
{ type: FormComponentType.DATA_GRID },
|
|
35
|
+
// { type: FormComponentType.AUTO_NUMBER }
|
|
36
|
+
],
|
|
37
|
+
[ComponentCategory.LAYOUT]: [
|
|
38
|
+
{ type: FormComponentType.MESSAGE },
|
|
39
|
+
{ type: FormComponentType.PANEL },
|
|
40
|
+
{ type: FormComponentType.TABLE },
|
|
41
|
+
{ type: FormComponentType.TABS },
|
|
42
|
+
{ type: FormComponentType.CARD },
|
|
43
|
+
{ type: FormComponentType.STATIC_HTML }
|
|
44
|
+
]
|
|
45
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
export const defaultTemplates = [
|
|
2
|
+
{
|
|
3
|
+
id: 'loginForm',
|
|
4
|
+
title: 'Login Form',
|
|
5
|
+
schema: {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
email: {
|
|
9
|
+
type: 'string',
|
|
10
|
+
title: 'Email Address',
|
|
11
|
+
name: 'emailAddress',
|
|
12
|
+
description: 'Enter your email',
|
|
13
|
+
format: 'email'
|
|
14
|
+
},
|
|
15
|
+
password: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
title: 'Password',
|
|
18
|
+
name: 'password',
|
|
19
|
+
description: 'Enter your password',
|
|
20
|
+
minLength: 6
|
|
21
|
+
},
|
|
22
|
+
rememberMe: {
|
|
23
|
+
type: 'boolean',
|
|
24
|
+
title: 'Remember Me',
|
|
25
|
+
name: 'remember',
|
|
26
|
+
default: false
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
required: ['email', 'password']
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'registrationForm',
|
|
34
|
+
title: 'User Registration',
|
|
35
|
+
schema: {
|
|
36
|
+
"version": "0.1.0",
|
|
37
|
+
"properties": {
|
|
38
|
+
"firstName": {
|
|
39
|
+
"id": "textbox_1780395123369_348",
|
|
40
|
+
"type": "string",
|
|
41
|
+
"label": "First Name",
|
|
42
|
+
"name": 'firstName',
|
|
43
|
+
"minLength": 2,
|
|
44
|
+
"widget": "textbox"
|
|
45
|
+
},
|
|
46
|
+
"lastName": {
|
|
47
|
+
"id": "textbox_1780395123369_714",
|
|
48
|
+
"type": "string",
|
|
49
|
+
"label": "Last Name",
|
|
50
|
+
"name": 'lastName',
|
|
51
|
+
"minLength": 2,
|
|
52
|
+
"widget": "textbox"
|
|
53
|
+
},
|
|
54
|
+
"emailAddress": {
|
|
55
|
+
"id": "textbox_1780395123369_215",
|
|
56
|
+
"type": "string",
|
|
57
|
+
"label": "Email Address",
|
|
58
|
+
"name": 'emailAddress',
|
|
59
|
+
"textboxType": "email",
|
|
60
|
+
"widget": "textbox"
|
|
61
|
+
},
|
|
62
|
+
"password": {
|
|
63
|
+
"id": "textbox_1780395123369_201",
|
|
64
|
+
"name": "password_1",
|
|
65
|
+
"type": "string",
|
|
66
|
+
"label": "Password",
|
|
67
|
+
"textboxType": "password",
|
|
68
|
+
"minLength": 8,
|
|
69
|
+
"widget": "textbox"
|
|
70
|
+
},
|
|
71
|
+
"confirmPassword": {
|
|
72
|
+
"id": "textbox_1780395123369_608",
|
|
73
|
+
"name": "password_2",
|
|
74
|
+
"type": "string",
|
|
75
|
+
"label": "Confirm Password",
|
|
76
|
+
"textboxType": "password",
|
|
77
|
+
"minLength": 8,
|
|
78
|
+
"widget": "textbox",
|
|
79
|
+
"customValidation": [
|
|
80
|
+
{
|
|
81
|
+
"expression": "valid = (input === {password_1}) ? true : 'Confirm password should match the password'"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
"iAgreeToTheTermsAndConditions": {
|
|
86
|
+
"id": "checkbox_1780395123369_384",
|
|
87
|
+
"name": "agree",
|
|
88
|
+
"type": "boolean",
|
|
89
|
+
"label": "I agree to the Terms and Conditions",
|
|
90
|
+
"widget": "checkbox"
|
|
91
|
+
},
|
|
92
|
+
"submit": {
|
|
93
|
+
"id": "submit_button_initial",
|
|
94
|
+
"type": "button",
|
|
95
|
+
"name": "default_submit",
|
|
96
|
+
"label": "Submit",
|
|
97
|
+
"buttonType": "submit",
|
|
98
|
+
"widget": "button",
|
|
99
|
+
"style": "primary",
|
|
100
|
+
"disabled": false
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"layout": [
|
|
104
|
+
{
|
|
105
|
+
"type": "field",
|
|
106
|
+
"propertyId": "firstName"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"type": "field",
|
|
110
|
+
"propertyId": "lastName"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"type": "field",
|
|
114
|
+
"propertyId": "emailAddress"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"type": "field",
|
|
118
|
+
"propertyId": "password"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"type": "field",
|
|
122
|
+
"propertyId": "confirmPassword"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"type": "field",
|
|
126
|
+
"propertyId": "iAgreeToTheTermsAndConditions"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"type": "field",
|
|
130
|
+
"propertyId": "submit"
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
"settings": {
|
|
134
|
+
"name": "Untitled Form"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: 'feedbackSurvey',
|
|
140
|
+
title: 'Feedback Survey',
|
|
141
|
+
schema: {
|
|
142
|
+
"version": "1.0",
|
|
143
|
+
"properties": {
|
|
144
|
+
"howSatisfiedAreYou": {
|
|
145
|
+
"id": "dropdown_1774507299146_461",
|
|
146
|
+
"type": "string",
|
|
147
|
+
"name": "satisfaction",
|
|
148
|
+
"label": "How satisfied are you?",
|
|
149
|
+
"options": [
|
|
150
|
+
"very_satisfied",
|
|
151
|
+
"satisfied",
|
|
152
|
+
"neutral",
|
|
153
|
+
"dissatisfied",
|
|
154
|
+
"very_dissatisfied"
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
"wouldYouRecommendUs": {
|
|
158
|
+
"id": "dropdown_1774507299146_513",
|
|
159
|
+
"type": "string",
|
|
160
|
+
"name": "recommendation",
|
|
161
|
+
"label": "Would you recommend us?",
|
|
162
|
+
"options": [
|
|
163
|
+
"yes",
|
|
164
|
+
"maybe",
|
|
165
|
+
"no"
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
"additionalFeedback": {
|
|
169
|
+
"id": "textarea_1774507317278_373",
|
|
170
|
+
"type": "string",
|
|
171
|
+
"name": "feedback",
|
|
172
|
+
"label": "Additional Feedback"
|
|
173
|
+
},
|
|
174
|
+
"submit": {
|
|
175
|
+
"id": "button_1774507299146_562",
|
|
176
|
+
"type": "button",
|
|
177
|
+
"name": "default_submit",
|
|
178
|
+
"label": "Submit",
|
|
179
|
+
"buttonType": "submit"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
];
|
|
185
|
+
export default defaultTemplates;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ValidationResult } from '../../Common/parser';
|
|
2
|
+
import type { FormSchema } from '../types/FormSchema';
|
|
3
|
+
/**
|
|
4
|
+
* Utility functions for split and full schema import/validation
|
|
5
|
+
* Used by both ImportDialog and FileImportDialog
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Validate unified schema (properties + layout)
|
|
9
|
+
*/
|
|
10
|
+
export declare const validateSplitSchemas: (dataSchemaInput: string, _uiSchemaInput: string) => ValidationResult;
|
|
11
|
+
/**
|
|
12
|
+
* Validate full schema (single JSON)
|
|
13
|
+
*/
|
|
14
|
+
export declare const validateFullSchema: (input: string) => ValidationResult;
|
|
15
|
+
/**
|
|
16
|
+
* Import unified schema with merge
|
|
17
|
+
* Accepts unified schema (properties + layout) and converts to FormSchema
|
|
18
|
+
* Also supports legacy format (FormComponent array) for backward compatibility
|
|
19
|
+
*/
|
|
20
|
+
export declare const importSplitSchemas: (dataSchemaInput: string, currentFormSchema: FormSchema) => FormSchema;
|
|
21
|
+
/**
|
|
22
|
+
* Import full schema
|
|
23
|
+
*/
|
|
24
|
+
export declare const importFullSchema: (input: string) => FormSchema;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { UniversalJsonParser } from '../../Common/parser';
|
|
2
|
+
import { splitSchema, mergeSchema, mergeWithIDRemapping, convertComponentsToDataSchema } from '../../Common/json-converter';
|
|
3
|
+
/**
|
|
4
|
+
* Utility functions for split and full schema import/validation
|
|
5
|
+
* Used by both ImportDialog and FileImportDialog
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Validate unified schema (properties + layout)
|
|
9
|
+
*/
|
|
10
|
+
export const validateSplitSchemas = (dataSchemaInput, _uiSchemaInput) => {
|
|
11
|
+
const errors = [];
|
|
12
|
+
const trimmedDataInput = dataSchemaInput.trim();
|
|
13
|
+
if (!trimmedDataInput) {
|
|
14
|
+
return {
|
|
15
|
+
valid: false,
|
|
16
|
+
errors: ['Please provide a schema']
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const testParse = JSON.parse(trimmedDataInput);
|
|
21
|
+
// Check if it's unified schema (has properties and layout)
|
|
22
|
+
const isUnifiedSchema = testParse.properties && Array.isArray(testParse.layout);
|
|
23
|
+
if (isUnifiedSchema) {
|
|
24
|
+
// Validate unified schema structure
|
|
25
|
+
if (typeof testParse.properties !== 'object') {
|
|
26
|
+
errors.push('Invalid schema: "properties" must be an object');
|
|
27
|
+
return { valid: false, errors };
|
|
28
|
+
}
|
|
29
|
+
return { valid: true };
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Try to parse as legacy format (FormComponent array)
|
|
33
|
+
const parser = new UniversalJsonParser();
|
|
34
|
+
const parseResult = parser.parse(trimmedDataInput);
|
|
35
|
+
if (!parseResult.success) {
|
|
36
|
+
errors.push(`Failed to parse schema: ${parseResult.errors.join(', ')}`);
|
|
37
|
+
return { valid: false, errors };
|
|
38
|
+
}
|
|
39
|
+
return { valid: true };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
errors.push(`Invalid JSON: ${e.message}`);
|
|
44
|
+
return { valid: false, errors };
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Validate full schema (single JSON)
|
|
49
|
+
*/
|
|
50
|
+
export const validateFullSchema = (input) => {
|
|
51
|
+
const trimmedInput = input.trim();
|
|
52
|
+
if (!trimmedInput || trimmedInput.length === 0) {
|
|
53
|
+
return {
|
|
54
|
+
valid: false,
|
|
55
|
+
errors: ['Please paste a full form schema JSON']
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const parser = new UniversalJsonParser();
|
|
59
|
+
const parseResult = parser.parse(trimmedInput);
|
|
60
|
+
return {
|
|
61
|
+
valid: parseResult?.success || false,
|
|
62
|
+
errors: parseResult?.errors.length > 0 ? parseResult.errors : undefined,
|
|
63
|
+
warnings: parseResult?.warnings.length > 0 ? parseResult.warnings : undefined
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Import unified schema with merge
|
|
68
|
+
* Accepts unified schema (properties + layout) and converts to FormSchema
|
|
69
|
+
* Also supports legacy format (FormComponent array) for backward compatibility
|
|
70
|
+
*/
|
|
71
|
+
export const importSplitSchemas = (dataSchemaInput, currentFormSchema) => {
|
|
72
|
+
const trimmedDataInput = dataSchemaInput.trim();
|
|
73
|
+
if (!trimmedDataInput) {
|
|
74
|
+
throw new Error('Please provide a schema');
|
|
75
|
+
}
|
|
76
|
+
let mergedSchema;
|
|
77
|
+
// Parse the input
|
|
78
|
+
const testParse = JSON.parse(trimmedDataInput);
|
|
79
|
+
// Check if it's unified schema format (has properties and layout)
|
|
80
|
+
const isUnifiedSchema = testParse.properties && Array.isArray(testParse.layout);
|
|
81
|
+
if (isUnifiedSchema) {
|
|
82
|
+
// ✅ NEW PATH: Unified schema - merge directly
|
|
83
|
+
mergedSchema = mergeSchema(testParse);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// ✅ LEGACY PATH: FormComponent array or old format - convert and merge with ID remapping
|
|
87
|
+
const parser = new UniversalJsonParser();
|
|
88
|
+
const parseResult = parser.parse(trimmedDataInput);
|
|
89
|
+
if (!parseResult.success || !parseResult.schema) {
|
|
90
|
+
throw new Error(`Failed to parse schema: ${parseResult.errors.join(', ')}`);
|
|
91
|
+
}
|
|
92
|
+
// Convert FormComponents to DataSchema
|
|
93
|
+
const dataSchema = convertComponentsToDataSchema(parseResult.schema.components);
|
|
94
|
+
// Get existing UI schema from current form
|
|
95
|
+
const currentUnified = splitSchema(currentFormSchema);
|
|
96
|
+
const currentUISchema = {
|
|
97
|
+
properties: currentUnified.properties,
|
|
98
|
+
layout: currentUnified.layout
|
|
99
|
+
};
|
|
100
|
+
// Merge with ID remapping to preserve layout stability
|
|
101
|
+
mergedSchema = mergeWithIDRemapping(dataSchema, currentUISchema);
|
|
102
|
+
}
|
|
103
|
+
return mergedSchema;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Import full schema
|
|
107
|
+
*/
|
|
108
|
+
export const importFullSchema = (input) => {
|
|
109
|
+
const trimmedInput = input.trim();
|
|
110
|
+
if (!trimmedInput || trimmedInput.length === 0) {
|
|
111
|
+
throw new Error('Please paste JSON content');
|
|
112
|
+
}
|
|
113
|
+
const parser = new UniversalJsonParser();
|
|
114
|
+
const parseResult = parser.parse(trimmedInput);
|
|
115
|
+
if (parseResult?.success && parseResult?.schema) {
|
|
116
|
+
return parseResult.schema;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
throw new Error(parseResult?.errors.join(', ') || 'Failed to parse schema');
|
|
120
|
+
}
|
|
121
|
+
};
|