@msbci/form-editor 1.0.2 → 1.2.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/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ComponentType } from 'react';
3
- import { IFormDefinition, IFormPage, IFormRoster, IFormVariable, IFormType, IDataSourceConnector, IConditionRule } from '@msbci/form-core';
2
+ import { ReactNode, ComponentType } from 'react';
3
+ import { IFormDefinition, IFormPage, IFormRoster, IFormVariable, IFormType, IDataSourceConnector, IConditionRule, IRosterVariableRef } from '@msbci/form-core';
4
4
  export { IDataSourceConnector, IFormDefinition, IFormPage, IFormRoster, IFormVariable, IMosobiThemeBase } from '@msbci/form-core';
5
5
  import * as zustand from 'zustand';
6
6
 
@@ -56,7 +56,7 @@ interface EditorState {
56
56
  /** Editor actions */
57
57
  interface EditorActions {
58
58
  setForm: (form: IFormDefinition) => void;
59
- updateFormMeta: (updates: Partial<Pick<IFormDefinition, 'name' | 'code' | 'description' | 'formTypeId' | 'version'>>) => void;
59
+ updateFormMeta: (updates: Partial<Pick<IFormDefinition, 'name' | 'code' | 'description' | 'formTypeId' | 'version' | 'langConfig'>>) => void;
60
60
  addPage: (page: IFormPage) => void;
61
61
  updatePage: (pageCode: string, updates: Partial<IFormPage>) => void;
62
62
  removePage: (pageCode: string) => void;
@@ -86,6 +86,278 @@ interface EditorActions {
86
86
  }
87
87
  type EditorStore = EditorState & EditorActions;
88
88
 
89
+ /**
90
+ * IEditorLabels — full label dictionary for the FormEditor UI.
91
+ *
92
+ * Pattern A (zero external dependency): consumers pass a `labels` prop to
93
+ * FormEditor and the values flow through React context to every sub-component.
94
+ * French is the absolute default; English ships out of the box; any other
95
+ * language can be added by providing a (deep-)partial override.
96
+ *
97
+ * Functions in this interface format strings with runtime arguments (counts,
98
+ * names, indices). They are *replaced wholesale* by deepMerge, not merged.
99
+ */
100
+ type DeepPartial<T> = T extends (...args: never[]) => unknown ? T : T extends object ? {
101
+ [K in keyof T]?: DeepPartial<T[K]>;
102
+ } : T;
103
+ interface IEditorLabels {
104
+ toolbar: {
105
+ formNamePlaceholder: string;
106
+ unsaved: string;
107
+ addPage: string;
108
+ types: string;
109
+ manageFormTypesTitle: string;
110
+ undo: string;
111
+ redo: string;
112
+ save: string;
113
+ saving: string;
114
+ export: string;
115
+ import: string;
116
+ viewEditor: string;
117
+ viewPreview: string;
118
+ viewJson: string;
119
+ };
120
+ toolbox: {
121
+ searchPlaceholder: string;
122
+ addPageFirst: string;
123
+ groupText: string;
124
+ groupSelection: string;
125
+ groupDateTime: string;
126
+ groupMedia: string;
127
+ groupAdvanced: string;
128
+ /**
129
+ * Shared variable-type labels. Re-used by both Toolbox(Simple) and
130
+ * VariableProperties (single source of truth).
131
+ */
132
+ types: {
133
+ text: string;
134
+ textarea: string;
135
+ number: string;
136
+ email: string;
137
+ select: string;
138
+ multiselect: string;
139
+ radio: string;
140
+ checkbox: string;
141
+ date: string;
142
+ datetime: string;
143
+ time: string;
144
+ file: string;
145
+ image: string;
146
+ gps: string;
147
+ rating: string;
148
+ calculated: string;
149
+ hidden: string;
150
+ label: string;
151
+ };
152
+ };
153
+ canvas: {
154
+ /** CanvasSimple — no page in form. */
155
+ emptyStateNoPage: string;
156
+ /** Canvas (dnd) — no page in form. */
157
+ emptyStateNoPageDnd: string;
158
+ /** Empty page — invites to add a field. */
159
+ emptyStatePage: string;
160
+ /** Fallback when page.name is blank. */
161
+ unnamedPage: string;
162
+ /** Badge on repeatable pages. */
163
+ repeatable: string;
164
+ /** "X fields · Y rosters" — count helper for the page header. */
165
+ fieldsRostersCount: (fields: number, rosters: number) => string;
166
+ /** "X fields" — count helper for the Canvas (dnd) page header. */
167
+ fieldsCount: (fields: number) => string;
168
+ /** "X vars" — count helper for the roster header. */
169
+ rosterVarsCount: (vars: number) => string;
170
+ /** Button: add a roster to the current page. */
171
+ addRoster: string;
172
+ /** Button: add a variable inside a roster. */
173
+ addFieldToRoster: string;
174
+ /** Prefix shown before the pilot variable code on a roster header. */
175
+ pilotPrefix: string;
176
+ /** Default name when auto-creating a roster. */
177
+ newRosterName: string;
178
+ /** Default name when auto-creating a roster variable. */
179
+ newFieldName: string;
180
+ /** Default name when auto-creating a toolbox-spawned variable.
181
+ * Receives the type label (e.g. "Texte court") and returns the full name. */
182
+ newVariableName: (typeLabel: string) => string;
183
+ /** Tooltip on the "has conditions" indicator. */
184
+ hasConditionsTitle: string;
185
+ /** Tooltip on the "data source connected" indicator. */
186
+ dataSourceConnectedTitle: string;
187
+ };
188
+ properties: {
189
+ /** Header of the right-hand properties panel. */
190
+ title: string;
191
+ name: string;
192
+ code: string;
193
+ description: string;
194
+ placeholder: string;
195
+ version: string;
196
+ formType: string;
197
+ noType: string;
198
+ formSummary: (pages: number, variables: number) => string;
199
+ pageSummary: (variables: number, rosters: number) => string;
200
+ rosterSummary: (variables: number, options: number) => string;
201
+ repeatablePage: string;
202
+ minInstances: string;
203
+ maxInstances: string;
204
+ controlVariableCode: string;
205
+ instanceLabel: string;
206
+ rosterType: string;
207
+ pilotVariableCode: string;
208
+ rosterTypes: {
209
+ check: string;
210
+ list: string;
211
+ collection: string;
212
+ collection_extend: string;
213
+ };
214
+ type: string;
215
+ ratingStyle: string;
216
+ ratingStyles: {
217
+ star: string;
218
+ number: string;
219
+ color: string;
220
+ };
221
+ layout: string;
222
+ startNewRow: string;
223
+ columnSpan: string;
224
+ columnSpanAuto: string;
225
+ columnSpanHalf: string;
226
+ columnSpanThird: string;
227
+ columnSpanFull: string;
228
+ required: string;
229
+ readonly: string;
230
+ hidden: string;
231
+ expression: string;
232
+ langConfigSection: string;
233
+ langConfigAvailable: string;
234
+ langConfigDefault: string;
235
+ langConfigStrategy: string;
236
+ langConfigStrategies: {
237
+ prop: string;
238
+ browser: string;
239
+ selector: string;
240
+ auto: string;
241
+ };
242
+ langConfigSelectorPosition: string;
243
+ langConfigPositions: {
244
+ top: string;
245
+ bottom: string;
246
+ };
247
+ langConfigConfirmRemove: (lang: string) => string;
248
+ langConfigConfirmYes: string;
249
+ langConfigConfirmNo: string;
250
+ };
251
+ optionsEditor: {
252
+ optionsCount: (count: number) => string;
253
+ noOptions: string;
254
+ optionLabelPlaceholder: string;
255
+ optionValuePlaceholder: string;
256
+ addOption: string;
257
+ optionLabelAria: (index: number) => string;
258
+ optionValueAria: (index: number) => string;
259
+ removeOptionAria: (index: number) => string;
260
+ };
261
+ conditionBuilder: {
262
+ conditionsCount: (count: number) => string;
263
+ addCondition: string;
264
+ rulesCount: (rules: number) => string;
265
+ addRule: string;
266
+ action: string;
267
+ match: string;
268
+ all: string;
269
+ any: string;
270
+ actions: {
271
+ show: string;
272
+ hide: string;
273
+ validate: string;
274
+ require: string;
275
+ readonly: string;
276
+ setValue: string;
277
+ };
278
+ operators: {
279
+ equals: string;
280
+ not_equals: string;
281
+ greater_than: string;
282
+ less_than: string;
283
+ greater_than_or_equal: string;
284
+ less_than_or_equal: string;
285
+ contains: string;
286
+ not_contains: string;
287
+ is_empty: string;
288
+ is_not_empty: string;
289
+ starts_with: string;
290
+ ends_with: string;
291
+ in: string;
292
+ not_in: string;
293
+ between: string;
294
+ regex: string;
295
+ };
296
+ variablePlaceholder: string;
297
+ valuePlaceholder: string;
298
+ errorMessage: string;
299
+ errorMessagePlaceholder: string;
300
+ targetVariableCode: string;
301
+ targetVariablePlaceholder: string;
302
+ valueToSet: string;
303
+ valueToSetPlaceholder: string;
304
+ };
305
+ dataSource: {
306
+ title: string;
307
+ connector: string;
308
+ none: string;
309
+ connectedTo: string;
310
+ dependencies: (count: number) => string;
311
+ selectVariable: string;
312
+ dependencyKeyPlaceholder: string;
313
+ addDependency: string;
314
+ };
315
+ formTypesDialog: {
316
+ dialogAriaLabel: string;
317
+ title: string;
318
+ closeAriaLabel: string;
319
+ noTypes: string;
320
+ confirmDelete: string;
321
+ deleteConfirm: string;
322
+ deleteCancel: string;
323
+ removeTypeAria: (name: string) => string;
324
+ newTypeNamePlaceholder: string;
325
+ newTypeCodePlaceholder: string;
326
+ addButton: string;
327
+ };
328
+ formEditor: {
329
+ previewMissing: string;
330
+ };
331
+ }
332
+
333
+ /**
334
+ * French labels for FormEditor — absolute default.
335
+ *
336
+ * Any consumer that does not pass a `labels` prop will see this content.
337
+ */
338
+
339
+ declare const frLabels: IEditorLabels;
340
+
341
+ /**
342
+ * English labels for FormEditor — opt-in via `labels` prop.
343
+ */
344
+
345
+ declare const enLabels: IEditorLabels;
346
+
347
+ interface EditorLabelsProviderProps {
348
+ labels: IEditorLabels;
349
+ children: ReactNode;
350
+ }
351
+ declare function EditorLabelsProvider({ labels, children, }: EditorLabelsProviderProps): react_jsx_runtime.JSX.Element;
352
+ /** Read the resolved labels. Defaults to French if no provider is mounted. */
353
+ declare function useLabels(): IEditorLabels;
354
+ /**
355
+ * Recursively merges `override` into `base`. Functions, arrays and primitives
356
+ * are replaced wholesale. Plain objects are merged key-by-key so a partial
357
+ * override never erases sibling keys.
358
+ */
359
+ declare function mergeLabels(base: IEditorLabels, override?: DeepPartial<IEditorLabels>): IEditorLabels;
360
+
89
361
  interface FormEditorProps {
90
362
  theme?: Record<string, unknown>;
91
363
  dataSources?: Record<string, IDataSourceConnector>;
@@ -94,6 +366,12 @@ interface FormEditorProps {
94
366
  formId?: string;
95
367
  onChange?: (form: IFormDefinition) => void;
96
368
  onSave?: () => void;
369
+ /**
370
+ * Localised labels for every visible string in the editor.
371
+ * Deep-merged with the French defaults — pass only the keys you want to
372
+ * override. Use {@link import('../i18n').enLabels} for English out of the box.
373
+ */
374
+ labels?: DeepPartial<IEditorLabels>;
97
375
  PreviewComponent?: ComponentType<{
98
376
  formSchema: IFormDefinition;
99
377
  theme?: Record<string, unknown>;
@@ -107,7 +385,7 @@ interface FormEditorProps {
107
385
  /** Wrapper around the entire editor (e.g. DndContext) */
108
386
  Wrapper?: ComponentType<any>;
109
387
  }
110
- declare function FormEditor({ theme, dataSources, adapter, initialForm, formId, onChange, onSave, PreviewComponent, ToolboxComponent, CanvasComponent, Wrapper, }: FormEditorProps): react_jsx_runtime.JSX.Element;
388
+ declare function FormEditor({ theme, dataSources, adapter, initialForm, formId, onChange, onSave, labels, PreviewComponent, ToolboxComponent, CanvasComponent, Wrapper, }: FormEditorProps): react_jsx_runtime.JSX.Element;
111
389
 
112
390
  declare const useEditorStore: zustand.UseBoundStore<zustand.StoreApi<EditorStore>>;
113
391
 
@@ -138,6 +416,14 @@ interface PropertiesPanelProps {
138
416
  }
139
417
  declare function PropertiesPanel({ availableConnectors }: PropertiesPanelProps): react_jsx_runtime.JSX.Element;
140
418
 
419
+ interface RosterConditionContext {
420
+ /** Variables that belong to the same roster row (scope-restricted). */
421
+ variables: IRosterVariableRef[];
422
+ /** Code of the variable whose conditions are being edited. */
423
+ currentVariableCode: string;
424
+ /** Order of the variable whose conditions are being edited. */
425
+ currentVariableOrder: number;
426
+ }
141
427
  interface ConditionBuilderProps {
142
428
  conditions: IConditionRule[];
143
429
  onChange: (conditions: IConditionRule[]) => void;
@@ -146,8 +432,13 @@ interface ConditionBuilderProps {
146
432
  code: string;
147
433
  name: string;
148
434
  }>;
435
+ /**
436
+ * When set, conditions are validated against the roster scope using
437
+ * RosterConditionEngine. Scope errors are displayed under each rule.
438
+ */
439
+ rosterContext?: RosterConditionContext;
149
440
  }
150
- declare function ConditionBuilder({ conditions, onChange, availableVariables }: ConditionBuilderProps): react_jsx_runtime.JSX.Element;
441
+ declare function ConditionBuilder({ conditions, onChange, availableVariables, rosterContext, }: ConditionBuilderProps): react_jsx_runtime.JSX.Element;
151
442
 
152
443
  interface DataSourceSelectorProps {
153
444
  /** Currently selected connector ID */
@@ -168,4 +459,4 @@ interface DataSourceSelectorProps {
168
459
  }
169
460
  declare function DataSourceSelector({ dataSourceId, dependencies, availableConnectors, availableVariables, onConnectorChange, onDependenciesChange, }: DataSourceSelectorProps): react_jsx_runtime.JSX.Element;
170
461
 
171
- export { CanvasSimple as Canvas, ConditionBuilder, type ConditionBuilderProps, DataSourceSelector, type DataSourceSelectorProps, type EditorActions, type EditorSelection, type EditorState, type EditorStore, EditorToolbar, type EditorView, FormEditor, type FormEditorProps, type HistoryEntry, type IEditorAdapter, PropertiesPanel, ToolboxSimple as Toolbox, useEditorStore };
462
+ export { CanvasSimple as Canvas, ConditionBuilder, type ConditionBuilderProps, DataSourceSelector, type DataSourceSelectorProps, type DeepPartial, type EditorActions, EditorLabelsProvider, type EditorSelection, type EditorState, type EditorStore, EditorToolbar, type EditorView, FormEditor, type FormEditorProps, type HistoryEntry, type IEditorAdapter, type IEditorLabels, PropertiesPanel, ToolboxSimple as Toolbox, frLabels as defaultLabels, enLabels, frLabels, mergeLabels, useEditorStore, useLabels };