mtrl-addons 0.3.8 → 0.3.9

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.
@@ -32,6 +32,8 @@ export declare const FORM_EVENTS: {
32
32
  readonly SUBMIT_ERROR: "submit:error";
33
33
  /** Fired when form is reset to initial state */
34
34
  readonly RESET: "reset";
35
+ /** Fired when setData is called with unsaved changes (protection enabled) */
36
+ readonly DATA_CONFLICT: "data:conflict";
35
37
  };
36
38
  /**
37
39
  * Form CSS class modifiers
@@ -21,8 +21,8 @@ interface EnhancedFormComponent extends BaseFormComponent {
21
21
  isModified: () => boolean;
22
22
  getModifiedData: () => FormData;
23
23
  snapshot: () => void;
24
- reset: () => void;
25
- clear: () => void;
24
+ reset: (force?: boolean) => boolean;
25
+ clear: (force?: boolean) => boolean;
26
26
  getField: (name: string) => FormField | undefined;
27
27
  getFieldNames: () => string[];
28
28
  hasField: (name: string) => boolean;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Data feature for Form component
3
- * Handles form data operations: get/set data, change tracking, snapshots
3
+ * Handles form data operations: get/set data, change tracking, snapshots,
4
+ * and change protection (beforeunload warning, data conflict detection)
4
5
  */
5
6
  import type { FormConfig, BaseFormComponent, FormData, FormState, FieldValue, FormFieldRegistry } from "../types";
6
7
  /**
@@ -32,8 +33,8 @@ export declare const withData: (config: FormConfig) => <T extends BaseFormCompon
32
33
  isModified: () => boolean;
33
34
  getModifiedData: () => FormData;
34
35
  snapshot: () => void;
35
- reset: () => void;
36
- clear: () => void;
36
+ reset: (force?: boolean) => boolean;
37
+ clear: (force?: boolean) => boolean;
37
38
  };
38
39
  export { flatToNested, getNestedValue, setNestedValue };
39
40
  export default withData;
@@ -7,4 +7,5 @@ export { withFields, getFieldValue, setFieldValue, updateTrackedFieldValue, sync
7
7
  export { withData, flatToNested, getNestedValue, setNestedValue } from "./data";
8
8
  export { withController } from "./controller";
9
9
  export { withSubmit, validateData, performRequest } from "./submit";
10
+ export { withProtection } from "./protection";
10
11
  export { withAPI } from "./api";
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Protection feature for Form component
3
+ * Handles blocking overlay to prevent clicks outside the form when it has unsaved changes
4
+ */
5
+ import type { FormConfig, BaseFormComponent, FormState, FormFieldRegistry } from "../types";
6
+ /**
7
+ * withProtection feature
8
+ * Adds blocking overlay protection to prevent clicks outside the form when modified
9
+ */
10
+ export declare const withProtection: (config: FormConfig) => <T extends BaseFormComponent & {
11
+ fields: FormFieldRegistry;
12
+ state: FormState;
13
+ emit?: (event: string, data?: unknown) => void;
14
+ on?: (event: string, handler: Function) => void;
15
+ reset?: (force?: boolean) => boolean;
16
+ clearErrors?: () => void;
17
+ disableControls?: () => void;
18
+ }>(component: T) => T;
19
+ export default withProtection;
@@ -5,7 +5,7 @@
5
5
  * forms from schema definitions, with built-in data management,
6
6
  * validation, and submission handling.
7
7
  */
8
- import type { FormConfig, FormComponent } from './types';
8
+ import type { FormConfig, FormComponent } from "./types";
9
9
  /**
10
10
  * Creates a new Form component using functional composition
11
11
  *
@@ -4,6 +4,6 @@
4
4
  */
5
5
  export { createForm, default } from "./form";
6
6
  export { DATA_STATE, FORM_EVENTS, FORM_CLASSES, FORM_DEFAULTS, FIELD_PREFIXES, } from "./constants";
