@relax.js/core 1.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/LICENSE +21 -0
- package/README.md +188 -0
- package/dist/DataLoader.d.ts +51 -0
- package/dist/DependencyInjection.d.ts +271 -0
- package/dist/DependencyInjectionOld.d.ts +35 -0
- package/dist/Metadata.d.ts +8 -0
- package/dist/SequentialId.d.ts +47 -0
- package/dist/_alt/src/MustardEngine.d.ts +30 -0
- package/dist/_alt/src/MustardParser.d.ts +63 -0
- package/dist/_alt/src/MustardParser2.d.ts +35 -0
- package/dist/_alt/src/pipes.d.ts +93 -0
- package/dist/_alt/src/template.d.ts +166 -0
- package/dist/_alt/src/tools.d.ts +4 -0
- package/dist/_alt/tests/pipes.tests.d.ts +1 -0
- package/dist/_alt/tests/template.tests.d.ts +1 -0
- package/dist/_alt/vitest.config.d.ts +2 -0
- package/dist/collections/Index.d.ts +1 -0
- package/dist/collections/LinkedList.d.ts +75 -0
- package/dist/collections/Pager.d.ts +15 -0
- package/dist/collections/index.js +2 -0
- package/dist/collections/index.js.map +7 -0
- package/dist/collections/index.mjs +2 -0
- package/dist/collections/index.mjs.map +7 -0
- package/dist/components/Table.d.ts +13 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +128 -0
- package/dist/components/index.js.map +7 -0
- package/dist/components/index.mjs +128 -0
- package/dist/components/index.mjs.map +7 -0
- package/dist/components/lists/Table.d.ts +59 -0
- package/dist/components/lists/TreeView.d.ts +67 -0
- package/dist/components/lists/index.d.ts +2 -0
- package/dist/components/loader.d.ts +60 -0
- package/dist/components/menus/MenuItem.d.ts +30 -0
- package/dist/components/menus/TopMenu.d.ts +16 -0
- package/dist/components/menus/index.d.ts +2 -0
- package/dist/components/panels/tabs.d.ts +15 -0
- package/dist/di/index.d.ts +1 -0
- package/dist/di/index.js +2 -0
- package/dist/di/index.js.map +7 -0
- package/dist/di/index.mjs +2 -0
- package/dist/di/index.mjs.map +7 -0
- package/dist/elements/CopyAttributes.d.ts +2 -0
- package/dist/elements/dom.d.ts +18 -0
- package/dist/elements/index.d.ts +2 -0
- package/dist/elements/index.js +2 -0
- package/dist/elements/index.js.map +7 -0
- package/dist/elements/index.mjs +2 -0
- package/dist/elements/index.mjs.map +7 -0
- package/dist/errors.d.ts +71 -0
- package/dist/forms/FormReader.d.ts +182 -0
- package/dist/forms/FormValidator.d.ts +114 -0
- package/dist/forms/ValidationRules.d.ts +103 -0
- package/dist/forms/index.d.ts +4 -0
- package/dist/forms/index.js +2 -0
- package/dist/forms/index.js.map +7 -0
- package/dist/forms/index.mjs +2 -0
- package/dist/forms/index.mjs.map +7 -0
- package/dist/forms/setFormData.d.ts +49 -0
- package/dist/getParentComponent.d.ts +43 -0
- package/dist/html/TableRenderer.d.ts +44 -0
- package/dist/html/TreeBinder.d.ts +9 -0
- package/dist/html/html.d.ts +55 -0
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.js +2 -0
- package/dist/html/index.js.map +7 -0
- package/dist/html/index.mjs +2 -0
- package/dist/html/index.mjs.map +7 -0
- package/dist/html/template.d.ts +167 -0
- package/dist/http/ServerSentEvents.d.ts +116 -0
- package/dist/http/SimpleWebSocket.d.ts +153 -0
- package/dist/http/http.d.ts +177 -0
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.js +2 -0
- package/dist/http/index.js.map +7 -0
- package/dist/http/index.mjs +2 -0
- package/dist/http/index.mjs.map +7 -0
- package/dist/i18n/i18n.d.ts +105 -0
- package/dist/i18n/icu.d.ts +64 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/index.js.map +7 -0
- package/dist/i18n/index.mjs +2 -0
- package/dist/i18n/index.mjs.map +7 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +7 -0
- package/dist/index.mjs +5 -0
- package/dist/index.mjs.map +7 -0
- package/dist/lib/DataLoader.d.ts +51 -0
- package/dist/lib/DependencyInjection.d.ts +271 -0
- package/dist/lib/InvokeParent.d.ts +10 -0
- package/dist/lib/Pipes.d.ts +236 -0
- package/dist/lib/SequentialId.d.ts +47 -0
- package/dist/lib/collections/Index.d.ts +1 -0
- package/dist/lib/collections/LinkedList.d.ts +75 -0
- package/dist/lib/collections/Pager.d.ts +15 -0
- package/dist/lib/collections/TableRenderer.d.ts +44 -0
- package/dist/lib/di/index.d.ts +1 -0
- package/dist/lib/elements/CopyAttributes.d.ts +2 -0
- package/dist/lib/elements/dom.d.ts +18 -0
- package/dist/lib/elements/index.d.ts +2 -0
- package/dist/lib/errors.d.ts +71 -0
- package/dist/lib/forms/FormReader.d.ts +182 -0
- package/dist/lib/forms/FormValidator.d.ts +114 -0
- package/dist/lib/forms/ValidationRules.d.ts +103 -0
- package/dist/lib/forms/index.d.ts +4 -0
- package/dist/lib/forms/setFormData.d.ts +49 -0
- package/dist/lib/getParentComponent.d.ts +43 -0
- package/dist/lib/html/TableRenderer.d.ts +44 -0
- package/dist/lib/html/TreeBinder.d.ts +9 -0
- package/dist/lib/html/html.d.ts +55 -0
- package/dist/lib/html/html2.d.ts +55 -0
- package/dist/lib/html/index.d.ts +5 -0
- package/dist/lib/html/m.d.ts +167 -0
- package/dist/lib/html/m2.d.ts +8 -0
- package/dist/lib/html/m3.d.ts +0 -0
- package/dist/lib/html/template.d.ts +167 -0
- package/dist/lib/http/HttpClient.d.ts +153 -0
- package/dist/lib/http/ServerSentEvents.d.ts +116 -0
- package/dist/lib/http/SimpleWebSocket.d.ts +153 -0
- package/dist/lib/http/http.d.ts +177 -0
- package/dist/lib/http/index.d.ts +3 -0
- package/dist/lib/i18n/i18n.d.ts +105 -0
- package/dist/lib/i18n/icu.d.ts +64 -0
- package/dist/lib/i18n/index.d.ts +2 -0
- package/dist/lib/index.d.ts +16 -0
- package/dist/lib/routing/NavigateRouteEvent.d.ts +52 -0
- package/dist/lib/routing/RouteLink.d.ts +7 -0
- package/dist/lib/routing/Routing.d.ts +270 -0
- package/dist/lib/routing/RoutingTarget.d.ts +22 -0
- package/dist/lib/routing/index.d.ts +7 -0
- package/dist/lib/routing/navigation.d.ts +70 -0
- package/dist/lib/routing/routeMatching.d.ts +21 -0
- package/dist/lib/routing/routeTargetRegistry.d.ts +23 -0
- package/dist/lib/routing/types.d.ts +130 -0
- package/dist/lib/templates/NodeTemplate.d.ts +38 -0
- package/dist/lib/templates/accessorParser.d.ts +87 -0
- package/dist/lib/templates/parseTemplate.d.ts +6 -0
- package/dist/lib/templates/tokenizer.d.ts +76 -0
- package/dist/lib/tools.d.ts +30 -0
- package/dist/lib/utils/index.d.ts +4 -0
- package/dist/pipes.d.ts +236 -0
- package/dist/routing/NavigateRouteEvent.d.ts +52 -0
- package/dist/routing/RouteLink.d.ts +7 -0
- package/dist/routing/RoutingTarget.d.ts +22 -0
- package/dist/routing/index.d.ts +7 -0
- package/dist/routing/index.js +5 -0
- package/dist/routing/index.js.map +7 -0
- package/dist/routing/index.mjs +5 -0
- package/dist/routing/index.mjs.map +7 -0
- package/dist/routing/navigation.d.ts +70 -0
- package/dist/routing/routeMatching.d.ts +21 -0
- package/dist/routing/routeTargetRegistry.d.ts +23 -0
- package/dist/routing/types.d.ts +130 -0
- package/dist/templates/NodeTemplate.d.ts +38 -0
- package/dist/templates/accessorParser.d.ts +87 -0
- package/dist/templates/parseTemplate.d.ts +6 -0
- package/dist/templates/tokenizer.d.ts +76 -0
- package/dist/tools.d.ts +30 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +7 -0
- package/dist/utils/index.mjs +2 -0
- package/dist/utils/index.mjs.map +7 -0
- package/docs/Architecture.md +333 -0
- package/docs/DependencyInjection.md +237 -0
- package/docs/Errors.md +87 -0
- package/docs/GettingStarted.md +231 -0
- package/docs/Pipes.md +211 -0
- package/docs/Translations.md +312 -0
- package/docs/WhyRelaxjs.md +336 -0
- package/docs/elements/dom.md +102 -0
- package/docs/forms/creating-form-components.md +924 -0
- package/docs/forms/form-api.md +94 -0
- package/docs/forms/forms.md +99 -0
- package/docs/forms/patterns.md +311 -0
- package/docs/forms/reading-writing.md +365 -0
- package/docs/forms/validation.md +351 -0
- package/docs/html/TableRenderer.md +292 -0
- package/docs/html/html.md +175 -0
- package/docs/html/index.md +54 -0
- package/docs/html/template.md +422 -0
- package/docs/http/HttpClient.md +459 -0
- package/docs/http/ServerSentEvents.md +184 -0
- package/docs/http/index.md +109 -0
- package/docs/i18n/i18n.md +309 -0
- package/docs/i18n/intl-standard.md +178 -0
- package/docs/routing/RouteLink.md +98 -0
- package/docs/routing/Routing.md +332 -0
- package/docs/routing/RoutingTarget.md +136 -0
- package/docs/routing/layouts.md +207 -0
- package/docs/utilities.md +143 -0
- package/package.json +93 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class PageSelectedEvent extends CustomEvent<number> {
|
|
2
|
+
page: number;
|
|
3
|
+
constructor(page: number);
|
|
4
|
+
}
|
|
5
|
+
export declare class Pager {
|
|
6
|
+
private container;
|
|
7
|
+
private totalCount;
|
|
8
|
+
private pageSize;
|
|
9
|
+
private currentPage;
|
|
10
|
+
constructor(container: HTMLElement, totalCount: number, pageSize: number);
|
|
11
|
+
private render;
|
|
12
|
+
private selectPage;
|
|
13
|
+
update(totalCount: number): void;
|
|
14
|
+
getCurrentPage(): number;
|
|
15
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare class TableRenderer {
|
|
2
|
+
private table;
|
|
3
|
+
private template;
|
|
4
|
+
private component;
|
|
5
|
+
private dataMap;
|
|
6
|
+
private rowMap;
|
|
7
|
+
IdColumn: string;
|
|
8
|
+
constructor(table: HTMLTableElement, template: HTMLTemplateElement, idColumn: string, component: HTMLElement);
|
|
9
|
+
render(data: Record<string, any>[]): void;
|
|
10
|
+
private clearRows;
|
|
11
|
+
private renderRow;
|
|
12
|
+
private populateRow;
|
|
13
|
+
private attachEventHandlers;
|
|
14
|
+
update(data: Record<string, any>): void;
|
|
15
|
+
}
|
|
16
|
+
export declare class SortChangeEvent extends CustomEvent<SortColumn[]> {
|
|
17
|
+
constructor(sortColumns: SortColumn[]);
|
|
18
|
+
}
|
|
19
|
+
type SortDirection = 'asc' | 'desc';
|
|
20
|
+
export type SortColumn = {
|
|
21
|
+
column: string;
|
|
22
|
+
direction: SortDirection;
|
|
23
|
+
};
|
|
24
|
+
export declare class TableSorter {
|
|
25
|
+
private table;
|
|
26
|
+
private sortColumns;
|
|
27
|
+
private component;
|
|
28
|
+
constructor(table: HTMLTableElement, component: HTMLElement);
|
|
29
|
+
private setupListeners;
|
|
30
|
+
private toggle;
|
|
31
|
+
private emit;
|
|
32
|
+
private updateSortIndicators;
|
|
33
|
+
getSortColumns(): SortColumn[];
|
|
34
|
+
clear(): void;
|
|
35
|
+
}
|
|
36
|
+
declare global {
|
|
37
|
+
interface HTMLTableElementEventMap extends HTMLElementEventMap {
|
|
38
|
+
'sortchange': SortChangeEvent;
|
|
39
|
+
}
|
|
40
|
+
interface HTMLTableElement {
|
|
41
|
+
addEventListener<K extends keyof HTMLTableElementEventMap>(type: K, listener: (this: HTMLTableElement, ev: HTMLTableElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../DependencyInjection';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds exactly one element matching the selector. When the selector starts
|
|
3
|
+
* with `#`, both `id` and `name` attributes are tried.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const input = selectOne<HTMLInputElement>('#email');
|
|
7
|
+
* const btn = selectOne<HTMLButtonElement>('.submit', form);
|
|
8
|
+
*/
|
|
9
|
+
export declare function selectOne<T extends Element = HTMLElement>(selector: string, parent?: Element | Document): T;
|
|
10
|
+
/**
|
|
11
|
+
* Sets a validation error on a form field found by selector. Supports native
|
|
12
|
+
* form elements and form-associated custom elements using `ElementInternals`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* formError('#email', 'Please enter a valid email');
|
|
16
|
+
* formError('#email', ''); // clears the error
|
|
17
|
+
*/
|
|
18
|
+
export declare function formError(selector: string, message: string, parent?: Element | Document): void;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global error handling for Relaxjs.
|
|
3
|
+
* Register a handler with `onError()` to intercept errors before they throw.
|
|
4
|
+
* Call `ctx.suppress()` in the handler to prevent the error from being thrown.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { onError } from 'relaxjs';
|
|
8
|
+
*
|
|
9
|
+
* onError((error, ctx) => {
|
|
10
|
+
* logToService(error.message, error.context);
|
|
11
|
+
* showToast(error.message);
|
|
12
|
+
* ctx.suppress();
|
|
13
|
+
* });
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Passed to error handlers to control error behavior.
|
|
17
|
+
* Call `suppress()` to prevent the error from being thrown.
|
|
18
|
+
*/
|
|
19
|
+
export interface ErrorContext {
|
|
20
|
+
suppress(): void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Error with structured context for debugging.
|
|
24
|
+
* The `context` record contains details like route name, component tag, route data.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* onError((error, ctx) => {
|
|
28
|
+
* console.log(error.context.route);
|
|
29
|
+
* console.log(error.context.componentTagName);
|
|
30
|
+
* });
|
|
31
|
+
*/
|
|
32
|
+
export declare class RelaxError extends Error {
|
|
33
|
+
context: Record<string, unknown>;
|
|
34
|
+
constructor(message: string, context: Record<string, unknown>);
|
|
35
|
+
}
|
|
36
|
+
type ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Registers a global error handler for Relaxjs errors.
|
|
39
|
+
* The handler receives the error and an `ErrorContext`.
|
|
40
|
+
* Call `ctx.suppress()` to prevent the error from being thrown.
|
|
41
|
+
* Only one handler can be active at a time; subsequent calls replace the previous handler.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* onError((error, ctx) => {
|
|
45
|
+
* if (error.context.route === 'optional-panel') {
|
|
46
|
+
* ctx.suppress();
|
|
47
|
+
* return;
|
|
48
|
+
* }
|
|
49
|
+
* showErrorDialog(error.message);
|
|
50
|
+
* });
|
|
51
|
+
*/
|
|
52
|
+
export declare function onError(fn: ErrorHandler): void;
|
|
53
|
+
/**
|
|
54
|
+
* Reports an error through the global handler.
|
|
55
|
+
* Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.
|
|
56
|
+
* The caller is responsible for throwing the returned error.
|
|
57
|
+
*
|
|
58
|
+
* @param message - Human-readable error description
|
|
59
|
+
* @param context - Structured data for debugging (route, component, params, cause, etc.)
|
|
60
|
+
* @returns The error to throw, or `null` if suppressed
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const error = reportError('Failed to load route component', {
|
|
64
|
+
* route: 'user',
|
|
65
|
+
* componentTagName: 'user-profile',
|
|
66
|
+
* routeData: { id: 123 },
|
|
67
|
+
* });
|
|
68
|
+
* if (error) throw error;
|
|
69
|
+
*/
|
|
70
|
+
export declare function reportError(message: string, context: Record<string, unknown>): RelaxError | null;
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module FormReader
|
|
3
|
+
* Utilities for reading form data into typed objects.
|
|
4
|
+
* Handles type conversion based on input types and data-type attributes.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // Basic form reading
|
|
8
|
+
* const form = document.querySelector('form');
|
|
9
|
+
* const data = readData(form);
|
|
10
|
+
*
|
|
11
|
+
* // Type-safe mapping to a class instance
|
|
12
|
+
* const user = mapFormToClass(form, new UserDTO());
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Maps form field values to a class instance's properties.
|
|
16
|
+
* Automatically converts values based on input types (checkbox, number, date).
|
|
17
|
+
*
|
|
18
|
+
* Form field names must match property names on the target instance.
|
|
19
|
+
*
|
|
20
|
+
* @template T - The type of the class instance
|
|
21
|
+
* @param form - The HTML form element to read from
|
|
22
|
+
* @param instance - The class instance to populate
|
|
23
|
+
* @param options - Configuration options
|
|
24
|
+
* @param options.throwOnMissingProperty - Throw if form field has no matching property
|
|
25
|
+
* @param options.throwOnMissingField - Throw if class property has no matching form field
|
|
26
|
+
* @returns The populated instance
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* class UserDTO {
|
|
30
|
+
* name: string = '';
|
|
31
|
+
* email: string = '';
|
|
32
|
+
* age: number = 0;
|
|
33
|
+
* newsletter: boolean = false;
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* const form = document.querySelector('form');
|
|
37
|
+
* const user = mapFormToClass(form, new UserDTO());
|
|
38
|
+
* console.log(user.name, user.age, user.newsletter);
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // With validation
|
|
42
|
+
* const user = mapFormToClass(form, new UserDTO(), {
|
|
43
|
+
* throwOnMissingProperty: true, // Catch typos in form field names
|
|
44
|
+
* throwOnMissingField: true // Ensure all DTO fields are in form
|
|
45
|
+
* });
|
|
46
|
+
*/
|
|
47
|
+
export declare function mapFormToClass<T extends object>(form: HTMLFormElement, instance: T, options?: {
|
|
48
|
+
throwOnMissingProperty?: boolean;
|
|
49
|
+
throwOnMissingField?: boolean;
|
|
50
|
+
}): T;
|
|
51
|
+
/**
|
|
52
|
+
* Configuration options for form reading operations.
|
|
53
|
+
*/
|
|
54
|
+
export interface FormReaderOptions {
|
|
55
|
+
/** Prefix to strip from field names when mapping to properties */
|
|
56
|
+
prefix?: string;
|
|
57
|
+
/** If true, checkboxes return their value instead of true/false */
|
|
58
|
+
disableBinaryCheckbox?: boolean;
|
|
59
|
+
/** If true, radio buttons return their value instead of true/false */
|
|
60
|
+
disableBinaryRadioButton?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Gets the appropriate type converter function for a form element.
|
|
64
|
+
* Uses the `data-type` attribute if present, otherwise infers from input type.
|
|
65
|
+
*
|
|
66
|
+
* @param element - The form element to get a converter for
|
|
67
|
+
* @returns A function that converts string values to the appropriate type
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* // With data-type attribute
|
|
71
|
+
* <input name="age" data-type="number" />
|
|
72
|
+
* const converter = getDataConverter(input);
|
|
73
|
+
* converter('42'); // Returns: 42 (number)
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // Inferred from input type
|
|
77
|
+
* <input type="checkbox" name="active" />
|
|
78
|
+
* const converter = getDataConverter(checkbox);
|
|
79
|
+
* converter('true'); // Returns: true (boolean)
|
|
80
|
+
*/
|
|
81
|
+
export declare function getDataConverter(element: HTMLElement): ConverterFunc;
|
|
82
|
+
/**
|
|
83
|
+
* Reads all form data into a plain object with automatic type conversion.
|
|
84
|
+
* Handles multiple values (e.g., multi-select) and custom form-associated elements.
|
|
85
|
+
*
|
|
86
|
+
* Type conversion is based on:
|
|
87
|
+
* 1. `data-type` attribute if present (number, boolean, string, Date)
|
|
88
|
+
* 2. Input type (checkbox, number, date, etc.)
|
|
89
|
+
* 3. Falls back to string
|
|
90
|
+
*
|
|
91
|
+
* @param form - The HTML form element to read
|
|
92
|
+
* @returns Object with property names matching field names
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* // HTML form
|
|
96
|
+
* <form>
|
|
97
|
+
* <input name="username" value="john" />
|
|
98
|
+
* <input name="age" type="number" value="25" />
|
|
99
|
+
* <input name="active" type="checkbox" checked />
|
|
100
|
+
* <select name="colors" multiple>
|
|
101
|
+
* <option value="red" selected>Red</option>
|
|
102
|
+
* <option value="blue" selected>Blue</option>
|
|
103
|
+
* </select>
|
|
104
|
+
* </form>
|
|
105
|
+
*
|
|
106
|
+
* // Reading the form
|
|
107
|
+
* const data = readData(form);
|
|
108
|
+
* // Returns: { username: 'john', age: 25, active: true, colors: ['red', 'blue'] }
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* // With custom form elements
|
|
112
|
+
* <form>
|
|
113
|
+
* <r-input name="email" value="test@example.com" />
|
|
114
|
+
* <r-checkbox name="terms" checked />
|
|
115
|
+
* </form>
|
|
116
|
+
* const data = readData(form);
|
|
117
|
+
1*/
|
|
118
|
+
export declare function readData<T = Record<string, unknown>>(form: HTMLFormElement): T;
|
|
119
|
+
/**
|
|
120
|
+
* Function type for converting string form values to typed values.
|
|
121
|
+
*/
|
|
122
|
+
export type ConverterFunc = (value: string) => unknown;
|
|
123
|
+
/**
|
|
124
|
+
* Supported data-type attribute values for explicit type conversion.
|
|
125
|
+
*/
|
|
126
|
+
export type DataType = 'number' | 'boolean' | 'string' | 'Date';
|
|
127
|
+
/**
|
|
128
|
+
* Supported HTML input types for automatic type inference.
|
|
129
|
+
*/
|
|
130
|
+
export type InputType = 'tel' | 'text' | 'checkbox' | 'radio' | 'number' | 'color' | 'date' | 'datetime-local' | 'month' | 'week' | 'time';
|
|
131
|
+
/**
|
|
132
|
+
* Converts string values to booleans.
|
|
133
|
+
* Handles 'true'/'false' strings and numeric values (>0 is true).
|
|
134
|
+
*
|
|
135
|
+
* @param value - String value to convert
|
|
136
|
+
* @returns Boolean value or undefined if empty
|
|
137
|
+
* @throws Error if value cannot be interpreted as boolean
|
|
138
|
+
*/
|
|
139
|
+
export declare function BooleanConverter(value?: string): boolean | undefined;
|
|
140
|
+
/**
|
|
141
|
+
* Converts string values to numbers.
|
|
142
|
+
*
|
|
143
|
+
* @param value - String value to convert
|
|
144
|
+
* @returns Number value or undefined if empty
|
|
145
|
+
* @throws Error if value is not a valid number
|
|
146
|
+
*/
|
|
147
|
+
export declare function NumberConverter(value?: string): number | undefined;
|
|
148
|
+
/**
|
|
149
|
+
* Converts string values to Date objects.
|
|
150
|
+
* Supports both ISO format (`2024-01-15`) and locale-specific formats
|
|
151
|
+
* (`01/15/2024` for en-US, `15.01.2024` for de, etc.) based on the
|
|
152
|
+
* current i18n locale.
|
|
153
|
+
*
|
|
154
|
+
* @param value - Date string in ISO or locale format
|
|
155
|
+
* @returns Date object
|
|
156
|
+
* @throws Error if value is not a valid date
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* // ISO format (from <input type="date">)
|
|
160
|
+
* DateConverter('2024-01-15') // Date(2024, 0, 15)
|
|
161
|
+
*
|
|
162
|
+
* // Locale format (from <input type="text" data-type="Date">)
|
|
163
|
+
* // with locale set to 'sv': 2024-01-15
|
|
164
|
+
* // with locale set to 'en-US': 01/15/2024
|
|
165
|
+
* // with locale set to 'de': 15.01.2024
|
|
166
|
+
*/
|
|
167
|
+
export declare function DateConverter(value: string): Date | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* Creates a converter function based on the data-type attribute value.
|
|
170
|
+
*
|
|
171
|
+
* @param dataType - The data-type attribute value
|
|
172
|
+
* @returns Appropriate converter function for the type
|
|
173
|
+
*/
|
|
174
|
+
export declare function createConverterFromDataType(dataType: DataType): ConverterFunc;
|
|
175
|
+
/**
|
|
176
|
+
* Creates a converter function based on HTML input type.
|
|
177
|
+
* Handles special types like checkbox, date, time, week, and month.
|
|
178
|
+
*
|
|
179
|
+
* @param inputType - The HTML input type attribute value
|
|
180
|
+
* @returns Appropriate converter function for the type
|
|
181
|
+
*/
|
|
182
|
+
export declare function createConverterFromInputType(inputType: InputType): ConverterFunc;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module FormValidator
|
|
3
|
+
* Form validation with support for native HTML5 validation and error summaries.
|
|
4
|
+
* Provides automatic validation on submit with customizable behavior.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // Basic usage with submit callback
|
|
8
|
+
* const form = document.querySelector('form');
|
|
9
|
+
* const validator = new FormValidator(form, {
|
|
10
|
+
* submitCallback: () => saveData()
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // With auto-validation on input
|
|
15
|
+
* const validator = new FormValidator(form, {
|
|
16
|
+
* autoValidate: true,
|
|
17
|
+
* useSummary: true
|
|
18
|
+
* });
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Configuration options for FormValidator.
|
|
22
|
+
*/
|
|
23
|
+
export interface ValidatorOptions {
|
|
24
|
+
/** Validate on every input event, not just submit */
|
|
25
|
+
autoValidate?: boolean;
|
|
26
|
+
/** Show errors in a summary element instead of browser tooltips */
|
|
27
|
+
useSummary?: boolean;
|
|
28
|
+
/** Custom validation function called before native validation */
|
|
29
|
+
customChecks?: (form: HTMLFormElement) => void;
|
|
30
|
+
/** Always prevent default form submission */
|
|
31
|
+
preventDefault?: boolean;
|
|
32
|
+
/** Prevent default on validation failure (default: true) */
|
|
33
|
+
preventDefaultOnFailed?: boolean;
|
|
34
|
+
/** Callback invoked when form passes validation */
|
|
35
|
+
submitCallback?: () => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Form validation helper that integrates with HTML5 validation.
|
|
39
|
+
* Supports error summaries, auto-validation, and custom submit handling.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // Prevent submission and handle manually
|
|
43
|
+
* class MyComponent extends HTMLElement {
|
|
44
|
+
* private validator: FormValidator;
|
|
45
|
+
*
|
|
46
|
+
* connectedCallback() {
|
|
47
|
+
* const form = this.querySelector('form');
|
|
48
|
+
* this.validator = new FormValidator(form, {
|
|
49
|
+
* submitCallback: () => this.handleSubmit()
|
|
50
|
+
* });
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* private async handleSubmit() {
|
|
54
|
+
* const data = readData(this.form);
|
|
55
|
+
* await fetch('/api/save', { method: 'POST', body: JSON.stringify(data) });
|
|
56
|
+
* }
|
|
57
|
+
* }
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* // With error summary display
|
|
61
|
+
* const validator = new FormValidator(form, {
|
|
62
|
+
* useSummary: true,
|
|
63
|
+
* autoValidate: true
|
|
64
|
+
* });
|
|
65
|
+
*/
|
|
66
|
+
export declare class FormValidator {
|
|
67
|
+
private form;
|
|
68
|
+
private options?;
|
|
69
|
+
private errorSummary;
|
|
70
|
+
constructor(form: HTMLFormElement, options?: ValidatorOptions);
|
|
71
|
+
/**
|
|
72
|
+
* Validates all form fields.
|
|
73
|
+
* Uses native HTML5 validation and optionally displays an error summary.
|
|
74
|
+
*
|
|
75
|
+
* @returns true if form is valid, false otherwise
|
|
76
|
+
*/
|
|
77
|
+
validateForm(): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Displays a list of error messages in the summary element.
|
|
80
|
+
*
|
|
81
|
+
* @param messages - Array of error messages to display
|
|
82
|
+
*/
|
|
83
|
+
displayErrorSummary(messages: string[]): void;
|
|
84
|
+
private createErrorSummary;
|
|
85
|
+
/**
|
|
86
|
+
* Adds a single error to the summary display.
|
|
87
|
+
*
|
|
88
|
+
* @param fieldName - The name of the field with the error
|
|
89
|
+
* @param message - The error message
|
|
90
|
+
*/
|
|
91
|
+
addErrorToSummary(fieldName: string, message: string): void;
|
|
92
|
+
/**
|
|
93
|
+
* Clears all errors from the summary display.
|
|
94
|
+
*/
|
|
95
|
+
clearErrorSummary(): void;
|
|
96
|
+
private focusFirstErrorElement;
|
|
97
|
+
/**
|
|
98
|
+
* Finds a form element relative to the given element.
|
|
99
|
+
* Searches parent first, then direct children.
|
|
100
|
+
*
|
|
101
|
+
* @param element - The element to search from
|
|
102
|
+
* @returns The found form element
|
|
103
|
+
* @throws Error if no form is found
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* class MyComponent extends HTMLElement {
|
|
107
|
+
* connectedCallback() {
|
|
108
|
+
* const form = FormValidator.FindForm(this);
|
|
109
|
+
* new FormValidator(form);
|
|
110
|
+
* }
|
|
111
|
+
* }
|
|
112
|
+
*/
|
|
113
|
+
static FindForm(element: HTMLElement): HTMLFormElement;
|
|
114
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ValidationRules
|
|
3
|
+
* Form validation rules for use with FormValidator.
|
|
4
|
+
* Provides declarative validation through decorators.
|
|
5
|
+
*
|
|
6
|
+
* Validation messages use the i18n system. Load the 'r-validation' namespace
|
|
7
|
+
* for localized error messages:
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* await loadNamespace('r-validation');
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // In HTML, use validation attributes
|
|
14
|
+
* <input name="age" data-validate="required range(0-120)" />
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Context provided to validators during validation.
|
|
18
|
+
*/
|
|
19
|
+
export interface ValidationContext {
|
|
20
|
+
/** The HTML input type (text, number, email, etc.) */
|
|
21
|
+
inputType: string;
|
|
22
|
+
/** The data-type attribute value if present */
|
|
23
|
+
dataType?: string;
|
|
24
|
+
/** Adds an error message to the validation result */
|
|
25
|
+
addError(message: string): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Interface for custom validators.
|
|
29
|
+
*/
|
|
30
|
+
interface Validator {
|
|
31
|
+
/**
|
|
32
|
+
* Validates the given value.
|
|
33
|
+
* @param value - The string value to validate
|
|
34
|
+
* @param context - Validation context with type info and error reporting
|
|
35
|
+
*/
|
|
36
|
+
validate(value: string, context: ValidationContext): void;
|
|
37
|
+
}
|
|
38
|
+
interface ValidatorRegistryEntry {
|
|
39
|
+
validator: {
|
|
40
|
+
new (): Validator;
|
|
41
|
+
};
|
|
42
|
+
validInputTypes: string[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Decorator to register a validator class for a specific validation name.
|
|
46
|
+
*
|
|
47
|
+
* @param validationName - The name used in data-validate attribute
|
|
48
|
+
* @param validInputTypes - Optional list of input types this validator applies to
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* @RegisterValidator('email')
|
|
52
|
+
* class EmailValidation implements Validator {
|
|
53
|
+
* validate(value: string, context: ValidationContext) {
|
|
54
|
+
* if (!value.includes('@')) {
|
|
55
|
+
* context.addError('Invalid email address');
|
|
56
|
+
* }
|
|
57
|
+
* }
|
|
58
|
+
* }
|
|
59
|
+
*/
|
|
60
|
+
export declare function RegisterValidator(validationName: string, validInputTypes?: string[]): (target: {
|
|
61
|
+
new (...args: unknown[]): Validator;
|
|
62
|
+
}) => void;
|
|
63
|
+
/**
|
|
64
|
+
* Looks up a registered validator by name.
|
|
65
|
+
*
|
|
66
|
+
* @param name - The validator name used in `data-validate`
|
|
67
|
+
* @returns The registry entry, or `undefined` if not found
|
|
68
|
+
*/
|
|
69
|
+
export declare function getValidator(name: string): ValidatorRegistryEntry | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Validates that a field has a non-empty value.
|
|
72
|
+
* Use with `data-validate="required"`.
|
|
73
|
+
*/
|
|
74
|
+
export declare class RequiredValidation implements Validator {
|
|
75
|
+
static create(rule: string): RequiredValidation | null;
|
|
76
|
+
validate(value: string, context: ValidationContext): void;
|
|
77
|
+
getMessage(): string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Validates that a numeric value falls within a specified range.
|
|
81
|
+
* Use with `data-validate="range(min-max)"`.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* <input name="age" type="number" data-validate="range(0-120)" />
|
|
85
|
+
*/
|
|
86
|
+
export declare class RangeValidation implements Validator {
|
|
87
|
+
min: number;
|
|
88
|
+
max: number;
|
|
89
|
+
constructor(min: number, max: number);
|
|
90
|
+
static create(rule: string): RangeValidation | null;
|
|
91
|
+
validate(value: string, context: ValidationContext): void;
|
|
92
|
+
getMessage(actual: string): string;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Validates that a value contains only numeric digits (0-9).
|
|
96
|
+
* Use with `data-validate="digits"`.
|
|
97
|
+
*/
|
|
98
|
+
export declare class DigitsValidation implements Validator {
|
|
99
|
+
static create(rule: string): DigitsValidation | null;
|
|
100
|
+
validate(value: string, context: ValidationContext): void;
|
|
101
|
+
getMessage(): string;
|
|
102
|
+
}
|
|
103
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FormReaderOptions, ConverterFunc, DataType, InputType, mapFormToClass, getDataConverter, readData, BooleanConverter, NumberConverter, DateConverter, createConverterFromDataType, createConverterFromInputType } from './FormReader';
|
|
2
|
+
export { ValidatorOptions, FormValidator } from './FormValidator';
|
|
3
|
+
export { setFormData } from './setFormData';
|
|
4
|
+
export { ValidationContext, RegisterValidator, getValidator, RequiredValidation, RangeValidation, DigitsValidation } from './ValidationRules';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sets form field values from a data object using the name attribute.
|
|
3
|
+
* Supports dot notation for accessing nested properties and array handling.
|
|
4
|
+
*
|
|
5
|
+
* @param form - The HTML form element to populate
|
|
6
|
+
* @param data - The data object containing values to set in the form
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // Basic usage with flat object
|
|
10
|
+
* const form = document.querySelector('form');
|
|
11
|
+
* const data = { name: 'John', email: 'john@example.com' };
|
|
12
|
+
* setFormData(form, data);
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Using with nested objects via dot notation
|
|
16
|
+
* const form = document.querySelector('form');
|
|
17
|
+
* const data = {
|
|
18
|
+
* user: {
|
|
19
|
+
* name: 'John',
|
|
20
|
+
* contact: {
|
|
21
|
+
* email: 'john@example.com'
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* };
|
|
25
|
+
* // Form has fields with names like "user.name" and "user.contact.email"
|
|
26
|
+
* setFormData(form, data);
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Using with simple arrays using [] notation
|
|
30
|
+
* const form = document.querySelector('form');
|
|
31
|
+
* const data = {
|
|
32
|
+
* hobbies: ['Reading', 'Cycling', 'Cooking']
|
|
33
|
+
* };
|
|
34
|
+
* // Form has multiple fields with names like "hobbies[]"
|
|
35
|
+
* setFormData(form, data);
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // Using with array of objects using numeric indexers
|
|
39
|
+
* const form = document.querySelector('form');
|
|
40
|
+
* const data = {
|
|
41
|
+
* users: [
|
|
42
|
+
* { name: 'John', email: 'john@example.com' },
|
|
43
|
+
* { name: 'Jane', email: 'jane@example.com' }
|
|
44
|
+
* ]
|
|
45
|
+
* };
|
|
46
|
+
* // Form has fields with names like "users[0].name", "users[1].email", etc.
|
|
47
|
+
* setFormData(form, data);
|
|
48
|
+
*/
|
|
49
|
+
export declare function setFormData(form: HTMLFormElement, data: object): void;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds the closest parent element of a specific Web Component type.
|
|
3
|
+
* Traverses up the DOM tree looking for an ancestor matching the constructor.
|
|
4
|
+
*
|
|
5
|
+
* Useful for child components that need to communicate with or access
|
|
6
|
+
* their parent container component, common in composite component patterns.
|
|
7
|
+
*
|
|
8
|
+
* @template T - The type of HTMLElement to find
|
|
9
|
+
* @param node - The starting node to search from
|
|
10
|
+
* @param constructor - The class constructor of the desired element type
|
|
11
|
+
* @returns The matching parent element or null if not found
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // Inside a child component, find the parent container
|
|
15
|
+
* class ListItem extends HTMLElement {
|
|
16
|
+
* connectedCallback() {
|
|
17
|
+
* const list = getParentComponent(this, ListContainer);
|
|
18
|
+
* if (list) {
|
|
19
|
+
* list.registerItem(this);
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Access parent component's methods
|
|
26
|
+
* class TabPanel extends HTMLElement {
|
|
27
|
+
* activate() {
|
|
28
|
+
* const tabs = getParentComponent(this, TabContainer);
|
|
29
|
+
* tabs?.selectPanel(this);
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Handle case where parent might not exist
|
|
35
|
+
* const form = getParentComponent(input, FormContainer);
|
|
36
|
+
* if (!form) {
|
|
37
|
+
* console.warn('Input must be inside a FormContainer');
|
|
38
|
+
* return;
|
|
39
|
+
* }
|
|
40
|
+
*/
|
|
41
|
+
export declare function getParentComponent<T extends HTMLElement>(node: Node, constructor: {
|
|
42
|
+
new (...args: any[]): T;
|
|
43
|
+
}): T | null;
|