mtrl-addons 0.3.7 → 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.
- package/dist/components/form/constants.d.ts +2 -0
- package/dist/components/form/features/api.d.ts +2 -2
- package/dist/components/form/features/data.d.ts +4 -3
- package/dist/components/form/features/index.d.ts +1 -0
- package/dist/components/form/features/protection.d.ts +19 -0
- package/dist/components/form/form.d.ts +1 -1
- package/dist/components/form/index.d.ts +1 -1
- package/dist/components/form/types.d.ts +51 -4
- package/dist/components/vlist/features/keyboard.d.ts +18 -0
- package/dist/components/vlist/index.d.ts +1 -1
- package/dist/components/vlist/types.d.ts +29 -0
- package/dist/index.js +694 -44
- package/dist/index.mjs +687 -37
- package/dist/styles.css +19 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
- package/src/styles/components/_form.scss +16 -0
- package/src/styles/components/_vlist.scss +12 -2
|
@@ -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: () =>
|
|
25
|
-
clear: () =>
|
|
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: () =>
|
|
36
|
-
clear: () =>
|
|
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
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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 */
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard Navigation Feature for VList
|
|
3
|
+
*
|
|
4
|
+
* Implements Material Design 3 accessibility guidelines for lists:
|
|
5
|
+
* - Arrow keys (Up/Down/Left/Right) navigate between items with wrapping
|
|
6
|
+
* - Space/Enter activates/selects the focused item
|
|
7
|
+
* - Tab moves focus to/from the list
|
|
8
|
+
* - Home/End jump to first/last item
|
|
9
|
+
* - Page Up/Down skip multiple items
|
|
10
|
+
*
|
|
11
|
+
* @see https://m3.material.io/components/lists/accessibility
|
|
12
|
+
*/
|
|
13
|
+
import type { VListConfig, VListComponent, VListItem } from "../types";
|
|
14
|
+
/**
|
|
15
|
+
* Adds keyboard navigation and accessibility to VList component
|
|
16
|
+
*/
|
|
17
|
+
export declare const withKeyboard: <T extends VListItem = VListItem>(config: VListConfig<T>) => (component: VListComponent<T>) => VListComponent<T>;
|
|
18
|
+
export default withKeyboard;
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* feature directly without the list-manager layer.
|
|
6
6
|
*/
|
|
7
7
|
export { createVList } from "./vlist";
|
|
8
|
-
export type { RemoveItemOptions, VListConfig, VListComponent, VListItem, VListAPI, VListState, VListEvents, } from "./types";
|
|
8
|
+
export type { RemoveItemOptions, VListConfig, VListComponent, VListItem, VListAPI, VListState, VListEvents, ListKeyboardConfig, } from "./types";
|
|
@@ -150,6 +150,34 @@ export interface ListSelectionConfig {
|
|
|
150
150
|
/** Automatically select first item after initial load (default: false) */
|
|
151
151
|
autoSelectFirst?: boolean;
|
|
152
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Keyboard navigation configuration
|
|
155
|
+
*
|
|
156
|
+
* Follows Material Design 3 accessibility guidelines:
|
|
157
|
+
* - Arrow keys (Up/Down/Left/Right) navigate with wrapping
|
|
158
|
+
* - Space/Enter activates/selects items
|
|
159
|
+
* - Home/End jump to first/last
|
|
160
|
+
*
|
|
161
|
+
* @see https://m3.material.io/components/lists/accessibility
|
|
162
|
+
*/
|
|
163
|
+
export interface ListKeyboardConfig {
|
|
164
|
+
/** Enable keyboard navigation (default: true when selection is enabled) */
|
|
165
|
+
enabled?: boolean;
|
|
166
|
+
/** Enable Home/End keys (default: true) */
|
|
167
|
+
homeEnd?: boolean;
|
|
168
|
+
/** Enable Page Up/Down keys (default: true) */
|
|
169
|
+
pageUpDown?: boolean;
|
|
170
|
+
/** Number of items to skip with Page Up/Down (default: 10) */
|
|
171
|
+
pageSize?: number;
|
|
172
|
+
/** Enable type-ahead search (default: false) */
|
|
173
|
+
typeAhead?: boolean;
|
|
174
|
+
/** Type-ahead search timeout in ms (default: 500) */
|
|
175
|
+
typeAheadTimeout?: number;
|
|
176
|
+
/** Wrap around when reaching start/end (default: true per MD3 spec) */
|
|
177
|
+
wrap?: boolean;
|
|
178
|
+
/** Callback when keyboard navigation occurs */
|
|
179
|
+
onNavigate?: (index: number, key: string) => void;
|
|
180
|
+
}
|
|
153
181
|
/**
|
|
154
182
|
* List orientation configuration
|
|
155
183
|
*/
|
|
@@ -615,6 +643,7 @@ export interface VListConfig<T extends ListItem = ListItem> {
|
|
|
615
643
|
maintainDomOrder?: boolean;
|
|
616
644
|
};
|
|
617
645
|
selection?: ListSelectionConfig;
|
|
646
|
+
keyboard?: ListKeyboardConfig;
|
|
618
647
|
on?: ListEventHandlers<T>;
|
|
619
648
|
}
|
|
620
649
|
export type VListComponent<T extends ListItem = ListItem> = ListComponent<T> & {
|