@magnet-cms/plugin-playground 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/index.cjs +1023 -0
- package/dist/backend/index.d.cts +10 -0
- package/dist/backend/index.d.ts +10 -0
- package/dist/backend/index.js +1 -0
- package/dist/chunk-WY4YMBWZ.js +1044 -0
- package/dist/frontend/bundle.iife.js +2163 -0
- package/dist/frontend/bundle.iife.js.map +1 -0
- package/dist/index.cjs +1135 -0
- package/dist/index.d.cts +36 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +76 -0
- package/package.json +81 -0
- package/src/frontend/index.ts +110 -0
- package/src/frontend/pages/Playground/Editor/AddFieldDialog.tsx +187 -0
- package/src/frontend/pages/Playground/Editor/CodePreview.tsx +59 -0
- package/src/frontend/pages/Playground/Editor/FieldCard.tsx +161 -0
- package/src/frontend/pages/Playground/Editor/FieldList.tsx +121 -0
- package/src/frontend/pages/Playground/Editor/FieldSettingsPanel.tsx +652 -0
- package/src/frontend/pages/Playground/Editor/RelationConfigModal.tsx +292 -0
- package/src/frontend/pages/Playground/Editor/SchemaList.tsx +76 -0
- package/src/frontend/pages/Playground/Editor/SchemaOptionsDialog.tsx +109 -0
- package/src/frontend/pages/Playground/Editor/index.tsx +322 -0
- package/src/frontend/pages/Playground/constants/field-types.ts +384 -0
- package/src/frontend/pages/Playground/hooks/useSchemaBuilder.ts +280 -0
- package/src/frontend/pages/Playground/index.tsx +19 -0
- package/src/frontend/pages/Playground/types/builder.types.ts +191 -0
- package/src/frontend/pages/Playground/utils/code-generator.ts +319 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useCallback,
|
|
4
|
+
useContext,
|
|
5
|
+
useMemo,
|
|
6
|
+
useReducer,
|
|
7
|
+
} from 'react'
|
|
8
|
+
import { getFieldTypeDefinition } from '../constants/field-types'
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_BUILDER_STATE,
|
|
11
|
+
FIELD_TYPE_TO_TS_TYPE,
|
|
12
|
+
type SchemaBuilderAction,
|
|
13
|
+
type SchemaBuilderContextType,
|
|
14
|
+
type SchemaBuilderState,
|
|
15
|
+
type SchemaConfig,
|
|
16
|
+
type SchemaField,
|
|
17
|
+
type ViewMode,
|
|
18
|
+
} from '../types/builder.types'
|
|
19
|
+
import { generateSchemaCode, generateSchemaJSON } from '../utils/code-generator'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Generate a unique ID for fields
|
|
23
|
+
*/
|
|
24
|
+
function generateId(): string {
|
|
25
|
+
return `field_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Convert display name to API ID (camelCase)
|
|
30
|
+
*/
|
|
31
|
+
function toApiId(displayName: string): string {
|
|
32
|
+
return displayName
|
|
33
|
+
.toLowerCase()
|
|
34
|
+
.replace(/[^a-z0-9\s]/g, '')
|
|
35
|
+
.split(/\s+/)
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
.map((word, index) =>
|
|
38
|
+
index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1),
|
|
39
|
+
)
|
|
40
|
+
.join('')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Schema builder reducer
|
|
45
|
+
*/
|
|
46
|
+
function schemaBuilderReducer(
|
|
47
|
+
state: SchemaBuilderState,
|
|
48
|
+
action: SchemaBuilderAction,
|
|
49
|
+
): SchemaBuilderState {
|
|
50
|
+
switch (action.type) {
|
|
51
|
+
case 'SET_SCHEMA':
|
|
52
|
+
return {
|
|
53
|
+
...state,
|
|
54
|
+
schema: { ...state.schema, ...action.payload },
|
|
55
|
+
isDirty: true,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
case 'ADD_FIELD':
|
|
59
|
+
return {
|
|
60
|
+
...state,
|
|
61
|
+
fields: [...state.fields, action.payload],
|
|
62
|
+
selectedFieldId: action.payload.id,
|
|
63
|
+
isDirty: true,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
case 'UPDATE_FIELD':
|
|
67
|
+
return {
|
|
68
|
+
...state,
|
|
69
|
+
fields: state.fields.map((field) =>
|
|
70
|
+
field.id === action.payload.id
|
|
71
|
+
? { ...field, ...action.payload.changes }
|
|
72
|
+
: field,
|
|
73
|
+
),
|
|
74
|
+
isDirty: true,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
case 'DELETE_FIELD':
|
|
78
|
+
return {
|
|
79
|
+
...state,
|
|
80
|
+
fields: state.fields.filter((field) => field.id !== action.payload),
|
|
81
|
+
selectedFieldId:
|
|
82
|
+
state.selectedFieldId === action.payload
|
|
83
|
+
? null
|
|
84
|
+
: state.selectedFieldId,
|
|
85
|
+
isDirty: true,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
case 'REORDER_FIELDS':
|
|
89
|
+
return {
|
|
90
|
+
...state,
|
|
91
|
+
fields: action.payload,
|
|
92
|
+
isDirty: true,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
case 'SELECT_FIELD':
|
|
96
|
+
return {
|
|
97
|
+
...state,
|
|
98
|
+
selectedFieldId: action.payload,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
case 'SET_VIEW_MODE':
|
|
102
|
+
return {
|
|
103
|
+
...state,
|
|
104
|
+
viewMode: action.payload,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
case 'MARK_DIRTY':
|
|
108
|
+
return {
|
|
109
|
+
...state,
|
|
110
|
+
isDirty: true,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
case 'MARK_SAVED':
|
|
114
|
+
return {
|
|
115
|
+
...state,
|
|
116
|
+
isDirty: false,
|
|
117
|
+
lastSaved: new Date(),
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
case 'RESET':
|
|
121
|
+
return action.payload
|
|
122
|
+
|
|
123
|
+
case 'LOAD_SCHEMA':
|
|
124
|
+
return {
|
|
125
|
+
...state,
|
|
126
|
+
schema: action.payload.schema,
|
|
127
|
+
fields: action.payload.fields,
|
|
128
|
+
isDirty: false,
|
|
129
|
+
isNew: false,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
default:
|
|
133
|
+
return state
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Schema builder context
|
|
139
|
+
*/
|
|
140
|
+
export const SchemaBuilderContext =
|
|
141
|
+
createContext<SchemaBuilderContextType | null>(null)
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Hook to access the schema builder context
|
|
145
|
+
*/
|
|
146
|
+
export function useSchemaBuilder(): SchemaBuilderContextType {
|
|
147
|
+
const context = useContext(SchemaBuilderContext)
|
|
148
|
+
if (!context) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
'useSchemaBuilder must be used within a SchemaBuilderProvider',
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
return context
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Hook to create the schema builder state and actions
|
|
158
|
+
*/
|
|
159
|
+
export function useSchemaBuilderState(
|
|
160
|
+
initialState: SchemaBuilderState = DEFAULT_BUILDER_STATE,
|
|
161
|
+
): SchemaBuilderContextType {
|
|
162
|
+
const [state, dispatch] = useReducer(schemaBuilderReducer, initialState)
|
|
163
|
+
|
|
164
|
+
// Convenience actions
|
|
165
|
+
const addField = useCallback((partial: Partial<SchemaField>) => {
|
|
166
|
+
const fieldType = partial.type || 'text'
|
|
167
|
+
const definition = getFieldTypeDefinition(fieldType)
|
|
168
|
+
const displayName = partial.displayName || 'New Field'
|
|
169
|
+
const name = partial.name || toApiId(displayName)
|
|
170
|
+
|
|
171
|
+
const field: SchemaField = {
|
|
172
|
+
id: generateId(),
|
|
173
|
+
name,
|
|
174
|
+
displayName,
|
|
175
|
+
type: fieldType,
|
|
176
|
+
tsType:
|
|
177
|
+
definition?.tsType || FIELD_TYPE_TO_TS_TYPE[fieldType] || 'string',
|
|
178
|
+
prop: {
|
|
179
|
+
required: false,
|
|
180
|
+
unique: false,
|
|
181
|
+
...partial.prop,
|
|
182
|
+
},
|
|
183
|
+
ui: {
|
|
184
|
+
tab: 'General',
|
|
185
|
+
...definition?.defaultUI,
|
|
186
|
+
...partial.ui,
|
|
187
|
+
},
|
|
188
|
+
validations: partial.validations || definition?.defaultValidations || [],
|
|
189
|
+
relationConfig: partial.relationConfig,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
dispatch({ type: 'ADD_FIELD', payload: field })
|
|
193
|
+
}, [])
|
|
194
|
+
|
|
195
|
+
const updateField = useCallback(
|
|
196
|
+
(id: string, changes: Partial<SchemaField>) => {
|
|
197
|
+
dispatch({ type: 'UPDATE_FIELD', payload: { id, changes } })
|
|
198
|
+
},
|
|
199
|
+
[],
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
const deleteField = useCallback((id: string) => {
|
|
203
|
+
dispatch({ type: 'DELETE_FIELD', payload: id })
|
|
204
|
+
}, [])
|
|
205
|
+
|
|
206
|
+
const selectField = useCallback((id: string | null) => {
|
|
207
|
+
dispatch({ type: 'SELECT_FIELD', payload: id })
|
|
208
|
+
}, [])
|
|
209
|
+
|
|
210
|
+
const reorderFields = useCallback((fields: SchemaField[]) => {
|
|
211
|
+
dispatch({ type: 'REORDER_FIELDS', payload: fields })
|
|
212
|
+
}, [])
|
|
213
|
+
|
|
214
|
+
const setViewMode = useCallback((mode: ViewMode) => {
|
|
215
|
+
dispatch({ type: 'SET_VIEW_MODE', payload: mode })
|
|
216
|
+
}, [])
|
|
217
|
+
|
|
218
|
+
const updateSchema = useCallback((changes: Partial<SchemaConfig>) => {
|
|
219
|
+
dispatch({ type: 'SET_SCHEMA', payload: changes })
|
|
220
|
+
}, [])
|
|
221
|
+
|
|
222
|
+
const resetState = useCallback((newState?: SchemaBuilderState) => {
|
|
223
|
+
dispatch({ type: 'RESET', payload: newState || DEFAULT_BUILDER_STATE })
|
|
224
|
+
}, [])
|
|
225
|
+
|
|
226
|
+
// Computed values
|
|
227
|
+
const selectedField = useMemo(
|
|
228
|
+
() => state.fields.find((f) => f.id === state.selectedFieldId) ?? null,
|
|
229
|
+
[state.fields, state.selectedFieldId],
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
const generatedCode = useMemo(() => generateSchemaCode(state), [state])
|
|
233
|
+
|
|
234
|
+
const generatedJSON = useMemo(() => generateSchemaJSON(state), [state])
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
state,
|
|
238
|
+
dispatch,
|
|
239
|
+
addField,
|
|
240
|
+
updateField,
|
|
241
|
+
deleteField,
|
|
242
|
+
selectField,
|
|
243
|
+
reorderFields,
|
|
244
|
+
setViewMode,
|
|
245
|
+
updateSchema,
|
|
246
|
+
resetState,
|
|
247
|
+
selectedField,
|
|
248
|
+
generatedCode,
|
|
249
|
+
generatedJSON,
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Create a field from a field type definition
|
|
255
|
+
*/
|
|
256
|
+
export function createFieldFromType(
|
|
257
|
+
type: SchemaField['type'],
|
|
258
|
+
displayName: string,
|
|
259
|
+
): Partial<SchemaField> {
|
|
260
|
+
const definition = getFieldTypeDefinition(type)
|
|
261
|
+
if (!definition) {
|
|
262
|
+
return { type, displayName }
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
type,
|
|
267
|
+
displayName,
|
|
268
|
+
name: toApiId(displayName),
|
|
269
|
+
tsType: definition.tsType,
|
|
270
|
+
validations: [...definition.defaultValidations],
|
|
271
|
+
ui: { ...definition.defaultUI },
|
|
272
|
+
prop: { required: false, unique: false },
|
|
273
|
+
...(definition.hasRelationConfig && {
|
|
274
|
+
relationConfig: {
|
|
275
|
+
targetSchema: '',
|
|
276
|
+
relationType: 'manyToOne',
|
|
277
|
+
},
|
|
278
|
+
}),
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { useNavigate } from 'react-router-dom'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Playground index - redirects to the editor with 3-column layout
|
|
6
|
+
* The schema list is now integrated into the editor sidebar
|
|
7
|
+
*/
|
|
8
|
+
const Playground = () => {
|
|
9
|
+
const navigate = useNavigate()
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
// Redirect to new schema editor - the schema list is shown in the sidebar
|
|
13
|
+
navigate('/playground/new', { replace: true })
|
|
14
|
+
}, [navigate])
|
|
15
|
+
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default Playground
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema Playground Builder Types
|
|
3
|
+
*
|
|
4
|
+
* These types define the state structure for the visual schema builder.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Supported field types in the schema builder
|
|
9
|
+
*/
|
|
10
|
+
export type FieldType =
|
|
11
|
+
| 'text'
|
|
12
|
+
| 'number'
|
|
13
|
+
| 'date'
|
|
14
|
+
| 'boolean'
|
|
15
|
+
| 'select'
|
|
16
|
+
| 'relation'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Select/dropdown option structure
|
|
20
|
+
*/
|
|
21
|
+
export interface SelectOption {
|
|
22
|
+
key: string
|
|
23
|
+
value: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Relation field configuration
|
|
28
|
+
*/
|
|
29
|
+
export interface RelationConfig {
|
|
30
|
+
targetSchema: string
|
|
31
|
+
relationType: 'oneToOne' | 'oneToMany' | 'manyToOne' | 'manyToMany'
|
|
32
|
+
inverseSide?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Validation rule structure (maps to class-validator decorators)
|
|
37
|
+
*/
|
|
38
|
+
export interface ValidationRule {
|
|
39
|
+
type: string // e.g., 'IsString', 'IsNotEmpty', 'Length', 'Min', 'Max'
|
|
40
|
+
constraints?: (string | number)[] // e.g., [10, 255] for Length
|
|
41
|
+
message?: string // Custom error message
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* UI configuration (maps to @UI() decorator options)
|
|
46
|
+
*/
|
|
47
|
+
export interface FieldUIConfig {
|
|
48
|
+
type?: string // UI type override (e.g., 'switch' for boolean)
|
|
49
|
+
label?: string // Display label
|
|
50
|
+
description?: string // Help text
|
|
51
|
+
placeholder?: string // Input placeholder
|
|
52
|
+
tab?: string // Tab name for grouping
|
|
53
|
+
side?: boolean // Show in side panel
|
|
54
|
+
row?: boolean // Half-width layout
|
|
55
|
+
options?: SelectOption[] // For select/radio fields
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Property configuration (maps to @Prop() decorator options)
|
|
60
|
+
*/
|
|
61
|
+
export interface FieldPropConfig {
|
|
62
|
+
required?: boolean
|
|
63
|
+
unique?: boolean
|
|
64
|
+
default?: unknown
|
|
65
|
+
intl?: boolean // Enable i18n for this field
|
|
66
|
+
hidden?: boolean // Hide from UI
|
|
67
|
+
readonly?: boolean
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Complete field definition in the builder
|
|
72
|
+
*/
|
|
73
|
+
export interface SchemaField {
|
|
74
|
+
id: string // Unique ID for React keys and drag-drop
|
|
75
|
+
name: string // API ID / property name (e.g., 'firstName')
|
|
76
|
+
displayName: string // Human-readable label (e.g., 'First Name')
|
|
77
|
+
type: FieldType // Field type
|
|
78
|
+
tsType: string // TypeScript type (string, number, Date, boolean, etc.)
|
|
79
|
+
prop: FieldPropConfig // @Prop() options
|
|
80
|
+
ui: FieldUIConfig // @UI() options
|
|
81
|
+
validations: ValidationRule[] // @Validators() rules
|
|
82
|
+
relationConfig?: RelationConfig // For relation fields
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Schema-level configuration (maps to @Schema() decorator options)
|
|
87
|
+
*/
|
|
88
|
+
export interface SchemaConfig {
|
|
89
|
+
name: string // Class name (e.g., 'Cat')
|
|
90
|
+
apiId?: string // API identifier (e.g., 'cat')
|
|
91
|
+
versioning: boolean // Enable version history
|
|
92
|
+
i18n: boolean // Enable internationalization
|
|
93
|
+
description?: string // Schema description
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* View modes for the editor
|
|
98
|
+
*/
|
|
99
|
+
export type ViewMode = 'builder' | 'json' | 'code'
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Complete builder state
|
|
103
|
+
*/
|
|
104
|
+
export interface SchemaBuilderState {
|
|
105
|
+
schema: SchemaConfig
|
|
106
|
+
fields: SchemaField[]
|
|
107
|
+
selectedFieldId: string | null
|
|
108
|
+
viewMode: ViewMode
|
|
109
|
+
isDirty: boolean
|
|
110
|
+
lastSaved: Date | null
|
|
111
|
+
isNew: boolean // Whether this is a new schema or editing existing
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Reducer action types
|
|
116
|
+
*/
|
|
117
|
+
export type SchemaBuilderAction =
|
|
118
|
+
| { type: 'SET_SCHEMA'; payload: Partial<SchemaConfig> }
|
|
119
|
+
| { type: 'ADD_FIELD'; payload: SchemaField }
|
|
120
|
+
| {
|
|
121
|
+
type: 'UPDATE_FIELD'
|
|
122
|
+
payload: { id: string; changes: Partial<SchemaField> }
|
|
123
|
+
}
|
|
124
|
+
| { type: 'DELETE_FIELD'; payload: string }
|
|
125
|
+
| { type: 'REORDER_FIELDS'; payload: SchemaField[] }
|
|
126
|
+
| { type: 'SELECT_FIELD'; payload: string | null }
|
|
127
|
+
| { type: 'SET_VIEW_MODE'; payload: ViewMode }
|
|
128
|
+
| { type: 'MARK_DIRTY' }
|
|
129
|
+
| { type: 'MARK_SAVED' }
|
|
130
|
+
| { type: 'RESET'; payload: SchemaBuilderState }
|
|
131
|
+
| {
|
|
132
|
+
type: 'LOAD_SCHEMA'
|
|
133
|
+
payload: { schema: SchemaConfig; fields: SchemaField[] }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Default values for a new schema
|
|
138
|
+
*/
|
|
139
|
+
export const DEFAULT_SCHEMA_CONFIG: SchemaConfig = {
|
|
140
|
+
name: '',
|
|
141
|
+
versioning: true,
|
|
142
|
+
i18n: true,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Default builder state
|
|
147
|
+
*/
|
|
148
|
+
export const DEFAULT_BUILDER_STATE: SchemaBuilderState = {
|
|
149
|
+
schema: DEFAULT_SCHEMA_CONFIG,
|
|
150
|
+
fields: [],
|
|
151
|
+
selectedFieldId: null,
|
|
152
|
+
viewMode: 'builder',
|
|
153
|
+
isDirty: false,
|
|
154
|
+
lastSaved: null,
|
|
155
|
+
isNew: true,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Mapping from field type to TypeScript type
|
|
160
|
+
*/
|
|
161
|
+
export const FIELD_TYPE_TO_TS_TYPE: Record<FieldType, string> = {
|
|
162
|
+
text: 'string',
|
|
163
|
+
number: 'number',
|
|
164
|
+
date: 'Date',
|
|
165
|
+
boolean: 'boolean',
|
|
166
|
+
select: 'string',
|
|
167
|
+
relation: 'string', // ObjectId reference
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Context type for the schema builder
|
|
172
|
+
*/
|
|
173
|
+
export interface SchemaBuilderContextType {
|
|
174
|
+
state: SchemaBuilderState
|
|
175
|
+
dispatch: React.Dispatch<SchemaBuilderAction>
|
|
176
|
+
|
|
177
|
+
// Convenience actions
|
|
178
|
+
addField: (field: Partial<SchemaField>) => void
|
|
179
|
+
updateField: (id: string, changes: Partial<SchemaField>) => void
|
|
180
|
+
deleteField: (id: string) => void
|
|
181
|
+
selectField: (id: string | null) => void
|
|
182
|
+
reorderFields: (fields: SchemaField[]) => void
|
|
183
|
+
setViewMode: (mode: ViewMode) => void
|
|
184
|
+
updateSchema: (changes: Partial<SchemaConfig>) => void
|
|
185
|
+
resetState: (state?: SchemaBuilderState) => void
|
|
186
|
+
|
|
187
|
+
// Computed values
|
|
188
|
+
selectedField: SchemaField | null
|
|
189
|
+
generatedCode: string
|
|
190
|
+
generatedJSON: object
|
|
191
|
+
}
|