mtrl-addons 0.2.4 → 0.2.5
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/config.d.ts +49 -0
- package/dist/components/form/constants.d.ts +67 -0
- package/dist/components/form/features/api.d.ts +52 -0
- package/dist/components/form/features/controller.d.ts +23 -0
- package/dist/components/form/features/data.d.ts +39 -0
- package/dist/components/form/features/fields.d.ts +47 -0
- package/dist/components/form/features/index.d.ts +10 -0
- package/dist/components/form/features/layout.d.ts +11 -0
- package/dist/components/form/features/submit.d.ts +35 -0
- package/dist/components/form/form.d.ts +64 -0
- package/dist/components/form/index.d.ts +9 -0
- package/dist/components/form/types.d.ts +260 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/index.js +812 -3
- package/dist/index.mjs +812 -3
- package/package.json +3 -2
- package/src/styles/core/_layout.scss +694 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { FormConfig, FormState, FormData } from "./types";
|
|
2
|
+
import { FORM_DEFAULTS } from "./constants";
|
|
3
|
+
export { FORM_DEFAULTS };
|
|
4
|
+
/**
|
|
5
|
+
* Creates the base configuration with defaults applied
|
|
6
|
+
*/
|
|
7
|
+
export declare const createBaseConfig: (config?: FormConfig) => FormConfig;
|
|
8
|
+
/**
|
|
9
|
+
* Creates the initial form state
|
|
10
|
+
*/
|
|
11
|
+
export declare const createInitialState: (config: FormConfig) => FormState;
|
|
12
|
+
/**
|
|
13
|
+
* Gets the element configuration for withElement
|
|
14
|
+
*/
|
|
15
|
+
export declare const getElementConfig: (config: FormConfig) => {
|
|
16
|
+
tag: string;
|
|
17
|
+
className: string;
|
|
18
|
+
attributes: {
|
|
19
|
+
"data-component": string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Extracts field name from a prefixed name (e.g., 'info.username' -> 'username')
|
|
24
|
+
*/
|
|
25
|
+
export declare const extractFieldName: (prefixedName: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Gets the full field path including prefix
|
|
28
|
+
*/
|
|
29
|
+
export declare const getFieldPath: (name: string, prefix?: string) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Checks if a name is a field name (starts with info. or data.)
|
|
32
|
+
*/
|
|
33
|
+
export declare const isFieldName: (name: string) => boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a name is a file field name
|
|
36
|
+
*/
|
|
37
|
+
export declare const isFileName: (name: string) => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Deep comparison of two values for change detection
|
|
40
|
+
*/
|
|
41
|
+
export declare const isValueEqual: (a: unknown, b: unknown) => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Checks if form data has been modified from initial state
|
|
44
|
+
*/
|
|
45
|
+
export declare const hasDataChanged: (initial: FormData, current: FormData) => boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Gets only the modified fields between initial and current data
|
|
48
|
+
*/
|
|
49
|
+
export declare const getModifiedFields: (initial: FormData, current: FormData) => FormData;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data state constants
|
|
3
|
+
* Tracks whether form data has been modified from initial state
|
|
4
|
+
*/
|
|
5
|
+
export declare const DATA_STATE: {
|
|
6
|
+
/** Data matches initial state - no changes made */
|
|
7
|
+
readonly PRISTINE: "pristine";
|
|
8
|
+
/** Data has been modified from initial state */
|
|
9
|
+
readonly DIRTY: "dirty";
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Form event constants
|
|
13
|
+
*/
|
|
14
|
+
export declare const FORM_EVENTS: {
|
|
15
|
+
/** Fired when any field value changes */
|
|
16
|
+
readonly CHANGE: "change";
|
|
17
|
+
/** Fired when form is submitted */
|
|
18
|
+
readonly SUBMIT: "submit";
|
|
19
|
+
/** Fired when data state changes (pristine <-> dirty) */
|
|
20
|
+
readonly STATE_CHANGE: "state:change";
|
|
21
|
+
/** Fired when data is set on the form */
|
|
22
|
+
readonly DATA_SET: "data:set";
|
|
23
|
+
/** Fired when data is retrieved from the form */
|
|
24
|
+
readonly DATA_GET: "data:get";
|
|
25
|
+
/** Fired when a specific field changes */
|
|
26
|
+
readonly FIELD_CHANGE: "field:change";
|
|
27
|
+
/** Fired when validation fails */
|
|
28
|
+
readonly VALIDATION_ERROR: "validation:error";
|
|
29
|
+
/** Fired when submit succeeds */
|
|
30
|
+
readonly SUBMIT_SUCCESS: "submit:success";
|
|
31
|
+
/** Fired when submit fails */
|
|
32
|
+
readonly SUBMIT_ERROR: "submit:error";
|
|
33
|
+
/** Fired when form is reset to initial state */
|
|
34
|
+
readonly RESET: "reset";
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Form CSS class modifiers
|
|
38
|
+
*/
|
|
39
|
+
export declare const FORM_CLASSES: {
|
|
40
|
+
/** Applied when data has been modified */
|
|
41
|
+
readonly MODIFIED: "modified";
|
|
42
|
+
/** Applied when form is submitting */
|
|
43
|
+
readonly SUBMITTING: "submitting";
|
|
44
|
+
/** Applied when form is disabled */
|
|
45
|
+
readonly DISABLED: "disabled";
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Default form configuration
|
|
49
|
+
*/
|
|
50
|
+
export declare const FORM_DEFAULTS: {
|
|
51
|
+
readonly prefix: "mtrl";
|
|
52
|
+
readonly componentName: "form";
|
|
53
|
+
readonly tag: "div";
|
|
54
|
+
readonly formTag: "form";
|
|
55
|
+
readonly method: "POST";
|
|
56
|
+
readonly autocomplete: "off";
|
|
57
|
+
readonly useChanges: true;
|
|
58
|
+
readonly controls: readonly ["submit", "cancel"];
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Field name prefixes used for extraction
|
|
62
|
+
*/
|
|
63
|
+
export declare const FIELD_PREFIXES: {
|
|
64
|
+
readonly INFO: "info.";
|
|
65
|
+
readonly FILE: "file.";
|
|
66
|
+
readonly DATA: "data.";
|
|
67
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API feature for Form component
|
|
3
|
+
* Provides a clean, unified public API for the form
|
|
4
|
+
* Also wires up control button click handlers (submit/cancel)
|
|
5
|
+
*/
|
|
6
|
+
import type { FormConfig, BaseFormComponent, FormComponent, FormData, DataState, FormState, FormField, FormFieldRegistry, FormValidationResult, FormSubmitOptions, FieldValue } from "../types";
|
|
7
|
+
/**
|
|
8
|
+
* Extended component interface before API is applied
|
|
9
|
+
*/
|
|
10
|
+
interface EnhancedFormComponent extends BaseFormComponent {
|
|
11
|
+
form: HTMLFormElement;
|
|
12
|
+
ui: Record<string, unknown>;
|
|
13
|
+
fields: FormFieldRegistry;
|
|
14
|
+
files: FormFieldRegistry;
|
|
15
|
+
state: FormState;
|
|
16
|
+
controls: Map<string, FormField>;
|
|
17
|
+
getData: () => FormData;
|
|
18
|
+
setData: (data: FormData, silent?: boolean) => void;
|
|
19
|
+
getFieldValue: (name: string) => FieldValue;
|
|
20
|
+
setFieldValue: (name: string, value: FieldValue, silent?: boolean) => void;
|
|
21
|
+
isModified: () => boolean;
|
|
22
|
+
getModifiedData: () => FormData;
|
|
23
|
+
snapshot: () => void;
|
|
24
|
+
reset: () => void;
|
|
25
|
+
clear: () => void;
|
|
26
|
+
getField: (name: string) => FormField | undefined;
|
|
27
|
+
getFieldNames: () => string[];
|
|
28
|
+
hasField: (name: string) => boolean;
|
|
29
|
+
getDataState: () => DataState;
|
|
30
|
+
enableControls: () => void;
|
|
31
|
+
disableControls: () => void;
|
|
32
|
+
enableFields: () => void;
|
|
33
|
+
disableFields: () => void;
|
|
34
|
+
validate: () => FormValidationResult;
|
|
35
|
+
submit: (options?: FormSubmitOptions) => Promise<unknown>;
|
|
36
|
+
setValidationRules: (rules: import("../types").FormValidationRule[]) => void;
|
|
37
|
+
clearErrors: () => void;
|
|
38
|
+
setFieldError: (field: string, error: string) => void;
|
|
39
|
+
getFieldError: (field: string) => string | undefined;
|
|
40
|
+
on?: (event: string, handler: Function) => void;
|
|
41
|
+
off?: (event: string, handler: Function) => void;
|
|
42
|
+
emit?: (event: string, data?: unknown) => void;
|
|
43
|
+
lifecycle?: {
|
|
44
|
+
destroy: () => void;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* withAPI feature
|
|
49
|
+
* Creates a clean public API for the form component
|
|
50
|
+
*/
|
|
51
|
+
export declare const withAPI: (config: FormConfig) => (component: EnhancedFormComponent) => FormComponent;
|
|
52
|
+
export default withAPI;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controller feature for Form component
|
|
3
|
+
* Manages control buttons (submit/cancel) based on data state (pristine/dirty)
|
|
4
|
+
*/
|
|
5
|
+
import type { FormConfig, BaseFormComponent, FormState, FormFieldRegistry, FormField } from "../types";
|
|
6
|
+
/**
|
|
7
|
+
* withController feature
|
|
8
|
+
* Adds control button handling based on data state (pristine/dirty)
|
|
9
|
+
*/
|
|
10
|
+
export declare const withController: (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
|
+
}>(component: T) => T & {
|
|
16
|
+
controls: Map<string, FormField>;
|
|
17
|
+
getDataState: () => string;
|
|
18
|
+
enableControls: () => void;
|
|
19
|
+
disableControls: () => void;
|
|
20
|
+
enableFields: () => void;
|
|
21
|
+
disableFields: () => void;
|
|
22
|
+
};
|
|
23
|
+
export default withController;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data feature for Form component
|
|
3
|
+
* Handles form data operations: get/set data, change tracking, snapshots
|
|
4
|
+
*/
|
|
5
|
+
import type { FormConfig, BaseFormComponent, FormData, FormState, FieldValue, FormFieldRegistry } from "../types";
|
|
6
|
+
/**
|
|
7
|
+
* Gets a nested value from an object using dot notation
|
|
8
|
+
*/
|
|
9
|
+
declare const getNestedValue: (obj: Record<string, unknown>, path: string) => unknown;
|
|
10
|
+
/**
|
|
11
|
+
* Sets a nested value in an object using dot notation
|
|
12
|
+
*/
|
|
13
|
+
declare const setNestedValue: (obj: Record<string, unknown>, path: string, value: unknown) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Converts flat field data to nested object structure
|
|
16
|
+
* e.g., { 'user.name': 'John' } -> { user: { name: 'John' } }
|
|
17
|
+
*/
|
|
18
|
+
declare const flatToNested: (data: FormData) => Record<string, unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* withData feature
|
|
21
|
+
* Adds data management capabilities to the form
|
|
22
|
+
*/
|
|
23
|
+
export declare const withData: (config: FormConfig) => <T extends BaseFormComponent & {
|
|
24
|
+
fields: FormFieldRegistry;
|
|
25
|
+
emit?: (event: string, data?: unknown) => void;
|
|
26
|
+
}>(component: T) => T & {
|
|
27
|
+
state: FormState;
|
|
28
|
+
getData: () => FormData;
|
|
29
|
+
setData: (data: FormData, silent?: boolean) => void;
|
|
30
|
+
getFieldValue: (name: string) => FieldValue;
|
|
31
|
+
setFieldValue: (name: string, value: FieldValue, silent?: boolean) => void;
|
|
32
|
+
isModified: () => boolean;
|
|
33
|
+
getModifiedData: () => FormData;
|
|
34
|
+
snapshot: () => void;
|
|
35
|
+
reset: () => void;
|
|
36
|
+
clear: () => void;
|
|
37
|
+
};
|
|
38
|
+
export { flatToNested, getNestedValue, setNestedValue };
|
|
39
|
+
export default withData;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fields feature for Form component
|
|
3
|
+
* Extracts fields from layout and manages the field registry
|
|
4
|
+
*/
|
|
5
|
+
import type { FormConfig, BaseFormComponent, FormField, FormFieldRegistry, FieldValue } from "../types";
|
|
6
|
+
/**
|
|
7
|
+
* Gets the value from a field component
|
|
8
|
+
* All mtrl components now have unified getValue() API:
|
|
9
|
+
* - Textfield: returns string
|
|
10
|
+
* - Select: returns string or string[]
|
|
11
|
+
* - Chips: returns string[]
|
|
12
|
+
* - Switch/Checkbox: returns boolean (updated in mtrl core)
|
|
13
|
+
*/
|
|
14
|
+
export declare const getFieldValue: (field: FormField) => FieldValue;
|
|
15
|
+
/**
|
|
16
|
+
* Sets the value on a field component
|
|
17
|
+
* All mtrl components now have unified setValue() API:
|
|
18
|
+
* - Textfield: accepts string
|
|
19
|
+
* - Select: accepts string or string[]
|
|
20
|
+
* - Chips: accepts string[]
|
|
21
|
+
* - Switch/Checkbox: accepts boolean or string ("true"/"false") (updated in mtrl core)
|
|
22
|
+
*
|
|
23
|
+
* For silent updates (no change events), we set directly on the input element
|
|
24
|
+
*/
|
|
25
|
+
export declare const setFieldValue: (field: FormField, value: FieldValue, silent?: boolean) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Updates the tracked value for a field
|
|
28
|
+
* Called when setData is used with silent=true to keep deduplication in sync
|
|
29
|
+
*/
|
|
30
|
+
export declare const updateTrackedFieldValue: (name: string, value: FieldValue) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Updates all tracked field values from a fields registry
|
|
33
|
+
* Called after silent setData to sync deduplication state
|
|
34
|
+
*/
|
|
35
|
+
export declare const syncTrackedFieldValues: (fields: FormFieldRegistry) => void;
|
|
36
|
+
/**
|
|
37
|
+
* withFields feature
|
|
38
|
+
* Adds field extraction and registry management to the form
|
|
39
|
+
*/
|
|
40
|
+
export declare const withFields: (config: FormConfig) => <T extends BaseFormComponent>(component: T) => T & {
|
|
41
|
+
fields: FormFieldRegistry;
|
|
42
|
+
files: FormFieldRegistry;
|
|
43
|
+
getField: (name: string) => FormField | undefined;
|
|
44
|
+
getFieldNames: () => string[];
|
|
45
|
+
hasField: (name: string) => boolean;
|
|
46
|
+
};
|
|
47
|
+
export default withFields;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form component features
|
|
3
|
+
* Each feature adds specific capabilities to the form component
|
|
4
|
+
*/
|
|
5
|
+
export { withLayout } from "./layout";
|
|
6
|
+
export { withFields, getFieldValue, setFieldValue, updateTrackedFieldValue, syncTrackedFieldValues, } from "./fields";
|
|
7
|
+
export { withData, flatToNested, getNestedValue, setNestedValue } from "./data";
|
|
8
|
+
export { withController } from "./controller";
|
|
9
|
+
export { withSubmit, validateData, performRequest } from "./submit";
|
|
10
|
+
export { withAPI } from "./api";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FormConfig, BaseFormComponent } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* withLayout feature
|
|
4
|
+
* Adds form element creation and layout processing
|
|
5
|
+
*/
|
|
6
|
+
export declare const withLayout: (config: FormConfig) => <T extends BaseFormComponent>(component: T) => T & {
|
|
7
|
+
form: HTMLFormElement;
|
|
8
|
+
ui: Record<string, unknown>;
|
|
9
|
+
layoutResult: unknown;
|
|
10
|
+
};
|
|
11
|
+
export default withLayout;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Submit feature for Form component
|
|
3
|
+
* Handles form validation and submission
|
|
4
|
+
*/
|
|
5
|
+
import type { FormConfig, BaseFormComponent, FormData, FormState, FormFieldRegistry, FormValidationRule, FormValidationResult, FormSubmitOptions } from "../types";
|
|
6
|
+
/**
|
|
7
|
+
* Validates form data against validation rules
|
|
8
|
+
*/
|
|
9
|
+
declare const validateData: (data: FormData, rules: FormValidationRule[]) => FormValidationResult;
|
|
10
|
+
/**
|
|
11
|
+
* Performs the actual HTTP request
|
|
12
|
+
*/
|
|
13
|
+
declare const performRequest: (url: string, data: FormData, options: FormSubmitOptions) => Promise<unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* withSubmit feature
|
|
16
|
+
* Adds validation and submission capabilities to the form
|
|
17
|
+
*/
|
|
18
|
+
export declare const withSubmit: (config: FormConfig) => <T extends BaseFormComponent & {
|
|
19
|
+
fields: FormFieldRegistry;
|
|
20
|
+
state: FormState;
|
|
21
|
+
getData: () => FormData;
|
|
22
|
+
getModifiedData: () => FormData;
|
|
23
|
+
disableControls: () => void;
|
|
24
|
+
snapshot: () => void;
|
|
25
|
+
emit?: (event: string, data?: unknown) => void;
|
|
26
|
+
}>(component: T) => T & {
|
|
27
|
+
validate: () => FormValidationResult;
|
|
28
|
+
submit: (options?: FormSubmitOptions) => Promise<unknown>;
|
|
29
|
+
setValidationRules: (rules: FormValidationRule[]) => void;
|
|
30
|
+
clearErrors: () => void;
|
|
31
|
+
setFieldError: (field: string, error: string) => void;
|
|
32
|
+
getFieldError: (field: string) => string | undefined;
|
|
33
|
+
};
|
|
34
|
+
export { validateData, performRequest };
|
|
35
|
+
export default withSubmit;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form Component - Functional form builder with mtrl composition
|
|
3
|
+
*
|
|
4
|
+
* A form component that uses the mtrl-addons layout system to build
|
|
5
|
+
* forms from schema definitions, with built-in data management,
|
|
6
|
+
* validation, and submission handling.
|
|
7
|
+
*/
|
|
8
|
+
import type { FormConfig, FormComponent } from './types';
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new Form component using functional composition
|
|
11
|
+
*
|
|
12
|
+
* @param {FormConfig} config - Form configuration options
|
|
13
|
+
* @returns {FormComponent} A fully configured form component
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { createForm } from 'mtrl-addons'
|
|
18
|
+
* import { createTextfield, createSwitch, createChips } from 'mtrl'
|
|
19
|
+
*
|
|
20
|
+
* const form = createForm({
|
|
21
|
+
* class: 'account-form',
|
|
22
|
+
* action: '/api/users/',
|
|
23
|
+
* layout: [
|
|
24
|
+
* ['section', { class: 'user-section' },
|
|
25
|
+
* ['div', { class: 'section-title', text: 'User' }],
|
|
26
|
+
* [createTextfield, 'info.username', { label: 'Username' }],
|
|
27
|
+
* [createChips, 'info.role', {
|
|
28
|
+
* label: 'Role',
|
|
29
|
+
* chips: [
|
|
30
|
+
* { text: 'registered', value: 'registered' },
|
|
31
|
+
* { text: 'admin', value: 'admin' },
|
|
32
|
+
* { text: 'premium', value: 'premium' }
|
|
33
|
+
* ]
|
|
34
|
+
* }],
|
|
35
|
+
* [createSwitch, 'info.enabled', { label: 'Enabled' }]
|
|
36
|
+
* ]
|
|
37
|
+
* ],
|
|
38
|
+
* on: {
|
|
39
|
+
* change: (data) => console.log('Form changed:', data),
|
|
40
|
+
* submit: (data) => console.log('Form submitted:', data)
|
|
41
|
+
* }
|
|
42
|
+
* })
|
|
43
|
+
*
|
|
44
|
+
* // Append to DOM
|
|
45
|
+
* document.body.appendChild(form.element)
|
|
46
|
+
*
|
|
47
|
+
* // Set data
|
|
48
|
+
* form.setData({
|
|
49
|
+
* username: 'john_doe',
|
|
50
|
+
* role: 'admin',
|
|
51
|
+
* enabled: true
|
|
52
|
+
* })
|
|
53
|
+
*
|
|
54
|
+
* // Get data
|
|
55
|
+
* const data = form.getData()
|
|
56
|
+
*
|
|
57
|
+
* // Check if modified
|
|
58
|
+
* if (form.isModified()) {
|
|
59
|
+
* await form.submit()
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare const createForm: (config?: FormConfig) => FormComponent;
|
|
64
|
+
export default createForm;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form Component
|
|
3
|
+
* A functional form builder using mtrl composition pattern
|
|
4
|
+
*/
|
|
5
|
+
export { createForm, default } from "./form";
|
|
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";
|
|
8
|
+
export { createBaseConfig, createInitialState, getElementConfig, extractFieldName, getFieldPath, isFieldName, isFileName, isValueEqual, hasDataChanged, getModifiedFields, } from "./config";
|
|
9
|
+
export { withLayout, withFields, withData, withController, withSubmit, withAPI, getFieldValue, setFieldValue, flatToNested, getNestedValue, setNestedValue, validateData, performRequest, } from "./features";
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import type { DATA_STATE, FORM_EVENTS } from "./constants";
|
|
2
|
+
/**
|
|
3
|
+
* Data state type (pristine or dirty)
|
|
4
|
+
*/
|
|
5
|
+
export type DataState = (typeof DATA_STATE)[keyof typeof DATA_STATE];
|
|
6
|
+
/**
|
|
7
|
+
* Form event type
|
|
8
|
+
*/
|
|
9
|
+
export type FormEvent = (typeof FORM_EVENTS)[keyof typeof FORM_EVENTS];
|
|
10
|
+
/**
|
|
11
|
+
* Field value types supported by the form
|
|
12
|
+
*/
|
|
13
|
+
export type FieldValue = string | number | boolean | string[] | null | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Form data object - key-value pairs of field names and values
|
|
16
|
+
*/
|
|
17
|
+
export type FormData = Record<string, FieldValue>;
|
|
18
|
+
/**
|
|
19
|
+
* Form field interface - represents a form field component
|
|
20
|
+
*/
|
|
21
|
+
export interface FormField {
|
|
22
|
+
/** The field's DOM element */
|
|
23
|
+
element: HTMLElement;
|
|
24
|
+
/** Get the field's current value */
|
|
25
|
+
getValue?: () => FieldValue;
|
|
26
|
+
/** Set the field's value */
|
|
27
|
+
setValue?: (value: FieldValue) => void;
|
|
28
|
+
/** Enable the field */
|
|
29
|
+
enable?: () => void;
|
|
30
|
+
/** Disable the field */
|
|
31
|
+
disable?: () => void;
|
|
32
|
+
/** Check if field is disabled */
|
|
33
|
+
isDisabled?: () => boolean;
|
|
34
|
+
/** Add event listener */
|
|
35
|
+
on?: (event: string, handler: Function) => void;
|
|
36
|
+
/** Remove event listener */
|
|
37
|
+
off?: (event: string, handler: Function) => void;
|
|
38
|
+
/** Destroy the field */
|
|
39
|
+
destroy?: () => void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Form field registry - maps field names to field components
|
|
43
|
+
*/
|
|
44
|
+
export type FormFieldRegistry = Map<string, FormField>;
|
|
45
|
+
/**
|
|
46
|
+
* Layout schema item - can be a component factory, string, or nested array
|
|
47
|
+
*/
|
|
48
|
+
export type LayoutSchemaItem = Function | string | Record<string, unknown> | LayoutSchema;
|
|
49
|
+
/**
|
|
50
|
+
* Layout schema - array-based layout definition
|
|
51
|
+
*/
|
|
52
|
+
export type LayoutSchema = LayoutSchemaItem[];
|
|
53
|
+
/**
|
|
54
|
+
* Form section configuration
|
|
55
|
+
*/
|
|
56
|
+
export interface FormSectionConfig {
|
|
57
|
+
/** Section title */
|
|
58
|
+
title?: string;
|
|
59
|
+
/** Section CSS class */
|
|
60
|
+
class?: string;
|
|
61
|
+
/** Section layout schema */
|
|
62
|
+
layout?: LayoutSchema;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Form validation rule
|
|
66
|
+
*/
|
|
67
|
+
export interface FormValidationRule {
|
|
68
|
+
/** Field name to validate */
|
|
69
|
+
field: string;
|
|
70
|
+
/** Validation function - returns true if valid, string error message if invalid */
|
|
71
|
+
validate: (value: FieldValue, data: FormData) => boolean | string;
|
|
72
|
+
/** Error message if validation returns false */
|
|
73
|
+
message?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Form validation result
|
|
77
|
+
*/
|
|
78
|
+
export interface FormValidationResult {
|
|
79
|
+
/** Whether the form is valid */
|
|
80
|
+
valid: boolean;
|
|
81
|
+
/** Validation errors by field name */
|
|
82
|
+
errors: Record<string, string>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Form submit options
|
|
86
|
+
*/
|
|
87
|
+
export interface FormSubmitOptions {
|
|
88
|
+
/** HTTP method */
|
|
89
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
90
|
+
/** Request headers */
|
|
91
|
+
headers?: Record<string, string>;
|
|
92
|
+
/** Whether to validate before submit */
|
|
93
|
+
validate?: boolean;
|
|
94
|
+
/** Custom submit handler - if provided, replaces default fetch */
|
|
95
|
+
handler?: (data: FormData, form: FormComponent) => Promise<unknown>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Form event handlers configuration
|
|
99
|
+
*/
|
|
100
|
+
export interface FormEventHandlers {
|
|
101
|
+
/** Called when any field value changes */
|
|
102
|
+
change?: (data: FormData, fieldName: string) => void;
|
|
103
|
+
/** Called when form is submitted */
|
|
104
|
+
submit?: (data: FormData) => void;
|
|
105
|
+
/** Called when form submit succeeds */
|
|
106
|
+
"submit:success"?: (response: unknown) => void;
|
|
107
|
+
/** Called when form submit fails */
|
|
108
|
+
"submit:error"?: (error: Error) => void;
|
|
109
|
+
/** Called when data state changes (pristine <-> dirty) */
|
|
110
|
+
"state:change"?: (event: {
|
|
111
|
+
modified: boolean;
|
|
112
|
+
state: DataState;
|
|
113
|
+
}) => void;
|
|
114
|
+
/** Called when form data is set */
|
|
115
|
+
"data:set"?: (data: FormData) => void;
|
|
116
|
+
/** Called when form is reset */
|
|
117
|
+
reset?: () => void;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Submit button handler - called when submit button is clicked
|
|
121
|
+
* Return a promise that resolves with the result or rejects with an error
|
|
122
|
+
*/
|
|
123
|
+
export type SubmitHandler = (data: FormData, form: FormComponent) => Promise<unknown>;
|
|
124
|
+
/**
|
|
125
|
+
* Cancel button handler - called when cancel button is clicked
|
|
126
|
+
*/
|
|
127
|
+
export type CancelHandler = (form: FormComponent) => void;
|
|
128
|
+
/**
|
|
129
|
+
* Form configuration
|
|
130
|
+
*/
|
|
131
|
+
export interface FormConfig {
|
|
132
|
+
/** Component prefix for class names */
|
|
133
|
+
prefix?: string;
|
|
134
|
+
/** Component name */
|
|
135
|
+
componentName?: string;
|
|
136
|
+
/** Additional CSS class for the form container */
|
|
137
|
+
class?: string;
|
|
138
|
+
/** Form action URL for submission */
|
|
139
|
+
action?: string;
|
|
140
|
+
/** HTTP method for form submission */
|
|
141
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
142
|
+
/** Form autocomplete attribute */
|
|
143
|
+
autocomplete?: "on" | "off";
|
|
144
|
+
/** Layout schema defining form structure */
|
|
145
|
+
layout?: LayoutSchema;
|
|
146
|
+
/** System info fields (excluded from form data) */
|
|
147
|
+
sysinfo?: string[];
|
|
148
|
+
/** Whether to track changes and auto-enable/disable controls */
|
|
149
|
+
useChanges?: boolean;
|
|
150
|
+
/** Control button names (default: ['submit', 'cancel']) */
|
|
151
|
+
controls?: string[] | null;
|
|
152
|
+
/** Handler called when submit button is clicked */
|
|
153
|
+
onSubmit?: SubmitHandler;
|
|
154
|
+
/** Handler called when cancel button is clicked */
|
|
155
|
+
onCancel?: CancelHandler;
|
|
156
|
+
/** Initial form data */
|
|
157
|
+
data?: FormData;
|
|
158
|
+
/** Validation rules */
|
|
159
|
+
validation?: FormValidationRule[];
|
|
160
|
+
/** Event handlers */
|
|
161
|
+
on?: FormEventHandlers;
|
|
162
|
+
/** Container element to append form to */
|
|
163
|
+
container?: HTMLElement;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Form state
|
|
167
|
+
*/
|
|
168
|
+
export interface FormState {
|
|
169
|
+
/** Whether form has been modified from initial data */
|
|
170
|
+
modified: boolean;
|
|
171
|
+
/** Whether form is currently submitting */
|
|
172
|
+
submitting: boolean;
|
|
173
|
+
/** Whether form is disabled */
|
|
174
|
+
disabled: boolean;
|
|
175
|
+
/** Initial data snapshot for change detection */
|
|
176
|
+
initialData: FormData;
|
|
177
|
+
/** Current form data */
|
|
178
|
+
currentData: FormData;
|
|
179
|
+
/** Validation errors */
|
|
180
|
+
errors: Record<string, string>;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Form component public API
|
|
184
|
+
*/
|
|
185
|
+
export interface FormAPI {
|
|
186
|
+
/** Get all form data */
|
|
187
|
+
getData: () => FormData;
|
|
188
|
+
/** Set form data */
|
|
189
|
+
setData: (data: FormData, silent?: boolean) => FormComponent;
|
|
190
|
+
/** Get a specific field value */
|
|
191
|
+
getFieldValue: (name: string) => FieldValue;
|
|
192
|
+
/** Set a specific field value */
|
|
193
|
+
setFieldValue: (name: string, value: FieldValue, silent?: boolean) => FormComponent;
|
|
194
|
+
/** Get a field component by name */
|
|
195
|
+
getField: (name: string) => FormField | undefined;
|
|
196
|
+
/** Get all field names */
|
|
197
|
+
getFieldNames: () => string[];
|
|
198
|
+
/** Check if form has been modified */
|
|
199
|
+
isModified: () => boolean;
|
|
200
|
+
/** Get current data state (pristine or dirty) */
|
|
201
|
+
getDataState: () => DataState;
|
|
202
|
+
/** Validate the form */
|
|
203
|
+
validate: () => FormValidationResult;
|
|
204
|
+
/** Submit the form */
|
|
205
|
+
submit: (options?: FormSubmitOptions) => Promise<unknown>;
|
|
206
|
+
/** Reset form to initial data */
|
|
207
|
+
reset: () => FormComponent;
|
|
208
|
+
/** Clear all form fields */
|
|
209
|
+
clear: () => FormComponent;
|
|
210
|
+
/** Enable all form fields */
|
|
211
|
+
enable: () => FormComponent;
|
|
212
|
+
/** Disable all form fields */
|
|
213
|
+
disable: () => FormComponent;
|
|
214
|
+
/** Enable control buttons */
|
|
215
|
+
enableControls: () => FormComponent;
|
|
216
|
+
/** Disable control buttons */
|
|
217
|
+
disableControls: () => FormComponent;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Form component interface
|
|
221
|
+
*/
|
|
222
|
+
export interface FormComponent extends FormAPI {
|
|
223
|
+
/** The form container element */
|
|
224
|
+
element: HTMLElement;
|
|
225
|
+
/** The form element */
|
|
226
|
+
form: HTMLFormElement;
|
|
227
|
+
/** Layout result with named components */
|
|
228
|
+
ui: Record<string, unknown>;
|
|
229
|
+
/** Field registry */
|
|
230
|
+
fields: FormFieldRegistry;
|
|
231
|
+
/** Current form state */
|
|
232
|
+
state: FormState;
|
|
233
|
+
/** Add event listener */
|
|
234
|
+
on: (event: string, handler: Function) => FormComponent;
|
|
235
|
+
/** Remove event listener */
|
|
236
|
+
off: (event: string, handler: Function) => FormComponent;
|
|
237
|
+
/** Emit an event */
|
|
238
|
+
emit: (event: string, data?: unknown) => void;
|
|
239
|
+
/** Destroy the form and clean up */
|
|
240
|
+
destroy: () => void;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Internal component structure before API is applied
|
|
244
|
+
*/
|
|
245
|
+
export interface BaseFormComponent {
|
|
246
|
+
element: HTMLElement;
|
|
247
|
+
form?: HTMLFormElement;
|
|
248
|
+
ui?: Record<string, unknown>;
|
|
249
|
+
fields?: FormFieldRegistry;
|
|
250
|
+
state?: FormState;
|
|
251
|
+
config?: FormConfig;
|
|
252
|
+
componentName?: string;
|
|
253
|
+
getClass?: (name: string) => string;
|
|
254
|
+
on?: (event: string, handler: Function) => void;
|
|
255
|
+
off?: (event: string, handler: Function) => void;
|
|
256
|
+
emit?: (event: string, data?: unknown) => void;
|
|
257
|
+
lifecycle?: {
|
|
258
|
+
destroy: () => void;
|
|
259
|
+
};
|
|
260
|
+
}
|
|
@@ -5,3 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { createVList } from "./vlist";
|
|
7
7
|
export type { VListConfig, VListComponent } from "./vlist/types";
|
|
8
|
+
export { createForm } from "./form";
|
|
9
|
+
export type { FormConfig, FormComponent, FormField, FormData, DataState, FormState, FormValidationRule, FormValidationResult, FormSubmitOptions, FormEventHandlers, FieldValue, SubmitHandler, CancelHandler, } from "./form/types";
|
|
10
|
+
export { DATA_STATE, FORM_EVENTS, FORM_CLASSES, FORM_DEFAULTS, } from "./form/constants";
|