7
- export type { DataState, FormEvent, FieldValue, FormData, FormField, FormFieldRegistry, LayoutSchema, LayoutSchemaItem, FormSectionConfig, FormValidationRule, FormValidationResult, FormSubmitOptions, FormEventHandlers, FormConfig, FormState, FormAPI, FormComponent, BaseFormComponent, SubmitHandler, CancelHandler, } from "./types";
7
+ export type { DataState, FormEvent, FieldValue, FormData, FormField, FormFieldRegistry, LayoutSchema, LayoutSchemaItem, FormSectionConfig, FormValidationRule, FormValidationResult, FormSubmitOptions, FormEventHandlers, FormConfig, FormState, FormAPI, FormComponent, BaseFormComponent, SubmitHandler, CancelHandler, ProtectChangesConfig, DataConflictEvent, } from "./types";
8
8
  export { createBaseConfig, createInitialState, getElementConfig, extractFieldName, getFieldPath, isFieldName, isFileName, isValueEqual, hasDataChanged, getModifiedFields, } from "./config";
9
9
  export { withLayout, withFields, withData, withController, withSubmit, withAPI, getFieldValue, setFieldValue, flatToNested, getNestedValue, setNestedValue, validateData, performRequest, } from "./features";
@@ -1,4 +1,37 @@
1
1
  import type { DATA_STATE, FORM_EVENTS } from "./constants";
2
+ /**
3
+ * Configuration for form change protection
4
+ */
5
+ export interface ProtectChangesConfig {
6
+ /**
7
+ * Warn user when trying to close browser tab/window with unsaved changes
8
+ * Uses the beforeunload event
9
+ * @default false
10
+ */
11
+ beforeUnload?: boolean;
12
+ /**
13
+ * Emit 'data:conflict' event when setData() is called with unsaved changes
14
+ * Allows the caller to confirm before overwriting
15
+ * @default false
16
+ */
17
+ onDataOverwrite?: boolean;
18
+ }
19
+ /**
20
+ * Event data for data:conflict event
21
+ * Emitted when setData() is called while form has unsaved changes
22
+ */
23
+ export interface DataConflictEvent {
24
+ /** Current form data (unsaved changes) */
25
+ currentData: FormData;
26
+ /** New data that would overwrite current data */
27
+ newData: FormData;
28
+ /** Whether the operation was cancelled */
29
+ cancelled: boolean;
30
+ /** Call this to cancel the setData operation */
31
+ cancel: () => void;
32
+ /** Call this to proceed with setData (default behavior if not cancelled) */
33
+ proceed: () => void;
34
+ }
2
35
  /**
3
36
  * Data state type (pristine or dirty)
4
37
  */
@@ -119,6 +152,8 @@ export interface FormEventHandlers {
119
152
  "data:set"?: (data: FormData) => void;
120
153
  /** Called when form is reset */
121
154
  reset?: () => void;
155
+ /** Called when setData() is called while form has unsaved changes */
156
+ "data:conflict"?: (event: DataConflictEvent) => void;
122
157
  }
123
158
  /**
124
159
  * Submit button handler - called when submit button is clicked
@@ -163,6 +198,12 @@ export interface FormConfig {
163
198
  validation?: FormValidationRule[];
164
199
  /** Whether to show error messages in field helper text (default: true) */
165
200
  showFieldErrorMessages?: boolean;
201
+ /**
202
+ * Protection settings for unsaved changes
203
+ * Can be a boolean (enables both protections) or a config object
204
+ * @default false
205
+ */
206
+ protectChanges?: boolean | ProtectChangesConfig;
166
207
  /** Event handlers */
167
208
  on?: FormEventHandlers;
168
209
  /** Container element to append form to */
@@ -219,10 +260,16 @@ export interface FormAPI {
219
260
  getFieldError: (field: string) => string | undefined;
220
261
  /** Submit the form */
221
262
  submit: (options?: FormSubmitOptions) => Promise<unknown>;
222
- /** Reset form to initial data */
223
- reset: () => FormComponent;
224
- /** Clear all form fields */
225
- clear: () => FormComponent;
263
+ /** Reset form to initial data
264
+ * @param {boolean} force - If true, bypass protection and reset immediately
265
+ * @returns {boolean} true if reset was performed, false if cancelled by protection
266
+ */
267
+ reset: (force?: boolean) => boolean;
268
+ /** Clear all form fields
269
+ * @param {boolean} force - If true, bypass protection and clear immediately
270
+ * @returns {boolean} true if clear was performed, false if cancelled by protection
271
+ */
272
+ clear: (force?: boolean) => boolean;
226
273
  /** Enable all form fields */
227
274
  enable: () => FormComponent;
228
275
  /** Disable all form fields */