@nuralyui/form 0.1.0 → 0.1.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/controllers/submission.controller.d.ts +0 -0
- package/controllers/submission.controller.d.ts.map +0 -0
- package/controllers/submission.controller.js +0 -0
- package/controllers/submission.controller.js.map +0 -0
- package/controllers/validation.controller.d.ts +1 -1
- package/controllers/validation.controller.d.ts.map +1 -1
- package/controllers/validation.controller.js +0 -0
- package/controllers/validation.controller.js.map +1 -1
- package/form.component.d.ts +1 -1
- package/form.component.js +1 -1
- package/form.component.js.map +1 -0
- package/form.style.d.ts +0 -0
- package/form.style.js +0 -0
- package/form.style.js.map +1 -0
- package/form.types.d.ts +1 -1
- package/form.types.js +0 -0
- package/form.types.js.map +1 -0
- package/index.d.ts +0 -0
- package/index.js +0 -0
- package/index.js.map +1 -0
- package/interfaces/validation.interface.d.ts +0 -0
- package/interfaces/validation.interface.d.ts.map +0 -0
- package/interfaces/validation.interface.js +0 -0
- package/interfaces/validation.interface.js.map +0 -0
- package/package.json +6 -1
- package/mixins/form-field-integration.mixin.d.ts +0 -22
- package/mixins/form-field-integration.mixin.d.ts.map +0 -1
- package/mixins/form-field-integration.mixin.js +0 -78
- package/mixins/form-field-integration.mixin.js.map +0 -1
- package/mixins/form-field-validation.mixin.d.ts +0 -35
- package/mixins/form-field-validation.mixin.d.ts.map +0 -1
- package/mixins/form-field-validation.mixin.js +0 -300
- package/mixins/form-field-validation.mixin.js.map +0 -1
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
import { FormField, FormValidationResult, FormValidationState } from '../form.types.js';
|
|
7
|
-
import { ValidatableComponent } from '
|
|
7
|
+
import { ValidatableComponent } from '@nuralyui/common/mixins';
|
|
8
8
|
/**
|
|
9
9
|
* Controller that coordinates validation across all form fields
|
|
10
10
|
* This does NOT perform validation - it coordinates existing component validations
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.controller.d.ts","sourceRoot":"","sources":["../../../../src/components/form/controllers/validation.controller.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACH,SAAS,EACT,oBAAoB,EACpB,mBAAmB,EAEtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"validation.controller.d.ts","sourceRoot":"","sources":["../../../../src/components/form/controllers/validation.controller.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACH,SAAS,EACT,oBAAoB,EACpB,mBAAmB,EAEtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;;GAGG;AACH,qBAAa,wBAAwB;IAKvB,OAAO,CAAC,IAAI;IAJxB,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,eAAe,CAAqD;IAC5E,OAAO,CAAC,iBAAiB,CAA8C;gBAEnD,IAAI,EAAE,GAAG;IAE7B;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,oBAAoB,GAAG,IAAI;IAoBhE;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQnC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAgBjC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAY7B;;OAEG;IACH,YAAY,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAa7C;;OAEG;YACW,iBAAiB;IAoC/B;;OAEG;IACH,kBAAkB,IAAI,mBAAmB;IAIzC;;OAEG;IACH,SAAS,IAAI,SAAS,EAAE;IAIxB;;OAEG;IACH,gBAAgB,IAAI,SAAS,EAAE;IAI/B;;OAEG;IACH,OAAO,IAAI,OAAO;IAKlB;;OAEG;IACH,sBAAsB,IAAI,OAAO;IASjC;;OAEG;IACH,KAAK,IAAI,IAAI;IAsBb;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAM/B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAG3B"}
|
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.controller.js","sourceRoot":"","sources":["../../../../src/components/form/controllers/validation.controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport {\n FormField,\n FormValidationResult,\n FormValidationState,\n FORM_EVENTS\n} from '../form.types.js';\nimport { ValidatableComponent } from '../../../shared/validation.types.js';\n\n/**\n * Controller that coordinates validation across all form fields\n * This does NOT perform validation - it coordinates existing component validations\n */\nexport class FormValidationController {\n private fields: Map<string, FormField> = new Map();\n private validationState: FormValidationState = FormValidationState.Pristine;\n private validationPromise: Promise<FormValidationResult> | null = null;\n\n constructor(private host: any) {}\n\n /**\n * Register a form field for validation coordination\n */\n registerField(element: HTMLElement & ValidatableComponent): void {\n const name = element.name || element.getAttribute('name') || `field-${Date.now()}`;\n \n const field: FormField = {\n element,\n name,\n value: element.value,\n isValid: element.getValidationStatus().isValid,\n validationMessage: element.validationMessage || '',\n required: element.required ?? false,\n touched: false,\n dirty: false\n };\n\n this.fields.set(name, field);\n\n // Listen for field changes\n this.addFieldListeners(element, name);\n }\n\n /**\n * Unregister a form field\n */\n unregisterField(name: string): void {\n const field = this.fields.get(name);\n if (field) {\n this.removeFieldListeners(field.element);\n this.fields.delete(name);\n }\n }\n\n /**\n * Add event listeners to a form field\n */\n private addFieldListeners(element: HTMLElement, fieldName: string): void {\n element.addEventListener('nr-validation', (event) => this.handleFieldValidation(fieldName, event as CustomEvent));\n }\n\n /**\n * Remove event listeners from a form field\n */\n private removeFieldListeners(_element: HTMLElement): void {\n // Remove all event listeners (implementation depends on your needs)\n // You might want to store listener references for proper cleanup\n }\n\n\n /**\n * Handle field validation event\n */\n private handleFieldValidation(fieldName: string, event?: CustomEvent): void {\n const field = this.fields.get(fieldName);\n if (!field) return;\n\n if (event && event.detail) {\n // Use the detailed validation information from the nr-validation event\n field.isValid = event.detail.isValid || false;\n field.validationMessage = event.detail.validationMessage || '';\n } else {\n // Fallback to ValidatableComponent validation\n const status = field.element.getValidationStatus();\n field.isValid = status.isValid;\n field.validationMessage = field.element.validationMessage || '';\n }\n\n // Update form validation state based on all fields\n this.updateFormValidationState();\n }\n\n /**\n * Update form validation state based on current field states\n */\n private updateFormValidationState(): void {\n const invalidFields = this.getInvalidFields();\n const isFormValid = invalidFields.length === 0;\n \n this.validationState = isFormValid ? FormValidationState.Valid : FormValidationState.Invalid;\n \n const result: FormValidationResult = {\n isValid: isFormValid,\n invalidFields,\n validationErrors: this.buildValidationErrors(),\n summary: isFormValid ? 'Form is valid' : `${invalidFields.length} field(s) have errors`\n };\n \n this.dispatchValidationEvent(result);\n }\n\n /**\n * Build validation errors object from current field states\n */\n private buildValidationErrors(): Record<string, string> {\n const errors: Record<string, string> = {};\n for (const [name, field] of this.fields) {\n if (!field.isValid && field.validationMessage) {\n errors[name] = field.validationMessage;\n }\n }\n return errors;\n }\n\n \n\n /**\n * Validate all form fields (coordinates existing validations)\n */\n validateForm(): Promise<FormValidationResult> {\n // Return existing promise if validation is in progress\n if (this.validationPromise) {\n return this.validationPromise;\n }\n\n this.validationState = FormValidationState.Pending;\n\n this.validationPromise = this.performValidation();\n \n return this.validationPromise;\n }\n\n /**\n * Perform the actual validation coordination\n */\n private async performValidation(): Promise<FormValidationResult> {\n const invalidFields: FormField[] = [];\n const validationErrors: Record<string, string> = {};\n\n // Check each field's validation state\n for (const [name, field] of this.fields) {\n // Trigger validation on the field component itself\n const status = field.element.getValidationStatus();\n const isValid = status.isValid;\n \n field.isValid = isValid;\n field.validationMessage = field.element.validationMessage || '';\n\n if (!isValid) {\n invalidFields.push(field);\n validationErrors[name] = field.validationMessage;\n }\n }\n\n const isFormValid = invalidFields.length === 0;\n this.validationState = isFormValid ? FormValidationState.Valid : FormValidationState.Invalid;\n\n const result: FormValidationResult = {\n isValid: isFormValid,\n invalidFields,\n validationErrors,\n summary: isFormValid ? 'Form is valid' : `${invalidFields.length} field(s) have errors`\n };\n\n this.dispatchValidationEvent(result);\n\n this.validationPromise = null;\n\n return result;\n }\n\n /**\n * Get current validation state\n */\n getValidationState(): FormValidationState {\n return this.validationState;\n }\n\n /**\n * Get all registered fields\n */\n getFields(): FormField[] {\n return Array.from(this.fields.values());\n }\n\n /**\n * Get invalid fields\n */\n getInvalidFields(): FormField[] {\n return Array.from(this.fields.values()).filter(field => !field.isValid);\n }\n\n /**\n * Check if form is valid\n */\n isValid(): boolean {\n return this.validationState === FormValidationState.Valid && \n Array.from(this.fields.values()).every(field => field.isValid);\n }\n\n /**\n * Focus first invalid field\n */\n focusFirstInvalidField(): boolean {\n const invalidField = Array.from(this.fields.values()).find(field => !field.isValid);\n if (invalidField && typeof invalidField.element.focus === 'function') {\n invalidField.element.focus();\n return true;\n }\n return false;\n }\n\n /**\n * Reset all fields\n */\n reset(): void {\n for (const field of this.fields.values()) {\n // Reset using ValidatableComponent interface if available\n if ('clearValidation' in field.element && typeof field.element.clearValidation === 'function') {\n field.element.clearValidation();\n }\n // Reset value if component supports it\n if ('value' in field.element) {\n field.element.value = '';\n }\n field.touched = false;\n field.dirty = false;\n field.isValid = true;\n field.validationMessage = '';\n }\n \n this.validationState = FormValidationState.Pristine;\n this.dispatchResetEvent();\n }\n\n \n\n /**\n * Dispatch validation event\n */\n private dispatchValidationEvent(result: FormValidationResult): void {\n (this.host as any).dispatchCustomEvent?.(FORM_EVENTS.VALIDATION_CHANGED, {\n validationResult: result\n });\n }\n\n /**\n * Dispatch reset event\n */\n private dispatchResetEvent(): void {\n (this.host as any).dispatchCustomEvent?.(FORM_EVENTS.RESET, {});\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validation.controller.js","sourceRoot":"","sources":["../../../../src/components/form/controllers/validation.controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport {\n FormField,\n FormValidationResult,\n FormValidationState,\n FORM_EVENTS\n} from '../form.types.js';\nimport { ValidatableComponent } from '@nuralyui/common/mixins';\n\n/**\n * Controller that coordinates validation across all form fields\n * This does NOT perform validation - it coordinates existing component validations\n */\nexport class FormValidationController {\n private fields: Map<string, FormField> = new Map();\n private validationState: FormValidationState = FormValidationState.Pristine;\n private validationPromise: Promise<FormValidationResult> | null = null;\n\n constructor(private host: any) {}\n\n /**\n * Register a form field for validation coordination\n */\n registerField(element: HTMLElement & ValidatableComponent): void {\n const name = element.name || element.getAttribute('name') || `field-${Date.now()}`;\n \n const field: FormField = {\n element,\n name,\n value: element.value,\n isValid: element.getValidationStatus().isValid,\n validationMessage: element.validationMessage || '',\n required: element.required ?? false,\n touched: false,\n dirty: false\n };\n\n this.fields.set(name, field);\n\n // Listen for field changes\n this.addFieldListeners(element, name);\n }\n\n /**\n * Unregister a form field\n */\n unregisterField(name: string): void {\n const field = this.fields.get(name);\n if (field) {\n this.removeFieldListeners(field.element);\n this.fields.delete(name);\n }\n }\n\n /**\n * Add event listeners to a form field\n */\n private addFieldListeners(element: HTMLElement, fieldName: string): void {\n element.addEventListener('nr-validation', (event) => this.handleFieldValidation(fieldName, event as CustomEvent));\n }\n\n /**\n * Remove event listeners from a form field\n */\n private removeFieldListeners(_element: HTMLElement): void {\n // Remove all event listeners (implementation depends on your needs)\n // You might want to store listener references for proper cleanup\n }\n\n\n /**\n * Handle field validation event\n */\n private handleFieldValidation(fieldName: string, event?: CustomEvent): void {\n const field = this.fields.get(fieldName);\n if (!field) return;\n\n if (event && event.detail) {\n // Use the detailed validation information from the nr-validation event\n field.isValid = event.detail.isValid || false;\n field.validationMessage = event.detail.validationMessage || '';\n } else {\n // Fallback to ValidatableComponent validation\n const status = field.element.getValidationStatus();\n field.isValid = status.isValid;\n field.validationMessage = field.element.validationMessage || '';\n }\n\n // Update form validation state based on all fields\n this.updateFormValidationState();\n }\n\n /**\n * Update form validation state based on current field states\n */\n private updateFormValidationState(): void {\n const invalidFields = this.getInvalidFields();\n const isFormValid = invalidFields.length === 0;\n \n this.validationState = isFormValid ? FormValidationState.Valid : FormValidationState.Invalid;\n \n const result: FormValidationResult = {\n isValid: isFormValid,\n invalidFields,\n validationErrors: this.buildValidationErrors(),\n summary: isFormValid ? 'Form is valid' : `${invalidFields.length} field(s) have errors`\n };\n \n this.dispatchValidationEvent(result);\n }\n\n /**\n * Build validation errors object from current field states\n */\n private buildValidationErrors(): Record<string, string> {\n const errors: Record<string, string> = {};\n for (const [name, field] of this.fields) {\n if (!field.isValid && field.validationMessage) {\n errors[name] = field.validationMessage;\n }\n }\n return errors;\n }\n\n \n\n /**\n * Validate all form fields (coordinates existing validations)\n */\n validateForm(): Promise<FormValidationResult> {\n // Return existing promise if validation is in progress\n if (this.validationPromise) {\n return this.validationPromise;\n }\n\n this.validationState = FormValidationState.Pending;\n\n this.validationPromise = this.performValidation();\n \n return this.validationPromise;\n }\n\n /**\n * Perform the actual validation coordination\n */\n private async performValidation(): Promise<FormValidationResult> {\n const invalidFields: FormField[] = [];\n const validationErrors: Record<string, string> = {};\n\n // Check each field's validation state\n for (const [name, field] of this.fields) {\n // Trigger validation on the field component itself\n const status = field.element.getValidationStatus();\n const isValid = status.isValid;\n \n field.isValid = isValid;\n field.validationMessage = field.element.validationMessage || '';\n\n if (!isValid) {\n invalidFields.push(field);\n validationErrors[name] = field.validationMessage;\n }\n }\n\n const isFormValid = invalidFields.length === 0;\n this.validationState = isFormValid ? FormValidationState.Valid : FormValidationState.Invalid;\n\n const result: FormValidationResult = {\n isValid: isFormValid,\n invalidFields,\n validationErrors,\n summary: isFormValid ? 'Form is valid' : `${invalidFields.length} field(s) have errors`\n };\n\n this.dispatchValidationEvent(result);\n\n this.validationPromise = null;\n\n return result;\n }\n\n /**\n * Get current validation state\n */\n getValidationState(): FormValidationState {\n return this.validationState;\n }\n\n /**\n * Get all registered fields\n */\n getFields(): FormField[] {\n return Array.from(this.fields.values());\n }\n\n /**\n * Get invalid fields\n */\n getInvalidFields(): FormField[] {\n return Array.from(this.fields.values()).filter(field => !field.isValid);\n }\n\n /**\n * Check if form is valid\n */\n isValid(): boolean {\n return this.validationState === FormValidationState.Valid && \n Array.from(this.fields.values()).every(field => field.isValid);\n }\n\n /**\n * Focus first invalid field\n */\n focusFirstInvalidField(): boolean {\n const invalidField = Array.from(this.fields.values()).find(field => !field.isValid);\n if (invalidField && typeof invalidField.element.focus === 'function') {\n invalidField.element.focus();\n return true;\n }\n return false;\n }\n\n /**\n * Reset all fields\n */\n reset(): void {\n for (const field of this.fields.values()) {\n // Reset using ValidatableComponent interface if available\n if ('clearValidation' in field.element && typeof field.element.clearValidation === 'function') {\n field.element.clearValidation();\n }\n // Reset value if component supports it\n if ('value' in field.element) {\n field.element.value = '';\n }\n field.touched = false;\n field.dirty = false;\n field.isValid = true;\n field.validationMessage = '';\n }\n \n this.validationState = FormValidationState.Pristine;\n this.dispatchResetEvent();\n }\n\n \n\n /**\n * Dispatch validation event\n */\n private dispatchValidationEvent(result: FormValidationResult): void {\n (this.host as any).dispatchCustomEvent?.(FORM_EVENTS.VALIDATION_CHANGED, {\n validationResult: result\n });\n }\n\n /**\n * Dispatch reset event\n */\n private dispatchResetEvent(): void {\n (this.host as any).dispatchCustomEvent?.(FORM_EVENTS.RESET, {});\n }\n}\n"]}
|
package/form.component.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { LitElement, PropertyValues } from 'lit';
|
|
7
7
|
import { FormConfig, FormValidationState, FormSubmissionState } from './form.types.js';
|
|
8
|
-
declare const NrFormElement_base: (new (...args: any[]) => import("
|
|
8
|
+
declare const NrFormElement_base: (new (...args: any[]) => import("@nuralyui/common/mixins").DependencyAware) & (new (...args: any[]) => import("@nuralyui/common/mixins").ThemeAware) & (new (...args: any[]) => import("@nuralyui/common/mixins").EventHandlerCapable) & typeof LitElement;
|
|
9
9
|
/**
|
|
10
10
|
* Comprehensive form component with field management and validation API
|
|
11
11
|
*
|
package/form.component.js
CHANGED
|
@@ -22,7 +22,7 @@ import { LitElement, html } from 'lit';
|
|
|
22
22
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
23
23
|
import { styles } from './form.style.js';
|
|
24
24
|
import { FormValidationState, FormSubmissionState, FORM_EVENTS } from './form.types.js';
|
|
25
|
-
import { NuralyUIBaseMixin } from '
|
|
25
|
+
import { NuralyUIBaseMixin } from '@nuralyui/common/mixins';
|
|
26
26
|
import { FormValidationController } from './controllers/validation.controller.js';
|
|
27
27
|
import { FormSubmissionController } from './controllers/submission.controller.js';
|
|
28
28
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.component.js","sourceRoot":"","sources":["../../../src/components/form/form.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { LitElement, html, PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { styles } from './form.style.js';\nimport {\n FormConfig,\n FormValidationState,\n FormSubmissionState,\n FormEventDetail,\n FORM_EVENTS\n} from './form.types.js';\nimport { NuralyUIBaseMixin } from '@nuralyui/common/mixins';\nimport { FormValidationController } from './controllers/validation.controller.js';\nimport { FormSubmissionController } from './controllers/submission.controller.js';\n\n/**\n * Comprehensive form component with field management and validation API\n * \n * Key Features:\n * - Coordinates validation across all form fields (does NOT validate itself)\n * - Handles form submission with built-in validation checks\n * - Provides form state management and events\n * - Integrates with existing component validation controllers\n * - Supports both programmatic and user-driven interactions\n * - Comprehensive API for field manipulation and validation\n * \n * @example Basic Usage\n * ```html\n * <nr-form @nr-form-submit-success=\"${handleSuccess}\" validate-on-change>\n * <nr-input name=\"username\" required></nr-input>\n * <nr-input name=\"email\" type=\"email\" required></nr-input>\n * <nr-button type=\"submit\">Submit</nr-button>\n * </nr-form>\n * ```\n * \n * @example Programmatic Usage\n * ```typescript\n * const form = document.querySelector('nr-form');\n * \n * // Set field values\n * form.setFieldsValue({ username: 'john', email: 'john@example.com' });\n * \n * // Get field values\n * const values = form.getFieldsValue();\n * \n * // Validate and submit\n * try {\n * const values = await form.finish();\n * console.log('Form submitted:', values);\n * } catch (errors) {\n * console.log('Validation failed:', errors);\n * }\n * \n * // Reset specific fields\n * form.resetFields(['username']);\n * ```\n * \n * @fires nr-form-validation-changed - Validation state changes\n * @fires nr-form-field-changed - Individual field changes\n * @fires nr-form-submit-attempt - Form submission attempted\n * @fires nr-form-submit-success - Form submitted successfully\n * @fires nr-form-submit-error - Form submission failed\n * @fires nr-form-reset - Form was reset\n * \n * @slot default - Form content (inputs, buttons, etc.)\n */\n@customElement('nr-form')\nexport class NrFormElement extends NuralyUIBaseMixin(LitElement) {\n static override styles = styles;\n\n /** Form configuration */\n @property({ type: Object })\n config: FormConfig = {\n validateOnChange: false, // Default to false - only validate on blur\n validateOnBlur: true,\n showErrorsImmediately: false,\n preventInvalidSubmission: true,\n resetOnSuccess: false,\n validationDelay: 300\n };\n\n /** Enable real-time validation on field changes */\n @property({ type: Boolean, attribute: 'validate-on-change' })\n validateOnChange = false; // Default to false\n\n /** Enable validation on field blur */\n @property({ type: Boolean, attribute: 'validate-on-blur' })\n validateOnBlur = true;\n\n /** Prevent form submission if validation fails */\n @property({ type: Boolean, attribute: 'prevent-invalid-submission' })\n preventInvalidSubmission = true;\n\n /** Reset form after successful submission */\n @property({ type: Boolean, attribute: 'reset-on-success' })\n resetOnSuccess = false;\n\n /** Form action URL for native submission */\n @property({ type: String })\n action?: string;\n\n /** Form method for native submission */\n @property({ type: String })\n method: 'GET' | 'POST' = 'POST';\n\n /** Form encoding type */\n @property({ type: String, attribute: 'enctype' })\n enctype: string = 'multipart/form-data';\n\n /** Target for form submission */\n @property({ type: String })\n target?: string;\n\n /** Disable the entire form */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /** Form validation state */\n @state()\n private _validationState: FormValidationState = FormValidationState.Pristine;\n\n /** Form submission state */\n @state()\n private _submissionState: FormSubmissionState = FormSubmissionState.Idle;\n\n /** Validation controller */\n private validationController = new FormValidationController(this);\n\n /** Submission controller */\n private submissionController = new FormSubmissionController(this);\n\n /** Get current validation state */\n get validationState(): FormValidationState {\n return this._validationState;\n }\n\n /** Get current submission state */\n get submissionState(): FormSubmissionState {\n return this._submissionState;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.setupFormObserver();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.cleanupFormObserver();\n }\n\n override willUpdate(changedProperties: PropertyValues): void {\n super.willUpdate(changedProperties);\n \n // Update config when properties change\n if (changedProperties.has('validateOnChange') || \n changedProperties.has('validateOnBlur') ||\n changedProperties.has('preventInvalidSubmission') ||\n changedProperties.has('resetOnSuccess')) {\n this.config = {\n ...this.config,\n validateOnChange: this.validateOnChange,\n validateOnBlur: this.validateOnBlur,\n preventInvalidSubmission: this.preventInvalidSubmission,\n resetOnSuccess: this.resetOnSuccess\n };\n }\n }\n\n override firstUpdated(): void {\n this.registerExistingFields();\n this.setupFormEvents();\n }\n\n /**\n * Setup mutation observer to detect new form fields\n */\n private setupFormObserver(): void {\n // Implementation for observing DOM changes to register new fields\n const observer = new MutationObserver((mutations) => {\n mutations.forEach(mutation => {\n mutation.addedNodes.forEach(node => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n this.registerFieldsInElement(node as Element);\n }\n });\n });\n });\n\n observer.observe(this, { \n childList: true, \n subtree: true \n });\n\n (this as any)._formObserver = observer;\n }\n\n /**\n * Cleanup mutation observer\n */\n private cleanupFormObserver(): void {\n const observer = (this as any)._formObserver;\n if (observer) {\n observer.disconnect();\n }\n }\n\n /**\n * Register existing form fields\n */\n private registerExistingFields(): void {\n this.registerFieldsInElement(this);\n }\n\n /**\n * Register form fields in an element\n */\n private registerFieldsInElement(element: Element): void {\n const selectors = [\n 'nr-input', 'nr-select', 'nr-radio', 'nr-checkbox', \n 'nr-textarea', 'nr-timepicker', 'nr-datepicker'\n ];\n\n selectors.forEach(selector => {\n const fields = element.querySelectorAll(selector);\n fields.forEach(field => {\n if (field.getAttribute('name')) {\n this.validationController.registerField(field as any);\n }\n });\n });\n }\n\n /**\n * Setup form events\n */\n private setupFormEvents(): void {\n // Listen for form submission\n this.addEventListener('submit', this.handleFormSubmit);\n \n // Listen for form reset\n this.addEventListener('reset', this.handleFormReset);\n\n // Listen for validation events\n this.addEventListener(FORM_EVENTS.VALIDATION_CHANGED, this.handleValidationChanged as EventListener);\n }\n\n /**\n * Handle form submission\n */\n private async handleFormSubmit(event: Event): Promise<void> {\n event.preventDefault();\n\n if (this.disabled) {\n return;\n }\n\n try {\n const submissionData = await this.submissionController.submitForm();\n \n if (this.resetOnSuccess) {\n this.reset();\n }\n\n // If action is specified, perform native submission\n if (this.action) {\n this.performNativeSubmission(submissionData.formData);\n }\n\n } catch (error) {\n console.error('Form submission failed:', error);\n // Error events are already dispatched by submission controller\n }\n }\n\n /**\n * Handle form reset\n */\n private handleFormReset(event: Event): void {\n event.preventDefault();\n this.reset();\n }\n\n /**\n * Handle validation state changes\n */\n private handleValidationChanged = (event: Event): void => {\n const customEvent = event as CustomEvent<FormEventDetail>;\n const result = customEvent.detail.validationResult;\n if (result) {\n this._validationState = result.isValid ? \n FormValidationState.Valid : \n FormValidationState.Invalid;\n }\n };\n\n /**\n * Perform native form submission\n */\n private performNativeSubmission(formData: FormData): void {\n const form = document.createElement('form');\n form.action = this.action!;\n form.method = this.method;\n form.enctype = this.enctype;\n if (this.target) form.target = this.target;\n\n // Add form data as hidden inputs\n for (const [name, value] of formData.entries()) {\n const input = document.createElement('input');\n input.type = 'hidden';\n input.name = name;\n input.value = value as string;\n form.appendChild(input);\n }\n\n document.body.appendChild(form);\n form.submit();\n document.body.removeChild(form);\n }\n\n /**\n * Validate the form\n */\n async validate(): Promise<boolean> {\n const result = await this.validationController.validateForm();\n return result.isValid;\n }\n\n /**\n * Submit the form programmatically\n */\n async submit(customData?: Record<string, any>): Promise<void> {\n await this.submissionController.submitForm(customData);\n }\n\n /**\n * Reset the form\n */\n reset(): void {\n this.validationController.reset();\n this.submissionController.resetSubmission();\n this._validationState = FormValidationState.Pristine;\n this._submissionState = FormSubmissionState.Idle;\n }\n\n /**\n * Check if form is valid\n */\n get isValid(): boolean {\n return this.validationController.isValid();\n }\n\n /**\n * Check if form is submitting\n */\n get isSubmitting(): boolean {\n return this.submissionController.isSubmitting();\n }\n\n /**\n * Get form data\n */\n getFormData() {\n return this.submissionController.collectFormData();\n }\n\n /**\n * Get invalid fields\n */\n getInvalidFields() {\n return this.validationController.getInvalidFields();\n }\n\n // ============================================\n // FORM API METHODS\n // ============================================\n\n /**\n * Get values of all fields\n * @returns Object containing all field values\n */\n getFieldsValue(nameList?: string[]): Record<string, any> {\n const formData = this.getFormData();\n const values = formData.jsonData;\n \n if (nameList && nameList.length > 0) {\n const filteredValues: Record<string, any> = {};\n nameList.forEach(name => {\n if (name in values) {\n filteredValues[name] = values[name];\n }\n });\n return filteredValues;\n }\n \n return values;\n }\n\n /**\n * Get value of specific field\n * @param name Field name\n * @returns Field value\n */\n getFieldValue(name: string): any {\n const values = this.getFieldsValue();\n return values[name];\n }\n\n /**\n * Set values of fields\n * @param values Object containing field values to set\n */\n setFieldsValue(values: Record<string, any>): void {\n Object.entries(values).forEach(([name, value]) => {\n this.setFieldValue(name, value);\n });\n }\n\n /**\n * Set value of specific field\n * @param name Field name\n * @param value Field value\n */\n setFieldValue(name: string, value: any): void {\n const fields = this.validationController.getFields();\n const field = fields.find(f => f.name === name);\n \n if (field && field.element) {\n field.element.value = value;\n field.value = value;\n // Trigger change event to update validation\n field.element.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }\n\n /**\n * Validate specific fields\n * @param nameList Array of field names to validate, if empty validates all\n * @returns Promise with validation result\n */\n async validateFields(nameList?: string[]): Promise<Record<string, any>> {\n const result = await this.validationController.validateForm();\n \n if (nameList && nameList.length > 0) {\n // Filter validation errors for specific fields\n const filteredErrors: Record<string, string> = {};\n nameList.forEach(name => {\n if (result.validationErrors[name]) {\n filteredErrors[name] = result.validationErrors[name];\n }\n });\n \n if (Object.keys(filteredErrors).length > 0) {\n throw new Error(JSON.stringify(filteredErrors));\n }\n \n return this.getFieldsValue(nameList);\n }\n \n if (!result.isValid) {\n throw new Error(JSON.stringify(result.validationErrors));\n }\n \n return this.getFieldsValue();\n }\n\n /**\n * Reset specific fields\n * @param nameList Array of field names to reset, if empty resets all\n */\n resetFields(nameList?: string[]): void {\n if (!nameList || nameList.length === 0) {\n this.reset();\n return;\n }\n \n const fields = this.validationController.getFields();\n nameList.forEach(name => {\n const field = fields.find(f => f.name === name);\n if (field && field.element) {\n // Reset value\n field.element.value = '';\n field.value = '';\n field.touched = false;\n field.dirty = false;\n field.isValid = true;\n field.validationMessage = '';\n \n // Trigger change event\n field.element.dispatchEvent(new Event('change', { bubbles: true }));\n }\n });\n }\n\n /**\n * Get field error\n * @param name Field name\n * @returns Field error message or null\n */\n getFieldError(name: string): string | null {\n const fields = this.validationController.getFields();\n const field = fields.find(f => f.name === name);\n return field && !field.isValid ? field.validationMessage : null;\n }\n\n /**\n * Get all field errors\n * @param nameList Array of field names, if empty returns all\n * @returns Object containing field errors\n */\n getFieldsError(nameList?: string[]): Record<string, string | null> {\n const fields = this.validationController.getFields();\n const errors: Record<string, string | null> = {};\n \n const targetFields = nameList \n ? fields.filter(f => nameList.includes(f.name))\n : fields;\n \n targetFields.forEach(field => {\n errors[field.name] = field.isValid ? null : field.validationMessage;\n });\n \n return errors;\n }\n\n /**\n * Check if field has been touched\n * @param name Field name\n * @returns Whether field has been touched\n */\n isFieldTouched(name: string): boolean {\n const fields = this.validationController.getFields();\n const field = fields.find(f => f.name === name);\n return field ? field.touched : false;\n }\n\n /**\n * Check if any fields have been touched\n * @param nameList Array of field names, if empty checks all\n * @returns Whether any of the specified fields have been touched\n */\n isFieldsTouched(nameList?: string[]): boolean {\n const fields = this.validationController.getFields();\n const targetFields = nameList \n ? fields.filter(f => nameList.includes(f.name))\n : fields;\n \n return targetFields.some(field => field.touched);\n }\n\n /**\n * Check if field value has been modified\n * @param name Field name\n * @returns Whether field has been modified\n */\n isFieldDirty(name: string): boolean {\n const fields = this.validationController.getFields();\n const field = fields.find(f => f.name === name);\n return field ? field.dirty : false;\n }\n\n /**\n * Check if any fields have been modified\n * @param nameList Array of field names, if empty checks all\n * @returns Whether any of the specified fields have been modified\n */\n isFieldsDirty(nameList?: string[]): boolean {\n const fields = this.validationController.getFields();\n const targetFields = nameList \n ? fields.filter(f => nameList.includes(f.name))\n : fields;\n \n return targetFields.some(field => field.dirty);\n }\n\n /**\n * Get field instance\n * @param name Field name\n * @returns Field element or null\n */\n getFieldInstance(name: string): HTMLElement | null {\n const fields = this.validationController.getFields();\n const field = fields.find(f => f.name === name);\n return field ? field.element : null;\n }\n\n /**\n * Scroll to first error field\n * @returns Whether scrolled to a field\n */\n scrollToField(name?: string): boolean {\n if (name) {\n const fieldElement = this.getFieldInstance(name);\n if (fieldElement) {\n fieldElement.scrollIntoView({ behavior: 'smooth', block: 'center' });\n if (typeof fieldElement.focus === 'function') {\n fieldElement.focus();\n }\n return true;\n }\n return false;\n }\n \n // Scroll to first invalid field\n return this.validationController.focusFirstInvalidField();\n }\n\n /**\n * Submit form and validate\n * @returns Promise with form values\n */\n async finish(): Promise<Record<string, any>> {\n try {\n const values = await this.validateFields();\n await this.submit();\n return values;\n } catch (error) {\n this.scrollToField();\n throw error;\n }\n }\n\n /**\n * Get field names that have validation errors\n * @returns Array of field names with errors\n */\n getFieldsWithErrors(): string[] {\n const fields = this.validationController.getFields();\n return fields\n .filter(field => !field.isValid)\n .map(field => field.name);\n }\n\n /**\n * Check if form has any validation errors\n * @returns Whether form has errors\n */\n hasErrors(): boolean {\n return this.getFieldsWithErrors().length > 0;\n }\n\n /**\n * Get summary of form state\n * @returns Object with form state information\n */\n getFormState(): {\n isValid: boolean;\n isSubmitting: boolean;\n hasErrors: boolean;\n errorCount: number;\n fieldCount: number;\n touchedFields: string[];\n dirtyFields: string[];\n invalidFields: string[];\n } {\n const fields = this.validationController.getFields();\n \n return {\n isValid: this.isValid,\n isSubmitting: this.isSubmitting,\n hasErrors: this.hasErrors(),\n errorCount: this.getFieldsWithErrors().length,\n fieldCount: fields.length,\n touchedFields: fields.filter(f => f.touched).map(f => f.name),\n dirtyFields: fields.filter(f => f.dirty).map(f => f.name),\n invalidFields: this.getFieldsWithErrors()\n };\n }\n\n /**\n * Set form loading state (useful for async operations)\n * @param loading Whether form is in loading state\n */\n setLoading(loading: boolean): void {\n this.disabled = loading;\n this.requestUpdate();\n }\n\n override render() {\n return html`\n <form \n action=\"${this.action || ''}\"\n method=\"${this.method.toLowerCase() as 'get' | 'post'}\"\n enctype=\"${this.enctype as 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/plain'}\"\n target=\"${this.target || ''}\"\n class=\"form-wrapper\"\n data-disabled=\"${this.disabled}\"\n novalidate\n >\n <slot></slot>\n </form>\n `;\n }\n}\n"]}
|
package/form.style.d.ts
CHANGED
|
File without changes
|
package/form.style.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.style.js","sourceRoot":"","sources":["../../../src/components/form/form.style.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DxB,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { css } from 'lit';\n\nexport const styles = css`\n :host {\n display: block;\n width: 100%;\n }\n\n :host([disabled]) {\n opacity: 0.6;\n pointer-events: none;\n }\n\n .form-wrapper {\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: var(--nuraly-form-gap, 16px);\n }\n\n .form-wrapper[disabled] {\n opacity: 0.6;\n pointer-events: none;\n }\n\n /* Form validation states */\n :host([data-validation-state=\"pristine\"]) {\n border-left: 3px solid transparent;\n }\n\n :host([data-validation-state=\"valid\"]) {\n border-left: 3px solid #52c41a;\n }\n\n :host([data-validation-state=\"invalid\"]) {\n border-left: 3px solid #ff4d4f;\n }\n\n :host([data-validation-state=\"pending\"]) {\n border-left: 3px solid #1890ff;\n }\n\n /* Form submission states */\n :host([data-submission-state=\"submitting\"]) {\n opacity: 0.8;\n pointer-events: none;\n }\n\n :host([data-submission-state=\"success\"]) {\n border-left: 3px solid #52c41a;\n }\n\n :host([data-submission-state=\"error\"]) {\n border-left: 3px solid #ff4d4f;\n }\n\n /* Responsive design */\n @media (max-width: 768px) {\n .form-wrapper {\n gap: var(--nuraly-form-gap-mobile, 12px);\n }\n }\n`;\n"]}
|
package/form.types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
|
-
import { ValidatableComponent, FormFieldInfo } from '
|
|
6
|
+
import { ValidatableComponent, FormFieldInfo } from '@nuralyui/common/mixins';
|
|
7
7
|
/**
|
|
8
8
|
* Form validation states that can be applied to the form and its children
|
|
9
9
|
*/
|
package/form.types.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.types.js","sourceRoot":"","sources":["../../../src/components/form/form.types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,MAAM,CAAN,IAAY,mBAMX;AAND,WAAY,mBAAmB;IAC7B,4CAAqB,CAAA;IACrB,0CAAmB,CAAA;IACnB,sCAAe,CAAA;IACf,0CAAmB,CAAA;IACnB,8CAAuB,CAAA,CAAG,0BAA0B;AACtD,CAAC,EANW,mBAAmB,KAAnB,mBAAmB,QAM9B;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,mBAKX;AALD,WAAY,mBAAmB;IAC7B,oCAAa,CAAA;IACb,gDAAyB,CAAA;IACzB,0CAAmB,CAAA;IACnB,sCAAe,CAAA;AACjB,CAAC,EALW,mBAAmB,KAAnB,mBAAmB,QAK9B;AAgED;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,kBAAkB,EAAE,4BAA4B;IAChD,aAAa,EAAE,uBAAuB;IACtC,cAAc,EAAE,wBAAwB;IACxC,cAAc,EAAE,wBAAwB;IACxC,YAAY,EAAE,sBAAsB;IACpC,KAAK,EAAE,eAAe;CACd,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { ValidatableComponent, FormFieldInfo } from '@nuralyui/common/mixins';\n\n/**\n * Form validation states that can be applied to the form and its children\n */\nexport enum FormValidationState {\n Pristine = 'pristine', // Form has not been interacted with\n Pending = 'pending', // Validation is in progress\n Valid = 'valid', // All form fields are valid\n Invalid = 'invalid', // One or more form fields are invalid\n Submitted = 'submitted' // Form has been submitted\n}\n\n/**\n * Form submission states\n */\nexport enum FormSubmissionState {\n Idle = 'idle',\n Submitting = 'submitting',\n Success = 'success',\n Error = 'error'\n}\n\n/**\n * Form configuration options\n */\nexport interface FormConfig {\n /** Enable real-time validation */\n validateOnChange?: boolean;\n /** Validate fields on blur */\n validateOnBlur?: boolean;\n /** Show validation errors immediately */\n showErrorsImmediately?: boolean;\n /** Prevent submission if invalid */\n preventInvalidSubmission?: boolean;\n /** Reset form after successful submission */\n resetOnSuccess?: boolean;\n /** Custom validation debounce delay (ms) */\n validationDelay?: number;\n}\n\n/**\n * Form field information\n */\nexport interface FormField extends FormFieldInfo {\n // FormField now extends the shared FormFieldInfo interface\n}\n\n/**\n * Form validation result\n */\nexport interface FormValidationResult {\n isValid: boolean;\n invalidFields: FormField[];\n validationErrors: Record<string, string>;\n summary: string;\n}\n\n/**\n * Form submission data\n */\nexport interface FormSubmissionData {\n formData: FormData;\n jsonData: Record<string, any>;\n fields: Record<string, any>;\n}\n\n/**\n * Interface that form field components must implement\n * @deprecated Use ValidatableComponent from shared/validation.types.js instead\n */\nexport interface FormFieldCapable extends ValidatableComponent {\n /** @deprecated This interface is replaced by ValidatableComponent */\n}\n\n/**\n * Form event details\n */\nexport interface FormEventDetail {\n formData?: FormSubmissionData;\n validationResult?: FormValidationResult;\n field?: FormField;\n error?: Error;\n}\n\n/**\n * Custom form events\n */\nexport const FORM_EVENTS = {\n VALIDATION_CHANGED: 'nr-form-validation-changed',\n FIELD_CHANGED: 'nr-form-field-changed',\n SUBMIT_ATTEMPT: 'nr-form-submit-attempt',\n SUBMIT_SUCCESS: 'nr-form-submit-success',\n SUBMIT_ERROR: 'nr-form-submit-error',\n RESET: 'nr-form-reset',\n} as const;\n\nexport type FormEventType = typeof FORM_EVENTS[keyof typeof FORM_EVENTS];\n"]}
|
package/index.d.ts
CHANGED
|
File without changes
|
package/index.js
CHANGED
|
File without changes
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/form/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,uBAAuB;AACvB,cAAc,iBAAiB,CAAC;AAEhC,cAAc;AACd,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\n// Main component\nexport { NrFormElement } from './form.component.js';\n\n// Types and interfaces\nexport * from './form.types.js';\n\n// Controllers\nexport { FormValidationController } from './controllers/validation.controller.js';\nexport { FormSubmissionController } from './controllers/submission.controller.js';\n"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuralyui/form",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "NuralyUI Form - A comprehensive form component with validation coordination, submission handling, and state management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"types": "./index.d.ts",
|
|
12
12
|
"default": "./index.js"
|
|
13
13
|
},
|
|
14
|
+
"./bundle": {
|
|
15
|
+
"import": "./bundle.js"
|
|
16
|
+
},
|
|
14
17
|
"./form.component.js": {
|
|
15
18
|
"types": "./form.component.d.ts",
|
|
16
19
|
"default": "./form.component.js"
|
|
@@ -19,6 +22,8 @@
|
|
|
19
22
|
"files": [
|
|
20
23
|
"*.js",
|
|
21
24
|
"*.d.ts",
|
|
25
|
+
"*.js.map",
|
|
26
|
+
"bundle.js",
|
|
22
27
|
"controllers/",
|
|
23
28
|
"interfaces/",
|
|
24
29
|
"mixins/",
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
*/
|
|
6
|
-
import { LitElement } from 'lit';
|
|
7
|
-
import { FormFieldCapable } from '../form.types.js';
|
|
8
|
-
declare type Constructor<T = {}> = new (...args: any[]) => T;
|
|
9
|
-
/**
|
|
10
|
-
* Lightweight mixin that provides only form integration capabilities
|
|
11
|
-
* This replaces the heavier FormFieldValidationMixin for components that have their own validation
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* export class InputComponent extends FormFieldIntegrationMixin(NuralyUIBaseMixin(LitElement)) {
|
|
16
|
-
* // Component manages its own validation via controllers
|
|
17
|
-
* }
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export declare const FormFieldIntegrationMixin: <T extends Constructor<LitElement>>(superClass: T) => Constructor<FormFieldCapable> & T;
|
|
21
|
-
export {};
|
|
22
|
-
//# sourceMappingURL=form-field-integration.mixin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"form-field-integration.mixin.d.ts","sourceRoot":"","sources":["../../../../src/components/form/mixins/form-field-integration.mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,aAAK,WAAW,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAErD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,yFA+GrC,CAAC"}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
*/
|
|
6
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
7
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
9
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
10
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
11
|
-
};
|
|
12
|
-
import { property } from 'lit/decorators.js';
|
|
13
|
-
/**
|
|
14
|
-
* Lightweight mixin that provides only form integration capabilities
|
|
15
|
-
* This replaces the heavier FormFieldValidationMixin for components that have their own validation
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```typescript
|
|
19
|
-
* export class InputComponent extends FormFieldIntegrationMixin(NuralyUIBaseMixin(LitElement)) {
|
|
20
|
-
* // Component manages its own validation via controllers
|
|
21
|
-
* }
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export const FormFieldIntegrationMixin = (superClass) => {
|
|
25
|
-
class FormFieldIntegrationMixinClass extends superClass {
|
|
26
|
-
constructor() {
|
|
27
|
-
super(...arguments);
|
|
28
|
-
/** Disabled state */
|
|
29
|
-
this.disabled = false;
|
|
30
|
-
/** Readonly state */
|
|
31
|
-
this.readonly = false;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Dispatch a standardized field change event for form integration
|
|
35
|
-
*/
|
|
36
|
-
dispatchFieldChangeEvent() {
|
|
37
|
-
var _a, _b;
|
|
38
|
-
this.dispatchEvent(new CustomEvent('nr-field-change', {
|
|
39
|
-
detail: {
|
|
40
|
-
name: this.name,
|
|
41
|
-
value: this.value,
|
|
42
|
-
isValid: (_b = (_a = this.checkValidity) === null || _a === void 0 ? void 0 : _a.call(this)) !== null && _b !== void 0 ? _b : true
|
|
43
|
-
},
|
|
44
|
-
bubbles: true,
|
|
45
|
-
composed: true
|
|
46
|
-
}));
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Dispatch a standardized validation event for form integration
|
|
50
|
-
*/
|
|
51
|
-
dispatchValidationEvent(isValid, message) {
|
|
52
|
-
this.dispatchEvent(new CustomEvent('nr-validation', {
|
|
53
|
-
detail: {
|
|
54
|
-
name: this.name,
|
|
55
|
-
isValid,
|
|
56
|
-
message: message || '',
|
|
57
|
-
value: this.value
|
|
58
|
-
},
|
|
59
|
-
bubbles: true,
|
|
60
|
-
composed: true
|
|
61
|
-
}));
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
__decorate([
|
|
65
|
-
property({ type: String })
|
|
66
|
-
], FormFieldIntegrationMixinClass.prototype, "name", void 0);
|
|
67
|
-
__decorate([
|
|
68
|
-
property({ type: Boolean })
|
|
69
|
-
], FormFieldIntegrationMixinClass.prototype, "required", void 0);
|
|
70
|
-
__decorate([
|
|
71
|
-
property({ type: Boolean, reflect: true })
|
|
72
|
-
], FormFieldIntegrationMixinClass.prototype, "disabled", void 0);
|
|
73
|
-
__decorate([
|
|
74
|
-
property({ type: Boolean, reflect: true })
|
|
75
|
-
], FormFieldIntegrationMixinClass.prototype, "readonly", void 0);
|
|
76
|
-
return FormFieldIntegrationMixinClass;
|
|
77
|
-
};
|
|
78
|
-
//# sourceMappingURL=form-field-integration.mixin.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"form-field-integration.mixin.js","sourceRoot":"","sources":["../../../../src/components/form/mixins/form-field-integration.mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;;;;;;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAK7C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAoC,UAAa,EAAE,EAAE;IAC5F,MAAM,8BAA+B,SAAQ,UAAU;QAAvD;;YAUE,qBAAqB;YAErB,aAAQ,GAAG,KAAK,CAAC;YAEjB,qBAAqB;YAErB,aAAQ,GAAG,KAAK,CAAC;QA2FnB,CAAC;QA9BC;;WAEG;QACO,wBAAwB;;YAChC,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,iBAAiB,EAAE;gBACpD,MAAM,EAAE;oBACN,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,OAAO,EAAE,MAAA,MAAA,IAAI,CAAC,aAAa,oDAAI,mCAAI,IAAI;iBACxC;gBACD,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC,CAAC;QACN,CAAC;QAED;;WAEG;QACO,uBAAuB,CAAC,OAAgB,EAAE,OAAgB;YAClE,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,eAAe,EAAE;gBAClD,MAAM,EAAE;oBACN,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,OAAO;oBACP,OAAO,EAAE,OAAO,IAAI,EAAE;oBACtB,KAAK,EAAE,IAAI,CAAC,KAAK;iBAClB;gBACD,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC,CAAC;QACN,CAAC;KACF;IAvGC;QADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gEACb;IAId;QADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;oEACT;IAInB;QADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;oEAC1B;IAIjB;QADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;oEAC1B;IA6FnB,OAAO,8BAAmE,CAAC;AAC7E,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { FormFieldCapable } from '../form.types.js';\n\ntype Constructor<T = {}> = new (...args: any[]) => T;\n\n/**\n * Lightweight mixin that provides only form integration capabilities\n * This replaces the heavier FormFieldValidationMixin for components that have their own validation\n * \n * @example\n * ```typescript\n * export class InputComponent extends FormFieldIntegrationMixin(NuralyUIBaseMixin(LitElement)) {\n * // Component manages its own validation via controllers\n * }\n * ```\n */\nexport const FormFieldIntegrationMixin = <T extends Constructor<LitElement>>(superClass: T) => {\n class FormFieldIntegrationMixinClass extends superClass implements FormFieldCapable {\n \n /** Field name for form submission */\n @property({ type: String })\n name?: string;\n \n /** Required field indicator */\n @property({ type: Boolean })\n required?: boolean;\n \n /** Disabled state */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /** Readonly state */\n @property({ type: Boolean, reflect: true })\n readonly = false;\n \n /** Field value - must be implemented by component */\n declare value: any;\n \n /** Validation message - should be managed by component's validation system */\n declare validationMessage?: string;\n\n // These methods should be implemented by the component using this mixin\n // They are declared here to satisfy the FormFieldCapable interface\n \n /**\n * Validate the field - should be implemented by component\n */\n validate?(): boolean | Promise<boolean>;\n \n /**\n * HTML5 checkValidity - should be implemented by component\n */\n checkValidity?(): boolean;\n \n /**\n * HTML5 reportValidity - should be implemented by component\n */\n reportValidity?(): boolean;\n \n /**\n * Set custom validity message - should be implemented by component\n */\n setCustomValidity?(message: string): void;\n \n /**\n * Reset field - should be implemented by component\n */\n reset?(): void;\n \n /**\n * Get current value - should be implemented by component\n */\n getValue?(): any;\n \n /**\n * Set field value - should be implemented by component\n */\n setValue?(value: any): void;\n \n /**\n * Get validation error - should be implemented by component\n */\n getError?(): string | null;\n \n /**\n * Clear validation - should be implemented by component\n */\n clearValidation?(): void;\n \n /**\n * Check if touched - should be implemented by component\n */\n isTouched?(): boolean;\n\n /**\n * Dispatch a standardized field change event for form integration\n */\n protected dispatchFieldChangeEvent(): void {\n this.dispatchEvent(new CustomEvent('nr-field-change', {\n detail: {\n name: this.name,\n value: this.value,\n isValid: this.checkValidity?.() ?? true\n },\n bubbles: true,\n composed: true\n }));\n }\n\n /**\n * Dispatch a standardized validation event for form integration\n */\n protected dispatchValidationEvent(isValid: boolean, message?: string): void {\n this.dispatchEvent(new CustomEvent('nr-validation', {\n detail: {\n name: this.name,\n isValid,\n message: message || '',\n value: this.value\n },\n bubbles: true,\n composed: true\n }));\n }\n }\n \n return FormFieldIntegrationMixinClass as Constructor<FormFieldCapable> & T;\n};\n"]}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* @deprecated This mixin is deprecated and no longer used.
|
|
8
|
-
*
|
|
9
|
-
* Form field validation is now handled by individual component validation controllers:
|
|
10
|
-
* - Input validation: InputValidationController
|
|
11
|
-
* - Form coordination: FormValidationController (listens to validation events)
|
|
12
|
-
*
|
|
13
|
-
* This approach eliminates duplication and provides better separation of concerns.
|
|
14
|
-
* Components handle their own validation, and forms coordinate/listen to validation events.
|
|
15
|
-
*/
|
|
16
|
-
import { LitElement } from 'lit';
|
|
17
|
-
import { FormFieldValidation } from '../interfaces/validation.interface.js';
|
|
18
|
-
declare type Constructor<T = {}> = new (...args: any[]) => T;
|
|
19
|
-
/**
|
|
20
|
-
* Mixin that provides standardized form field validation capabilities
|
|
21
|
-
* This should be used by input components that need to participate in forms
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* export class InputComponent extends FormFieldValidationMixin(NuralyUIBaseMixin(LitElement)) {
|
|
26
|
-
* // Component-specific validation logic
|
|
27
|
-
* protected validateValue(value: string): boolean {
|
|
28
|
-
* return value.length >= this.minLength;
|
|
29
|
-
* }
|
|
30
|
-
* }
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
export declare const FormFieldValidationMixin: <T extends Constructor<LitElement>>(superClass: T) => Constructor<FormFieldValidation> & T;
|
|
34
|
-
export {};
|
|
35
|
-
//# sourceMappingURL=form-field-validation.mixin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"form-field-validation.mixin.d.ts","sourceRoot":"","sources":["../../../../src/components/form/mixins/form-field-validation.mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEjC,OAAO,EAAE,mBAAmB,EAAyB,MAAM,uCAAuC,CAAC;AAEnG,aAAK,WAAW,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAErD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,4FAqTpC,CAAC"}
|
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
*/
|
|
6
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
7
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
9
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
10
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
11
|
-
};
|
|
12
|
-
import { property, state } from 'lit/decorators.js';
|
|
13
|
-
/**
|
|
14
|
-
* Mixin that provides standardized form field validation capabilities
|
|
15
|
-
* This should be used by input components that need to participate in forms
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```typescript
|
|
19
|
-
* export class InputComponent extends FormFieldValidationMixin(NuralyUIBaseMixin(LitElement)) {
|
|
20
|
-
* // Component-specific validation logic
|
|
21
|
-
* protected validateValue(value: string): boolean {
|
|
22
|
-
* return value.length >= this.minLength;
|
|
23
|
-
* }
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export const FormFieldValidationMixin = (superClass) => {
|
|
28
|
-
class FormFieldValidationMixinClass extends superClass {
|
|
29
|
-
constructor() {
|
|
30
|
-
super(...arguments);
|
|
31
|
-
/** Current validation message */
|
|
32
|
-
this.validationMessage = '';
|
|
33
|
-
/** Validation state */
|
|
34
|
-
this._isValid = true;
|
|
35
|
-
/** Whether field has been touched by user */
|
|
36
|
-
this._isTouched = false;
|
|
37
|
-
/** Whether field value has changed from initial */
|
|
38
|
-
this._isDirty = false;
|
|
39
|
-
/**
|
|
40
|
-
* Handle focus event
|
|
41
|
-
*/
|
|
42
|
-
this.handleFocus = () => {
|
|
43
|
-
this._isTouched = true;
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Handle blur event
|
|
47
|
-
*/
|
|
48
|
-
this.handleBlur = () => {
|
|
49
|
-
this.validateOnBlur();
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Handle input event
|
|
53
|
-
*/
|
|
54
|
-
this.handleInput = () => {
|
|
55
|
-
this.updateDirtyState();
|
|
56
|
-
this.validateOnInput();
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* Handle change event
|
|
60
|
-
*/
|
|
61
|
-
this.handleChange = () => {
|
|
62
|
-
this.updateDirtyState();
|
|
63
|
-
this.validateOnChange();
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
connectedCallback() {
|
|
67
|
-
super.connectedCallback();
|
|
68
|
-
this._initialValue = this.value;
|
|
69
|
-
this.addValidationListeners();
|
|
70
|
-
}
|
|
71
|
-
disconnectedCallback() {
|
|
72
|
-
super.disconnectedCallback();
|
|
73
|
-
this.removeValidationListeners();
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Add validation event listeners
|
|
77
|
-
*/
|
|
78
|
-
addValidationListeners() {
|
|
79
|
-
this.addEventListener('focus', this.handleFocus);
|
|
80
|
-
this.addEventListener('blur', this.handleBlur);
|
|
81
|
-
this.addEventListener('input', this.handleInput);
|
|
82
|
-
this.addEventListener('change', this.handleChange);
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Remove validation event listeners
|
|
86
|
-
*/
|
|
87
|
-
removeValidationListeners() {
|
|
88
|
-
this.removeEventListener('focus', this.handleFocus);
|
|
89
|
-
this.removeEventListener('blur', this.handleBlur);
|
|
90
|
-
this.removeEventListener('input', this.handleInput);
|
|
91
|
-
this.removeEventListener('change', this.handleChange);
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Update dirty state
|
|
95
|
-
*/
|
|
96
|
-
updateDirtyState() {
|
|
97
|
-
this._isDirty = this.value !== this._initialValue;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Validate on blur (can be overridden)
|
|
101
|
-
*/
|
|
102
|
-
validateOnBlur() {
|
|
103
|
-
// Only validate if the validation trigger is set to blur
|
|
104
|
-
const trigger = this.validationTrigger;
|
|
105
|
-
if (trigger === 'blur') {
|
|
106
|
-
this.validate();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Validate on input (can be overridden)
|
|
111
|
-
*/
|
|
112
|
-
validateOnInput() {
|
|
113
|
-
// Override in component if needed
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Validate on change (can be overridden)
|
|
117
|
-
*/
|
|
118
|
-
validateOnChange() {
|
|
119
|
-
// Only validate if the validation trigger is set to change
|
|
120
|
-
const trigger = this.validationTrigger;
|
|
121
|
-
if (trigger === 'change') {
|
|
122
|
-
this.validate();
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Main validation method - validates the field
|
|
127
|
-
*/
|
|
128
|
-
validate() {
|
|
129
|
-
const isValid = this.performValidation();
|
|
130
|
-
this.setValidationState(isValid);
|
|
131
|
-
return isValid;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Perform the actual validation logic
|
|
135
|
-
* Override this method in components for specific validation
|
|
136
|
-
*/
|
|
137
|
-
performValidation() {
|
|
138
|
-
// Required field validation
|
|
139
|
-
if (this.required && this.isEmpty()) {
|
|
140
|
-
this.validationMessage = 'This field is required';
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
// Component-specific validation
|
|
144
|
-
if (!this.isEmpty() && !this.validateValue(this.value)) {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
this.validationMessage = '';
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Component-specific value validation
|
|
152
|
-
* Override this method in components
|
|
153
|
-
*/
|
|
154
|
-
validateValue(_value) {
|
|
155
|
-
return true; // Default: always valid
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Check if value is empty
|
|
159
|
-
*/
|
|
160
|
-
isEmpty() {
|
|
161
|
-
const value = this.value;
|
|
162
|
-
return value === null ||
|
|
163
|
-
value === undefined ||
|
|
164
|
-
value === '' ||
|
|
165
|
-
(Array.isArray(value) && value.length === 0);
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Set validation state and dispatch events
|
|
169
|
-
*/
|
|
170
|
-
setValidationState(isValid) {
|
|
171
|
-
const wasValid = this._isValid;
|
|
172
|
-
this._isValid = isValid;
|
|
173
|
-
// Dispatch validation event if state changed
|
|
174
|
-
if (wasValid !== isValid) {
|
|
175
|
-
this.dispatchValidationEvent(isValid);
|
|
176
|
-
}
|
|
177
|
-
// Update UI
|
|
178
|
-
this.requestUpdate();
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* HTML5 constraint validation API
|
|
182
|
-
*/
|
|
183
|
-
checkValidity() {
|
|
184
|
-
return this.validate();
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* HTML5 constraint validation API with UI feedback
|
|
188
|
-
*/
|
|
189
|
-
reportValidity() {
|
|
190
|
-
const isValid = this.validate();
|
|
191
|
-
if (!isValid) {
|
|
192
|
-
// Show validation UI (can be overridden)
|
|
193
|
-
this.showValidationUI();
|
|
194
|
-
// Dispatch invalid event
|
|
195
|
-
this.dispatchEvent(new CustomEvent('invalid', {
|
|
196
|
-
detail: { message: this.validationMessage },
|
|
197
|
-
bubbles: true,
|
|
198
|
-
composed: true
|
|
199
|
-
}));
|
|
200
|
-
}
|
|
201
|
-
return isValid;
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Set custom validation message
|
|
205
|
-
*/
|
|
206
|
-
setCustomValidity(message) {
|
|
207
|
-
this.validationMessage = message;
|
|
208
|
-
this._isValid = !message;
|
|
209
|
-
this.requestUpdate();
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Reset field to initial state
|
|
213
|
-
*/
|
|
214
|
-
reset() {
|
|
215
|
-
this.value = this._initialValue;
|
|
216
|
-
this._isValid = true;
|
|
217
|
-
this._isTouched = false;
|
|
218
|
-
this._isDirty = false;
|
|
219
|
-
this.validationMessage = '';
|
|
220
|
-
this.requestUpdate();
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Show validation UI (override in components)
|
|
224
|
-
*/
|
|
225
|
-
showValidationUI() {
|
|
226
|
-
// Default implementation - can be overridden
|
|
227
|
-
console.warn('Validation failed:', this.validationMessage);
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Dispatch validation event
|
|
231
|
-
*/
|
|
232
|
-
dispatchValidationEvent(isValid) {
|
|
233
|
-
const detail = {
|
|
234
|
-
isValid,
|
|
235
|
-
value: this.value,
|
|
236
|
-
message: this.validationMessage || '',
|
|
237
|
-
errors: isValid ? [] : [this.validationMessage || ''],
|
|
238
|
-
field: this.name,
|
|
239
|
-
timestamp: Date.now()
|
|
240
|
-
};
|
|
241
|
-
this.dispatchEvent(new CustomEvent('nr-validation', {
|
|
242
|
-
detail,
|
|
243
|
-
bubbles: true,
|
|
244
|
-
composed: true
|
|
245
|
-
}));
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Get validation state
|
|
249
|
-
*/
|
|
250
|
-
get isValid() {
|
|
251
|
-
return this._isValid;
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Get touched state
|
|
255
|
-
*/
|
|
256
|
-
get isTouched() {
|
|
257
|
-
return this._isTouched;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Get dirty state
|
|
261
|
-
*/
|
|
262
|
-
get isDirty() {
|
|
263
|
-
return this._isDirty;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Get validation classes for styling
|
|
267
|
-
*/
|
|
268
|
-
getValidationClasses() {
|
|
269
|
-
return {
|
|
270
|
-
'valid': this._isValid,
|
|
271
|
-
'invalid': !this._isValid,
|
|
272
|
-
'touched': this._isTouched,
|
|
273
|
-
'untouched': !this._isTouched,
|
|
274
|
-
'dirty': this._isDirty,
|
|
275
|
-
'pristine': !this._isDirty,
|
|
276
|
-
'required': this.required || false
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
__decorate([
|
|
281
|
-
property({ type: String })
|
|
282
|
-
], FormFieldValidationMixinClass.prototype, "name", void 0);
|
|
283
|
-
__decorate([
|
|
284
|
-
property({ type: Boolean })
|
|
285
|
-
], FormFieldValidationMixinClass.prototype, "required", void 0);
|
|
286
|
-
__decorate([
|
|
287
|
-
state()
|
|
288
|
-
], FormFieldValidationMixinClass.prototype, "validationMessage", void 0);
|
|
289
|
-
__decorate([
|
|
290
|
-
state()
|
|
291
|
-
], FormFieldValidationMixinClass.prototype, "_isValid", void 0);
|
|
292
|
-
__decorate([
|
|
293
|
-
state()
|
|
294
|
-
], FormFieldValidationMixinClass.prototype, "_isTouched", void 0);
|
|
295
|
-
__decorate([
|
|
296
|
-
state()
|
|
297
|
-
], FormFieldValidationMixinClass.prototype, "_isDirty", void 0);
|
|
298
|
-
return FormFieldValidationMixinClass;
|
|
299
|
-
};
|
|
300
|
-
//# sourceMappingURL=form-field-validation.mixin.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"form-field-validation.mixin.js","sourceRoot":"","sources":["../../../../src/components/form/mixins/form-field-validation.mixin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\n/**\n * @deprecated This mixin is deprecated and no longer used.\n * \n * Form field validation is now handled by individual component validation controllers:\n * - Input validation: InputValidationController\n * - Form coordination: FormValidationController (listens to validation events)\n * \n * This approach eliminates duplication and provides better separation of concerns.\n * Components handle their own validation, and forms coordinate/listen to validation events.\n */\n\nimport { LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { FormFieldValidation, ValidationEventDetail } from '../interfaces/validation.interface.js';\n\ntype Constructor<T = {}> = new (...args: any[]) => T;\n\n/**\n * Mixin that provides standardized form field validation capabilities\n * This should be used by input components that need to participate in forms\n * \n * @example\n * ```typescript\n * export class InputComponent extends FormFieldValidationMixin(NuralyUIBaseMixin(LitElement)) {\n * // Component-specific validation logic\n * protected validateValue(value: string): boolean {\n * return value.length >= this.minLength;\n * }\n * }\n * ```\n */\nexport const FormFieldValidationMixin = <T extends Constructor<LitElement>>(superClass: T) => {\n class FormFieldValidationMixinClass extends superClass implements FormFieldValidation {\n \n /** Field name for form submission */\n @property({ type: String })\n name?: string;\n \n /** Required field indicator */\n @property({ type: Boolean })\n required?: boolean;\n \n /** Current validation message */\n @state()\n validationMessage?: string = '';\n \n /** Validation state */\n @state()\n private _isValid: boolean = true;\n \n /** Whether field has been touched by user */\n @state()\n private _isTouched: boolean = false;\n \n /** Whether field value has changed from initial */\n @state()\n private _isDirty: boolean = false;\n \n /** Initial value for dirty state tracking */\n private _initialValue: any;\n \n /** Field value - must be implemented by component */\n declare value: any;\n \n override connectedCallback(): void {\n super.connectedCallback();\n this._initialValue = this.value;\n this.addValidationListeners();\n }\n \n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeValidationListeners();\n }\n \n /**\n * Add validation event listeners\n */\n private addValidationListeners(): void {\n this.addEventListener('focus', this.handleFocus);\n this.addEventListener('blur', this.handleBlur);\n this.addEventListener('input', this.handleInput);\n this.addEventListener('change', this.handleChange);\n }\n \n /**\n * Remove validation event listeners\n */\n private removeValidationListeners(): void {\n this.removeEventListener('focus', this.handleFocus);\n this.removeEventListener('blur', this.handleBlur);\n this.removeEventListener('input', this.handleInput);\n this.removeEventListener('change', this.handleChange);\n }\n \n /**\n * Handle focus event\n */\n private handleFocus = (): void => {\n this._isTouched = true;\n };\n \n /**\n * Handle blur event\n */\n private handleBlur = (): void => {\n this.validateOnBlur();\n };\n \n /**\n * Handle input event\n */\n private handleInput = (): void => {\n this.updateDirtyState();\n this.validateOnInput();\n };\n \n /**\n * Handle change event\n */\n private handleChange = (): void => {\n this.updateDirtyState();\n this.validateOnChange();\n };\n \n /**\n * Update dirty state\n */\n private updateDirtyState(): void {\n this._isDirty = this.value !== this._initialValue;\n }\n \n /**\n * Validate on blur (can be overridden)\n */\n protected validateOnBlur(): void {\n // Only validate if the validation trigger is set to blur\n const trigger = (this as any).validationTrigger;\n if (trigger === 'blur') {\n this.validate();\n }\n }\n \n /**\n * Validate on input (can be overridden)\n */\n protected validateOnInput(): void {\n // Override in component if needed\n }\n \n /**\n * Validate on change (can be overridden)\n */\n protected validateOnChange(): void {\n // Only validate if the validation trigger is set to change\n const trigger = (this as any).validationTrigger;\n if (trigger === 'change') {\n this.validate();\n }\n }\n \n /**\n * Main validation method - validates the field\n */\n validate(): boolean {\n const isValid = this.performValidation();\n this.setValidationState(isValid);\n return isValid;\n }\n \n /**\n * Perform the actual validation logic\n * Override this method in components for specific validation\n */\n protected performValidation(): boolean {\n // Required field validation\n if (this.required && this.isEmpty()) {\n this.validationMessage = 'This field is required';\n return false;\n }\n \n // Component-specific validation\n if (!this.isEmpty() && !this.validateValue(this.value)) {\n return false;\n }\n \n this.validationMessage = '';\n return true;\n }\n \n /**\n * Component-specific value validation\n * Override this method in components\n */\n protected validateValue(_value: any): boolean {\n return true; // Default: always valid\n }\n \n /**\n * Check if value is empty\n */\n protected isEmpty(): boolean {\n const value = this.value;\n return value === null || \n value === undefined || \n value === '' || \n (Array.isArray(value) && value.length === 0);\n }\n \n /**\n * Set validation state and dispatch events\n */\n private setValidationState(isValid: boolean): void {\n const wasValid = this._isValid;\n this._isValid = isValid;\n \n // Dispatch validation event if state changed\n if (wasValid !== isValid) {\n this.dispatchValidationEvent(isValid);\n }\n \n // Update UI\n this.requestUpdate();\n }\n \n /**\n * HTML5 constraint validation API\n */\n checkValidity(): boolean {\n return this.validate();\n }\n \n /**\n * HTML5 constraint validation API with UI feedback\n */\n reportValidity(): boolean {\n const isValid = this.validate();\n \n if (!isValid) {\n // Show validation UI (can be overridden)\n this.showValidationUI();\n \n // Dispatch invalid event\n this.dispatchEvent(new CustomEvent('invalid', {\n detail: { message: this.validationMessage },\n bubbles: true,\n composed: true\n }));\n }\n \n return isValid;\n }\n \n /**\n * Set custom validation message\n */\n setCustomValidity(message: string): void {\n this.validationMessage = message;\n this._isValid = !message;\n this.requestUpdate();\n }\n \n /**\n * Reset field to initial state\n */\n reset(): void {\n (this as any).value = this._initialValue;\n this._isValid = true;\n this._isTouched = false;\n this._isDirty = false;\n this.validationMessage = '';\n this.requestUpdate();\n }\n \n /**\n * Show validation UI (override in components)\n */\n protected showValidationUI(): void {\n // Default implementation - can be overridden\n console.warn('Validation failed:', this.validationMessage);\n }\n \n /**\n * Dispatch validation event\n */\n private dispatchValidationEvent(isValid: boolean): void {\n const detail: ValidationEventDetail = {\n isValid,\n value: this.value,\n message: this.validationMessage || '',\n errors: isValid ? [] : [this.validationMessage || ''],\n field: this.name,\n timestamp: Date.now()\n };\n \n this.dispatchEvent(new CustomEvent('nr-validation', {\n detail,\n bubbles: true,\n composed: true\n }));\n }\n \n /**\n * Get validation state\n */\n get isValid(): boolean {\n return this._isValid;\n }\n \n /**\n * Get touched state\n */\n get isTouched(): boolean {\n return this._isTouched;\n }\n \n /**\n * Get dirty state\n */\n get isDirty(): boolean {\n return this._isDirty;\n }\n \n /**\n * Get validation classes for styling\n */\n protected getValidationClasses(): Record<string, boolean> {\n return {\n 'valid': this._isValid,\n 'invalid': !this._isValid,\n 'touched': this._isTouched,\n 'untouched': !this._isTouched,\n 'dirty': this._isDirty,\n 'pristine': !this._isDirty,\n 'required': this.required || false\n };\n }\n }\n \n return FormFieldValidationMixinClass as Constructor<FormFieldValidation> & T;\n};\n"]}
|