@nuralyui/form 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle.js +154 -0
- package/controllers/submission.controller.d.ts +60 -0
- package/controllers/submission.controller.d.ts.map +1 -0
- package/controllers/submission.controller.js +220 -0
- package/controllers/submission.controller.js.map +1 -0
- package/controllers/validation.controller.d.ts +87 -0
- package/controllers/validation.controller.d.ts.map +1 -0
- package/controllers/validation.controller.js +236 -0
- package/controllers/validation.controller.js.map +1 -0
- package/form.component.d.ts +279 -0
- package/form.component.js +644 -0
- package/form.style.d.ts +7 -0
- package/form.style.js +68 -0
- package/form.types.d.ts +92 -0
- package/form.types.js +38 -0
- package/index.d.ts +10 -0
- package/index.js +13 -0
- package/interfaces/validation.interface.d.ts +118 -0
- package/interfaces/validation.interface.d.ts.map +1 -0
- package/interfaces/validation.interface.js +7 -0
- package/interfaces/validation.interface.js.map +1 -0
- package/mixins/form-field-integration.mixin.d.ts +22 -0
- package/mixins/form-field-integration.mixin.d.ts.map +1 -0
- package/mixins/form-field-integration.mixin.js +78 -0
- package/mixins/form-field-integration.mixin.js.map +1 -0
- package/mixins/form-field-validation.mixin.d.ts +35 -0
- package/mixins/form-field-validation.mixin.d.ts.map +1 -0
- package/mixins/form-field-validation.mixin.js +300 -0
- package/mixins/form-field-validation.mixin.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,300 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nuralyui/form",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "NuralyUI Form - A comprehensive form component with validation coordination, submission handling, and state management",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.js",
|
|
7
|
+
"module": "./index.js",
|
|
8
|
+
"types": "./index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./index.d.ts",
|
|
12
|
+
"default": "./index.js"
|
|
13
|
+
},
|
|
14
|
+
"./form.component.js": {
|
|
15
|
+
"types": "./form.component.d.ts",
|
|
16
|
+
"default": "./form.component.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"*.js",
|
|
21
|
+
"*.d.ts",
|
|
22
|
+
"controllers/",
|
|
23
|
+
"interfaces/",
|
|
24
|
+
"mixins/",
|
|
25
|
+
"utils/",
|
|
26
|
+
"demo/",
|
|
27
|
+
"test/"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"test": "wtr \"**/*.test.js\" --node-resolve",
|
|
32
|
+
"test:watch": "wtr \"**/*.test.js\" --node-resolve --watch",
|
|
33
|
+
"demo": "wds --open demo/ --node-resolve"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"form",
|
|
37
|
+
"validation",
|
|
38
|
+
"form-control",
|
|
39
|
+
"web-components",
|
|
40
|
+
"lit",
|
|
41
|
+
"nuraly",
|
|
42
|
+
"ui-components",
|
|
43
|
+
"form-submission",
|
|
44
|
+
"form-state"
|
|
45
|
+
],
|
|
46
|
+
"author": "Nuraly Team <team@nuraly.io>",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"lit": "^3.0.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@nuraly/shared": "^1.0.0"
|
|
53
|
+
},
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "https://github.com/Nuralyio/NuralyUI.git",
|
|
57
|
+
"directory": "src/components/form"
|
|
58
|
+
},
|
|
59
|
+
"bugs": {
|
|
60
|
+
"url": "https://github.com/Nuralyio/NuralyUI/issues"
|
|
61
|
+
},
|
|
62
|
+
"homepage": "https://nuralyui.com/components/form"
|
|
63
|
+
}
|