@dmitryvim/form-builder 0.1.42 → 0.2.1
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/README.md +260 -22
- package/dist/browser/formbuilder.min.js +184 -0
- package/dist/browser/formbuilder.v0.2.1.min.js +184 -0
- package/dist/cjs/index.cjs +3652 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/esm/index.js +3603 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/form-builder.js +154 -3369
- package/dist/types/components/container.d.ts +15 -0
- package/dist/types/components/file.d.ts +26 -0
- package/dist/types/components/group.d.ts +24 -0
- package/dist/types/components/index.d.ts +11 -0
- package/dist/types/components/number.d.ts +11 -0
- package/dist/types/components/registry.d.ts +15 -0
- package/dist/types/components/select.d.ts +11 -0
- package/dist/types/components/text.d.ts +11 -0
- package/dist/types/components/textarea.d.ts +11 -0
- package/dist/types/index.d.ts +33 -0
- package/dist/types/instance/FormBuilderInstance.d.ts +134 -0
- package/dist/types/instance/state.d.ts +13 -0
- package/dist/types/styles/theme.d.ts +63 -0
- package/dist/types/types/component-operations.d.ts +45 -0
- package/dist/types/types/config.d.ts +47 -0
- package/dist/types/types/index.d.ts +4 -0
- package/dist/types/types/schema.d.ts +115 -0
- package/dist/types/types/state.d.ts +11 -0
- package/dist/types/utils/helpers.d.ts +4 -0
- package/dist/types/utils/styles.d.ts +21 -0
- package/dist/types/utils/translation.d.ts +8 -0
- package/dist/types/utils/validation.d.ts +2 -0
- package/package.json +32 -15
- package/dist/demo.js +0 -861
- package/dist/elements.html +0 -1130
- package/dist/elements.js +0 -488
- package/dist/index.html +0 -315
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ContainerElement, RenderContext, ComponentContext, ValidationResult, Element } from "../types/index.js";
|
|
2
|
+
export declare function setRenderElement(fn: (element: any, ctx: RenderContext) => HTMLElement): void;
|
|
3
|
+
export declare function renderSingleContainerElement(element: ContainerElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
4
|
+
export declare function renderMultipleContainerElement(element: ContainerElement, ctx: RenderContext, wrapper: HTMLElement, _pathKey: string): void;
|
|
5
|
+
export declare function setValidateElement(fn: (element: Element, ctx: {
|
|
6
|
+
path: string;
|
|
7
|
+
}, customScopeRoot?: HTMLElement | null) => any): void;
|
|
8
|
+
/**
|
|
9
|
+
* Validate container field and return extracted value with errors
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateContainerElement(element: Element, key: string, context: ComponentContext): ValidationResult;
|
|
12
|
+
/**
|
|
13
|
+
* Update container field value in DOM without re-render
|
|
14
|
+
*/
|
|
15
|
+
export declare function updateContainerField(element: Element, fieldPath: string, value: any, context: ComponentContext): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FileElement, FilesElement, RenderContext, ComponentContext, ValidationResult, Element } from "../types/index.js";
|
|
2
|
+
import type { State } from "../types/state.js";
|
|
3
|
+
interface FileDeps {
|
|
4
|
+
picker: HTMLInputElement;
|
|
5
|
+
fileUploadHandler: () => void;
|
|
6
|
+
dragHandler: (files: FileList) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function renderFilePreview(container: HTMLElement, resourceId: string, state: State, options?: {
|
|
9
|
+
fileName?: string;
|
|
10
|
+
isReadonly?: boolean;
|
|
11
|
+
deps?: FileDeps | null;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
export declare function renderFilePreviewReadonly(resourceId: string, state: State, fileName?: string): Promise<HTMLElement>;
|
|
14
|
+
export declare function renderResourcePills(container: HTMLElement, rids: string[] | null, state: State, onRemove: ((rid: string) => void) | null): void;
|
|
15
|
+
export declare function renderFileElement(element: FileElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
16
|
+
export declare function renderFilesElement(element: FilesElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
17
|
+
export declare function renderMultipleFileElement(element: FileElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Validate file field and return extracted value with errors
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateFileElement(element: Element, key: string, context: ComponentContext): ValidationResult;
|
|
22
|
+
/**
|
|
23
|
+
* Update file field value in DOM without re-render
|
|
24
|
+
*/
|
|
25
|
+
export declare function updateFileField(element: Element, fieldPath: string, value: any, context: ComponentContext): void;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { GroupElement, RenderContext, ComponentContext, ValidationResult, Element } from "../types/index.js";
|
|
2
|
+
export declare function setRenderElement(_fn: (element: any, ctx: RenderContext) => HTMLElement): void;
|
|
3
|
+
/**
|
|
4
|
+
* Renders a group element by translating it to a ContainerElement
|
|
5
|
+
* and delegating to container rendering functions.
|
|
6
|
+
*
|
|
7
|
+
* This maintains backward compatibility with the legacy group type
|
|
8
|
+
* while eliminating code duplication.
|
|
9
|
+
*
|
|
10
|
+
* @deprecated Use type: "container" with multiple: true instead of type: "group" with repeat: {min, max}
|
|
11
|
+
*/
|
|
12
|
+
export declare function renderGroupElement(element: GroupElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
13
|
+
export { renderGroupElement as renderRepeatableGroup };
|
|
14
|
+
export { renderGroupElement as renderSingleGroup };
|
|
15
|
+
/**
|
|
16
|
+
* Validate group field by delegating to container validation
|
|
17
|
+
* @deprecated Use validateContainerElement with type: "container" instead
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateGroupElement(element: Element, key: string, context: ComponentContext): ValidationResult;
|
|
20
|
+
/**
|
|
21
|
+
* Update group field by delegating to container update
|
|
22
|
+
* @deprecated Use updateContainerField with type: "container" instead
|
|
23
|
+
*/
|
|
24
|
+
export declare function updateGroupField(element: Element, fieldPath: string, value: any, context: ComponentContext): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Element, RenderContext } from "../types/index.js";
|
|
2
|
+
import { renderTextElement, renderMultipleTextElement } from "./text.js";
|
|
3
|
+
import { renderTextareaElement, renderMultipleTextareaElement } from "./textarea.js";
|
|
4
|
+
import { renderNumberElement, renderMultipleNumberElement } from "./number.js";
|
|
5
|
+
import { renderSelectElement, renderMultipleSelectElement } from "./select.js";
|
|
6
|
+
import { renderFileElement, renderFilesElement, renderMultipleFileElement } from "./file.js";
|
|
7
|
+
import { renderSingleContainerElement, renderMultipleContainerElement, setValidateElement as setContainerValidateElement } from "./container.js";
|
|
8
|
+
import { renderGroupElement } from "./group.js";
|
|
9
|
+
export declare function renderElement(element: Element, ctx: RenderContext): HTMLElement;
|
|
10
|
+
export { setContainerValidateElement };
|
|
11
|
+
export { renderTextElement, renderMultipleTextElement, renderTextareaElement, renderMultipleTextareaElement, renderNumberElement, renderMultipleNumberElement, renderSelectElement, renderMultipleSelectElement, renderFileElement, renderFilesElement, renderMultipleFileElement, renderSingleContainerElement, renderMultipleContainerElement, renderGroupElement, };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { NumberElement, RenderContext, ComponentContext, ValidationResult } from "../types/index.js";
|
|
2
|
+
export declare function renderNumberElement(element: NumberElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
3
|
+
export declare function renderMultipleNumberElement(element: NumberElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
4
|
+
/**
|
|
5
|
+
* Validate number input field and return extracted value with errors
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateNumberElement(element: NumberElement, key: string, context: ComponentContext): ValidationResult;
|
|
8
|
+
/**
|
|
9
|
+
* Update number field value in DOM without re-render
|
|
10
|
+
*/
|
|
11
|
+
export declare function updateNumberField(element: NumberElement, fieldPath: string, value: any, context: ComponentContext): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Element, ComponentContext, ValidationResult, ComponentOperations } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get component operations for a given element type
|
|
4
|
+
*/
|
|
5
|
+
export declare function getComponentOperations(elementType: string): ComponentOperations | null;
|
|
6
|
+
/**
|
|
7
|
+
* Validate element using component-specific validator
|
|
8
|
+
* Falls back to legacy implementation if component not yet migrated
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateElementWithComponent(element: Element, key: string, context: ComponentContext): ValidationResult | null;
|
|
11
|
+
/**
|
|
12
|
+
* Update element using component-specific updater
|
|
13
|
+
* Falls back to legacy implementation if component not yet migrated
|
|
14
|
+
*/
|
|
15
|
+
export declare function updateElementWithComponent(element: Element, fieldPath: string, value: any, context: ComponentContext): boolean;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SelectElement, RenderContext, ComponentContext, ValidationResult, Element } from "../types/index.js";
|
|
2
|
+
export declare function renderSelectElement(element: SelectElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
3
|
+
export declare function renderMultipleSelectElement(element: SelectElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
4
|
+
/**
|
|
5
|
+
* Validate select field and return extracted value with errors
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateSelectElement(element: Element, key: string, context: ComponentContext): ValidationResult;
|
|
8
|
+
/**
|
|
9
|
+
* Update select field value in DOM without re-render
|
|
10
|
+
*/
|
|
11
|
+
export declare function updateSelectField(element: Element, fieldPath: string, value: any, context: ComponentContext): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TextElement, RenderContext, ComponentContext, ValidationResult } from "../types/index.js";
|
|
2
|
+
export declare function renderTextElement(element: TextElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
3
|
+
export declare function renderMultipleTextElement(element: TextElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
4
|
+
/**
|
|
5
|
+
* Validate text input field and return extracted value with errors
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateTextElement(element: TextElement, key: string, context: ComponentContext): ValidationResult;
|
|
8
|
+
/**
|
|
9
|
+
* Update text field value in DOM without re-render
|
|
10
|
+
*/
|
|
11
|
+
export declare function updateTextField(element: TextElement, fieldPath: string, value: any, context: ComponentContext): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TextareaElement, RenderContext, ComponentContext, ValidationResult } from "../types/index.js";
|
|
2
|
+
export declare function renderTextareaElement(element: TextareaElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
3
|
+
export declare function renderMultipleTextareaElement(element: TextareaElement, ctx: RenderContext, wrapper: HTMLElement, pathKey: string): void;
|
|
4
|
+
/**
|
|
5
|
+
* Validate textarea element - delegates to text validator since they share validation logic
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateTextareaElement(element: TextareaElement, key: string, context: ComponentContext): ValidationResult;
|
|
8
|
+
/**
|
|
9
|
+
* Update textarea field - delegates to text updater since they share update logic
|
|
10
|
+
*/
|
|
11
|
+
export declare function updateTextareaField(element: TextareaElement, fieldPath: string, value: any, context: ComponentContext): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form Builder - Instance-Based API
|
|
3
|
+
*
|
|
4
|
+
* Zero-dependency JSON Schema form builder library with multi-instance support
|
|
5
|
+
*/
|
|
6
|
+
import { FormBuilderInstance } from "./instance/FormBuilderInstance.js";
|
|
7
|
+
import { validateSchema } from "./utils/validation.js";
|
|
8
|
+
export type { SelectOption, ElementAction, BaseElement, TextElement, TextareaElement, NumberElement, SelectElement, FileElement, FilesElement, ContainerElement, GroupElement, Element, Schema, ExternalAction, FormData, RenderContext, Translations, Locale, Config, ResourceMetadata, State, } from "./types/index.js";
|
|
9
|
+
export type { Theme } from "./styles/theme.js";
|
|
10
|
+
export { defaultTheme, exampleThemes } from "./styles/theme.js";
|
|
11
|
+
/**
|
|
12
|
+
* Factory function for creating new form instances
|
|
13
|
+
*
|
|
14
|
+
* @param config Optional configuration for the instance
|
|
15
|
+
* @returns FormBuilderInstance
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const form = createFormBuilder({
|
|
19
|
+
* uploadFile: async (file) => {
|
|
20
|
+
* // Upload logic
|
|
21
|
+
* return "resource-id-123";
|
|
22
|
+
* },
|
|
23
|
+
* downloadFile: (resourceId, fileName) => {
|
|
24
|
+
* // Download logic
|
|
25
|
+
* }
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* form.renderForm(containerElement, schema, prefillData);
|
|
29
|
+
*/
|
|
30
|
+
export declare function createFormBuilder(config?: Partial<import("./types/index.js").Config>): FormBuilderInstance;
|
|
31
|
+
export { FormBuilderInstance };
|
|
32
|
+
export { validateSchema };
|
|
33
|
+
export default FormBuilderInstance;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { Schema, ExternalAction, FormData as FormDataResult, Config, State } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* FormBuilderInstance - Encapsulates all form state and operations
|
|
4
|
+
* Allows multiple independent forms on the same page without state collisions
|
|
5
|
+
*/
|
|
6
|
+
export declare class FormBuilderInstance {
|
|
7
|
+
private state;
|
|
8
|
+
private instanceId;
|
|
9
|
+
constructor(config?: Partial<Config>);
|
|
10
|
+
/**
|
|
11
|
+
* Get instance ID (useful for debugging and resource prefixing)
|
|
12
|
+
*/
|
|
13
|
+
getInstanceId(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get current state (for advanced use cases)
|
|
16
|
+
*/
|
|
17
|
+
getState(): State;
|
|
18
|
+
/**
|
|
19
|
+
* Set the form root element
|
|
20
|
+
*/
|
|
21
|
+
setFormRoot(element: HTMLElement): void;
|
|
22
|
+
/**
|
|
23
|
+
* Configure the form builder
|
|
24
|
+
*/
|
|
25
|
+
configure(config: Partial<Config>): void;
|
|
26
|
+
/**
|
|
27
|
+
* Set file upload handler
|
|
28
|
+
*/
|
|
29
|
+
setUploadHandler(uploadFn: ((file: File) => Promise<string>) | null): void;
|
|
30
|
+
/**
|
|
31
|
+
* Set file download handler
|
|
32
|
+
*/
|
|
33
|
+
setDownloadHandler(downloadFn: ((resourceId: string, fileName: string) => void) | null): void;
|
|
34
|
+
/**
|
|
35
|
+
* Set thumbnail generation handler
|
|
36
|
+
*/
|
|
37
|
+
setThumbnailHandler(thumbnailFn: ((resourceId: string) => Promise<string | null>) | null): void;
|
|
38
|
+
/**
|
|
39
|
+
* Set action handler
|
|
40
|
+
*/
|
|
41
|
+
setActionHandler(actionFn: ((value: string, key: string, relatedField: string | null) => void) | null): void;
|
|
42
|
+
/**
|
|
43
|
+
* Set mode (edit or readonly)
|
|
44
|
+
*/
|
|
45
|
+
setMode(mode: "edit" | "readonly"): void;
|
|
46
|
+
/**
|
|
47
|
+
* Set locale
|
|
48
|
+
*/
|
|
49
|
+
setLocale(locale: "en" | "ru"): void;
|
|
50
|
+
/**
|
|
51
|
+
* Trigger onChange callbacks with debouncing
|
|
52
|
+
* @param fieldPath - Optional field path for field-specific change events
|
|
53
|
+
* @param fieldValue - Optional field value for field-specific change events
|
|
54
|
+
*/
|
|
55
|
+
triggerOnChange(fieldPath?: string, fieldValue?: any): void;
|
|
56
|
+
/**
|
|
57
|
+
* Register an external action that will be displayed as a button
|
|
58
|
+
* External actions can be form-level (no related_field) or field-level (with related_field)
|
|
59
|
+
* @param action - External action definition
|
|
60
|
+
*/
|
|
61
|
+
registerAction(action: ExternalAction): void;
|
|
62
|
+
/**
|
|
63
|
+
* Find the DOM element corresponding to a field path (instance-scoped)
|
|
64
|
+
*/
|
|
65
|
+
private findFormElementByFieldPath;
|
|
66
|
+
/**
|
|
67
|
+
* Find schema element by field path
|
|
68
|
+
*/
|
|
69
|
+
private findSchemaElement;
|
|
70
|
+
/**
|
|
71
|
+
* Resolve action label from schema or external action
|
|
72
|
+
*/
|
|
73
|
+
private resolveActionLabel;
|
|
74
|
+
/**
|
|
75
|
+
* Render form-level action buttons at the bottom of the form
|
|
76
|
+
*/
|
|
77
|
+
private renderFormLevelActions;
|
|
78
|
+
/**
|
|
79
|
+
* Render external action buttons for fields
|
|
80
|
+
*/
|
|
81
|
+
renderExternalActions(): void;
|
|
82
|
+
/**
|
|
83
|
+
* Render form from schema
|
|
84
|
+
*/
|
|
85
|
+
renderForm(root: HTMLElement, schema: Schema, prefill?: Record<string, any>, actions?: ExternalAction[]): void;
|
|
86
|
+
/**
|
|
87
|
+
* Validate form and extract data
|
|
88
|
+
* This is a complete copy of the validateForm logic from form-builder.ts
|
|
89
|
+
* but uses instance state instead of global state
|
|
90
|
+
*/
|
|
91
|
+
validateForm(skipValidation?: boolean): FormDataResult;
|
|
92
|
+
/**
|
|
93
|
+
* Get form data
|
|
94
|
+
*/
|
|
95
|
+
getFormData(): FormDataResult;
|
|
96
|
+
/**
|
|
97
|
+
* Submit form with validation
|
|
98
|
+
*/
|
|
99
|
+
submitForm(): FormDataResult;
|
|
100
|
+
/**
|
|
101
|
+
* Save draft without validation
|
|
102
|
+
*/
|
|
103
|
+
saveDraft(): FormDataResult;
|
|
104
|
+
/**
|
|
105
|
+
* Clear the form - reset all field values to empty while preserving form structure
|
|
106
|
+
* This is done by re-rendering the form with empty data
|
|
107
|
+
*/
|
|
108
|
+
clearForm(): void;
|
|
109
|
+
/**
|
|
110
|
+
* Build prefill data for hidden fields only
|
|
111
|
+
* Hidden fields should retain their values when clearing
|
|
112
|
+
*/
|
|
113
|
+
private buildHiddenFieldsData;
|
|
114
|
+
/**
|
|
115
|
+
* Set form data - update multiple fields without full re-render
|
|
116
|
+
* @param data - Object with field paths and their values
|
|
117
|
+
*/
|
|
118
|
+
setFormData(data: Record<string, any>): void;
|
|
119
|
+
/**
|
|
120
|
+
* Update a single field by path without full re-render
|
|
121
|
+
* @param fieldPath - Field path (e.g., "email", "address.city", "items[0].name")
|
|
122
|
+
* @param value - New value for the field
|
|
123
|
+
*/
|
|
124
|
+
updateField(fieldPath: string, value: any): void;
|
|
125
|
+
/**
|
|
126
|
+
* Update field value in DOM based on field type
|
|
127
|
+
* Delegates to component-specific updaters via registry
|
|
128
|
+
*/
|
|
129
|
+
private updateFieldValue;
|
|
130
|
+
/**
|
|
131
|
+
* Destroy instance and clean up resources
|
|
132
|
+
*/
|
|
133
|
+
destroy(): void;
|
|
134
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { State, Config } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Default configuration for new instances
|
|
4
|
+
*/
|
|
5
|
+
export declare const defaultConfig: Config;
|
|
6
|
+
/**
|
|
7
|
+
* Create a new isolated state object for a FormBuilderInstance
|
|
8
|
+
*/
|
|
9
|
+
export declare function createInstanceState(config?: Partial<Config>): State;
|
|
10
|
+
/**
|
|
11
|
+
* Generate unique instance ID for resource prefixing
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateInstanceId(): string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface Theme {
|
|
2
|
+
primaryColor: string;
|
|
3
|
+
primaryHoverColor: string;
|
|
4
|
+
errorColor: string;
|
|
5
|
+
errorHoverColor: string;
|
|
6
|
+
successColor: string;
|
|
7
|
+
borderColor: string;
|
|
8
|
+
borderHoverColor: string;
|
|
9
|
+
borderFocusColor: string;
|
|
10
|
+
backgroundColor: string;
|
|
11
|
+
backgroundHoverColor: string;
|
|
12
|
+
backgroundReadonlyColor: string;
|
|
13
|
+
textColor: string;
|
|
14
|
+
textSecondaryColor: string;
|
|
15
|
+
textPlaceholderColor: string;
|
|
16
|
+
textDisabledColor: string;
|
|
17
|
+
buttonBgColor: string;
|
|
18
|
+
buttonTextColor: string;
|
|
19
|
+
buttonBorderColor: string;
|
|
20
|
+
buttonHoverBgColor: string;
|
|
21
|
+
buttonHoverBorderColor: string;
|
|
22
|
+
actionBgColor: string;
|
|
23
|
+
actionTextColor: string;
|
|
24
|
+
actionBorderColor: string;
|
|
25
|
+
actionHoverBgColor: string;
|
|
26
|
+
actionHoverBorderColor: string;
|
|
27
|
+
fileUploadBgColor: string;
|
|
28
|
+
fileUploadBorderColor: string;
|
|
29
|
+
fileUploadTextColor: string;
|
|
30
|
+
fileUploadHoverBorderColor: string;
|
|
31
|
+
inputPaddingX: string;
|
|
32
|
+
inputPaddingY: string;
|
|
33
|
+
borderRadius: string;
|
|
34
|
+
borderWidth: string;
|
|
35
|
+
fontSize: string;
|
|
36
|
+
fontSizeSmall: string;
|
|
37
|
+
fontSizeExtraSmall: string;
|
|
38
|
+
fontFamily: string;
|
|
39
|
+
fontWeightNormal: string;
|
|
40
|
+
fontWeightMedium: string;
|
|
41
|
+
focusRingWidth: string;
|
|
42
|
+
focusRingColor: string;
|
|
43
|
+
focusRingOpacity: string;
|
|
44
|
+
transitionDuration: string;
|
|
45
|
+
}
|
|
46
|
+
export declare const defaultTheme: Theme;
|
|
47
|
+
/**
|
|
48
|
+
* Generate CSS custom properties from theme object
|
|
49
|
+
* Prefixes all variables with --fb- to avoid conflicts
|
|
50
|
+
*/
|
|
51
|
+
export declare function generateCSSVariables(theme: Partial<Theme>): string;
|
|
52
|
+
/**
|
|
53
|
+
* Inject theme CSS variables into a container element or create a style tag
|
|
54
|
+
*/
|
|
55
|
+
export declare function injectThemeVariables(container: HTMLElement, theme: Partial<Theme>): void;
|
|
56
|
+
/**
|
|
57
|
+
* Example theme configurations for documentation
|
|
58
|
+
*/
|
|
59
|
+
export declare const exampleThemes: {
|
|
60
|
+
default: Theme;
|
|
61
|
+
dark: Theme;
|
|
62
|
+
klein: Theme;
|
|
63
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Element } from "./schema.js";
|
|
2
|
+
import type { State } from "./state.js";
|
|
3
|
+
import type { FormBuilderInstance } from "../instance/FormBuilderInstance.js";
|
|
4
|
+
/**
|
|
5
|
+
* Context passed to component validation and update functions
|
|
6
|
+
*/
|
|
7
|
+
export interface ComponentContext {
|
|
8
|
+
/** DOM element scope for queries (usually formRoot or container) */
|
|
9
|
+
scopeRoot: HTMLElement;
|
|
10
|
+
/** Form state */
|
|
11
|
+
state: State;
|
|
12
|
+
/** Form builder instance reference */
|
|
13
|
+
instance: FormBuilderInstance;
|
|
14
|
+
/** Path prefix for nested fields */
|
|
15
|
+
path: string;
|
|
16
|
+
/** Skip validation checks (for draft mode) */
|
|
17
|
+
skipValidation?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validation result from a component validator
|
|
21
|
+
*/
|
|
22
|
+
export interface ValidationResult {
|
|
23
|
+
/** Extracted data value */
|
|
24
|
+
value: any;
|
|
25
|
+
/** Validation errors encountered */
|
|
26
|
+
errors: string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Component validator function type
|
|
30
|
+
* Extracts data from DOM and validates it based on schema element rules
|
|
31
|
+
*/
|
|
32
|
+
export type ComponentValidator = (element: Element, key: string, context: ComponentContext) => ValidationResult;
|
|
33
|
+
/**
|
|
34
|
+
* Component updater function type
|
|
35
|
+
* Updates DOM with new value without full re-render
|
|
36
|
+
*/
|
|
37
|
+
export type ComponentUpdater = (element: Element, fieldPath: string, value: any, context: ComponentContext) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Component operations registry
|
|
40
|
+
* Maps element type to validator and updater functions
|
|
41
|
+
*/
|
|
42
|
+
export interface ComponentOperations {
|
|
43
|
+
validate: ComponentValidator;
|
|
44
|
+
update: ComponentUpdater;
|
|
45
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Theme } from "../styles/theme.js";
|
|
2
|
+
export interface Translations {
|
|
3
|
+
addElement: string;
|
|
4
|
+
removeElement: string;
|
|
5
|
+
uploadText: string;
|
|
6
|
+
dragDropText: string;
|
|
7
|
+
dragDropTextSingle: string;
|
|
8
|
+
clickDragText: string;
|
|
9
|
+
noFileSelected: string;
|
|
10
|
+
noFilesSelected: string;
|
|
11
|
+
downloadButton: string;
|
|
12
|
+
}
|
|
13
|
+
export type Locale = "en" | "ru";
|
|
14
|
+
export interface Config {
|
|
15
|
+
uploadFile: ((file: File) => Promise<string>) | null;
|
|
16
|
+
downloadFile: ((resourceId: string, fileName: string) => void) | null;
|
|
17
|
+
getThumbnail: ((resourceId: string) => Promise<string | null>) | null;
|
|
18
|
+
getDownloadUrl: ((resourceId: string) => string | null) | null;
|
|
19
|
+
actionHandler: ((value: string, key: string, relatedField: string | null) => void) | null;
|
|
20
|
+
onChange: ((data: {
|
|
21
|
+
valid: boolean;
|
|
22
|
+
errors: string[];
|
|
23
|
+
data: Record<string, any>;
|
|
24
|
+
}) => void) | null;
|
|
25
|
+
onFieldChange: ((fieldPath: string, value: any, formData: {
|
|
26
|
+
valid: boolean;
|
|
27
|
+
errors: string[];
|
|
28
|
+
data: Record<string, any>;
|
|
29
|
+
}) => void) | null;
|
|
30
|
+
onThumbnailError: ((error: Error, resourceId: string) => void) | null;
|
|
31
|
+
onUploadError: ((error: Error, file: File) => void) | null;
|
|
32
|
+
onDownloadError: ((error: Error, resourceId: string, fileName: string) => void) | null;
|
|
33
|
+
debounceMs: number;
|
|
34
|
+
enableFilePreview: boolean;
|
|
35
|
+
maxPreviewSize: string;
|
|
36
|
+
readonly: boolean;
|
|
37
|
+
locale: Locale;
|
|
38
|
+
translations: Record<Locale, Translations>;
|
|
39
|
+
theme: Partial<Theme>;
|
|
40
|
+
}
|
|
41
|
+
export interface ResourceMetadata {
|
|
42
|
+
name: string;
|
|
43
|
+
type: string;
|
|
44
|
+
size: number;
|
|
45
|
+
uploadedAt: Date;
|
|
46
|
+
file?: File;
|
|
47
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { SelectOption, ElementAction, BaseElement, TextElement, TextareaElement, NumberElement, SelectElement, FileElement, FilesElement, ContainerElement, GroupElement, Element, Schema, ExternalAction, FormData, RenderContext, } from "./schema.js";
|
|
2
|
+
export type { Translations, Locale, Config, ResourceMetadata, } from "./config.js";
|
|
3
|
+
export type { State } from "./state.js";
|
|
4
|
+
export type { ComponentContext, ValidationResult, ComponentValidator, ComponentUpdater, ComponentOperations, } from "./component-operations.js";
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export interface SelectOption {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ElementAction {
|
|
6
|
+
key: string;
|
|
7
|
+
label: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BaseElement {
|
|
10
|
+
type: string;
|
|
11
|
+
key: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
hint?: string;
|
|
15
|
+
required?: boolean;
|
|
16
|
+
hidden?: boolean;
|
|
17
|
+
default?: any;
|
|
18
|
+
actions?: ElementAction[];
|
|
19
|
+
}
|
|
20
|
+
export interface TextElement extends BaseElement {
|
|
21
|
+
type: "text";
|
|
22
|
+
pattern?: string;
|
|
23
|
+
minLength?: number;
|
|
24
|
+
maxLength?: number;
|
|
25
|
+
placeholder?: string;
|
|
26
|
+
multiple?: boolean;
|
|
27
|
+
minCount?: number;
|
|
28
|
+
maxCount?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface TextareaElement extends BaseElement {
|
|
31
|
+
type: "textarea";
|
|
32
|
+
rows?: number;
|
|
33
|
+
minLength?: number;
|
|
34
|
+
maxLength?: number;
|
|
35
|
+
pattern?: string;
|
|
36
|
+
placeholder?: string;
|
|
37
|
+
multiple?: boolean;
|
|
38
|
+
minCount?: number;
|
|
39
|
+
maxCount?: number;
|
|
40
|
+
}
|
|
41
|
+
export interface NumberElement extends BaseElement {
|
|
42
|
+
type: "number";
|
|
43
|
+
min?: number;
|
|
44
|
+
max?: number;
|
|
45
|
+
decimals?: number;
|
|
46
|
+
step?: number;
|
|
47
|
+
placeholder?: string;
|
|
48
|
+
multiple?: boolean;
|
|
49
|
+
minCount?: number;
|
|
50
|
+
maxCount?: number;
|
|
51
|
+
}
|
|
52
|
+
export interface SelectElement extends BaseElement {
|
|
53
|
+
type: "select";
|
|
54
|
+
options: SelectOption[];
|
|
55
|
+
placeholder?: string;
|
|
56
|
+
multiple?: boolean;
|
|
57
|
+
minCount?: number;
|
|
58
|
+
maxCount?: number;
|
|
59
|
+
}
|
|
60
|
+
export interface FileElement extends BaseElement {
|
|
61
|
+
type: "file";
|
|
62
|
+
accept?: string | {
|
|
63
|
+
extensions: string[];
|
|
64
|
+
};
|
|
65
|
+
maxSize?: number;
|
|
66
|
+
multiple?: boolean;
|
|
67
|
+
minCount?: number;
|
|
68
|
+
maxCount?: number;
|
|
69
|
+
}
|
|
70
|
+
export interface FilesElement extends BaseElement {
|
|
71
|
+
type: "files";
|
|
72
|
+
accept?: string | {
|
|
73
|
+
extensions: string[];
|
|
74
|
+
};
|
|
75
|
+
maxSize?: number;
|
|
76
|
+
minCount?: number;
|
|
77
|
+
maxCount?: number;
|
|
78
|
+
}
|
|
79
|
+
export interface ContainerElement extends BaseElement {
|
|
80
|
+
type: "container";
|
|
81
|
+
elements: Element[];
|
|
82
|
+
multiple?: boolean;
|
|
83
|
+
minCount?: number;
|
|
84
|
+
maxCount?: number;
|
|
85
|
+
}
|
|
86
|
+
export interface GroupElement extends BaseElement {
|
|
87
|
+
type: "group";
|
|
88
|
+
elements: Element[];
|
|
89
|
+
repeat?: {
|
|
90
|
+
min?: number;
|
|
91
|
+
max?: number;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export type Element = TextElement | TextareaElement | NumberElement | SelectElement | FileElement | FilesElement | ContainerElement | GroupElement;
|
|
95
|
+
export interface Schema {
|
|
96
|
+
version: string;
|
|
97
|
+
elements: Element[];
|
|
98
|
+
}
|
|
99
|
+
export interface ExternalAction {
|
|
100
|
+
key: string;
|
|
101
|
+
value: string;
|
|
102
|
+
related_field: string;
|
|
103
|
+
label?: string;
|
|
104
|
+
}
|
|
105
|
+
export interface FormData {
|
|
106
|
+
valid: boolean;
|
|
107
|
+
errors: string[];
|
|
108
|
+
data: Record<string, any>;
|
|
109
|
+
}
|
|
110
|
+
export interface RenderContext {
|
|
111
|
+
path: string;
|
|
112
|
+
prefill: Record<string, any>;
|
|
113
|
+
state: import("./state.js").State;
|
|
114
|
+
instance?: any;
|
|
115
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Schema, ExternalAction } from "./schema.js";
|
|
2
|
+
import type { Config, ResourceMetadata } from "./config.js";
|
|
3
|
+
export interface State {
|
|
4
|
+
schema: Schema | null;
|
|
5
|
+
formRoot: HTMLElement | null;
|
|
6
|
+
resourceIndex: Map<string, ResourceMetadata>;
|
|
7
|
+
externalActions: ExternalAction[] | null;
|
|
8
|
+
version: string;
|
|
9
|
+
config: Config;
|
|
10
|
+
debounceTimer: number | null;
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { State } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Apply themed input styles to an HTMLInputElement, HTMLTextAreaElement, or HTMLSelectElement
|
|
4
|
+
*/
|
|
5
|
+
export declare function applyInputStyles(element: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, state: State, className?: string): void;
|
|
6
|
+
/**
|
|
7
|
+
* Apply themed hint/description styles to a paragraph element
|
|
8
|
+
*/
|
|
9
|
+
export declare function applyHintStyles(element: HTMLParagraphElement): void;
|
|
10
|
+
/**
|
|
11
|
+
* Create a styled add button with theme support
|
|
12
|
+
*/
|
|
13
|
+
export declare function createAddButton(text: string, onClick: () => void): HTMLButtonElement;
|
|
14
|
+
/**
|
|
15
|
+
* Create a styled remove button with theme support
|
|
16
|
+
*/
|
|
17
|
+
export declare function createRemoveButton(text: string, onClick: () => void): HTMLButtonElement;
|
|
18
|
+
/**
|
|
19
|
+
* Apply themed action button styles (for external actions in readonly mode)
|
|
20
|
+
*/
|
|
21
|
+
export declare function applyActionButtonStyles(button: HTMLButtonElement, isFormLevel?: boolean): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { State } from "../types/state.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get translated string for a key
|
|
4
|
+
* @param key Translation key
|
|
5
|
+
* @param state Form state containing locale and translations
|
|
6
|
+
* @returns Translated string or key if not found
|
|
7
|
+
*/
|
|
8
|
+
export declare function t(key: string, state: State): string;
|