juxscript 1.1.80 → 1.1.81

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.
Files changed (52) hide show
  1. package/dom-structure-map.json +1 -1
  2. package/index.d.ts +2 -2
  3. package/index.d.ts.map +1 -1
  4. package/index.js +2 -2
  5. package/lib/components/badge.d.ts.map +1 -1
  6. package/lib/components/badge.js +2 -1
  7. package/lib/components/badge.ts +2 -1
  8. package/lib/components/base/BaseComponent.d.ts +55 -1
  9. package/lib/components/base/BaseComponent.d.ts.map +1 -1
  10. package/lib/components/base/BaseComponent.js +168 -2
  11. package/lib/components/base/BaseComponent.ts +203 -3
  12. package/lib/components/checkbox.d.ts +5 -4
  13. package/lib/components/checkbox.d.ts.map +1 -1
  14. package/lib/components/checkbox.js +33 -16
  15. package/lib/components/checkbox.ts +39 -22
  16. package/lib/components/datepicker.d.ts +5 -4
  17. package/lib/components/datepicker.d.ts.map +1 -1
  18. package/lib/components/datepicker.js +31 -16
  19. package/lib/components/datepicker.ts +37 -22
  20. package/lib/components/dropdown.d.ts.map +1 -1
  21. package/lib/components/dropdown.js +2 -1
  22. package/lib/components/dropdown.ts +2 -1
  23. package/lib/components/fileupload.d.ts +6 -6
  24. package/lib/components/fileupload.d.ts.map +1 -1
  25. package/lib/components/fileupload.js +77 -52
  26. package/lib/components/fileupload.ts +88 -58
  27. package/lib/components/input.d.ts +5 -4
  28. package/lib/components/input.d.ts.map +1 -1
  29. package/lib/components/input.js +38 -24
  30. package/lib/components/input.ts +48 -33
  31. package/lib/components/radio.d.ts +5 -4
  32. package/lib/components/radio.d.ts.map +1 -1
  33. package/lib/components/radio.js +37 -14
  34. package/lib/components/radio.ts +40 -16
  35. package/lib/components/select.d.ts +5 -4
  36. package/lib/components/select.d.ts.map +1 -1
  37. package/lib/components/select.js +32 -11
  38. package/lib/components/select.ts +38 -16
  39. package/lib/components/switch.d.ts +5 -4
  40. package/lib/components/switch.d.ts.map +1 -1
  41. package/lib/components/switch.js +34 -11
  42. package/lib/components/switch.ts +42 -16
  43. package/lib/components/watcher.d.ts +195 -0
  44. package/lib/components/watcher.d.ts.map +1 -0
  45. package/lib/components/watcher.js +241 -0
  46. package/lib/components/watcher.ts +261 -0
  47. package/package.json +1 -1
  48. package/lib/components/base/FormInput.d.ts +0 -77
  49. package/lib/components/base/FormInput.d.ts.map +0 -1
  50. package/lib/components/base/FormInput.js +0 -171
  51. package/lib/components/base/FormInput.ts +0 -237
  52. package/lib/components/event-chain.ts +0 -31
@@ -1,22 +1,26 @@
1
- import { FormInput } from './base/FormInput.js';
1
+ import { BaseComponent } from './base/BaseComponent.js';
2
2
  import { renderIcon } from './icons.js';
3
+ import { formatIdAsLabel } from '../utils/formatId.js'; // ✅ Import
3
4
  // Event definitions
4
5
  const TRIGGER_EVENTS = [];
5
6
  const CALLBACK_EVENTS = ['change', 'filesSelected', 'clear'];
6
- export class FileUpload extends FormInput {
7
+ export class FileUpload extends BaseComponent {
7
8
  constructor(id, options = {}) {
8
9
  super(id, {
10
+ visible: true,
11
+ disabled: options.disabled ?? false,
12
+ loading: false,
13
+ class: options.class ?? '',
14
+ style: options.style ?? '',
15
+ attributes: {},
16
+ label: options.label ?? formatIdAsLabel(id), // ✅ Auto-generate
17
+ required: options.required ?? false,
18
+ name: options.name ?? id,
19
+ errorMessage: undefined,
9
20
  files: [],
10
21
  accept: options.accept ?? '',
11
22
  multiple: options.multiple ?? false,
12
- icon: options.icon ?? 'upload',
13
- label: options.label ?? '',
14
- required: options.required ?? false,
15
- disabled: options.disabled ?? false,
16
- name: options.name ?? id,
17
- style: options.style ?? '',
18
- class: options.class ?? '',
19
- errorMessage: undefined
23
+ icon: options.icon ?? 'upload'
20
24
  });
21
25
  this._fileListElement = null;
22
26
  if (options.onValidate) {
@@ -32,12 +36,6 @@ export class FileUpload extends FormInput {
32
36
  /* ═════════════════════════════════════════════════════════════════
33
37
  * FLUENT API
34
38
  * ═════════════════════════════════════════════════════════════════ */
35
- // ✅ Inherited from FormInput/BaseComponent:
36
- // - label(), required(), name(), onValidate()
37
- // - validate(), isValid()
38
- // - style(), class()
39
- // - bind(), sync(), renderTo()
40
- // - disabled(), enable(), disable()
41
39
  accept(value) {
42
40
  this.state.accept = value;
43
41
  return this;
@@ -56,9 +54,8 @@ export class FileUpload extends FormInput {
56
54
  this._inputElement.value = '';
57
55
  }
58
56
  if (this._fileListElement) {
59
- this._updateFileList([]);
57
+ this._fileListElement.innerHTML = '';
60
58
  }
61
- // 🎯 Fire the clear callback event
62
59
  this._triggerCallback('clear');
63
60
  return this;
64
61
  }
@@ -70,13 +67,25 @@ export class FileUpload extends FormInput {
70
67
  }
71
68
  setValue(files) {
72
69
  this.state.files = files;
73
- if (this._fileListElement) {
74
- this._updateFileList(files);
75
- }
70
+ this._updateFileList();
76
71
  return this;
77
72
  }
78
- getFiles() {
79
- return this.getValue();
73
+ validate() {
74
+ this._hasBeenValidated = true;
75
+ const files = this.getValue();
76
+ const result = this._validateValue(files);
77
+ if (result === true) {
78
+ this._clearError();
79
+ return true;
80
+ }
81
+ else {
82
+ this._showError(result);
83
+ return false;
84
+ }
85
+ }
86
+ isValid() {
87
+ const files = this.getValue();
88
+ return this._validateValue(files) === true;
80
89
  }
81
90
  _validateValue(files) {
82
91
  const { required } = this.state;
@@ -98,14 +107,45 @@ export class FileUpload extends FormInput {
98
107
  input.className = 'jux-fileupload-input';
99
108
  input.id = `${this._id}-input`;
100
109
  input.name = name;
110
+ input.accept = accept;
111
+ input.multiple = multiple;
101
112
  input.required = required;
102
113
  input.disabled = disabled;
103
- if (accept)
104
- input.accept = accept;
105
- if (multiple)
106
- input.multiple = multiple;
114
+ input.style.display = 'none'; // Hidden, triggered by button
107
115
  return input;
108
116
  }
117
+ _updateFileList() {
118
+ if (!this._fileListElement)
119
+ return; // Safety check
120
+ this._fileListElement.innerHTML = '';
121
+ if (this.state.files.length === 0) {
122
+ return;
123
+ }
124
+ this.state.files.forEach((file, index) => {
125
+ const fileItem = document.createElement('div');
126
+ fileItem.className = 'jux-fileupload-item';
127
+ fileItem.innerHTML = `
128
+ <span class="jux-fileupload-filename">${file.name}</span>
129
+ <span class="jux-fileupload-filesize">${this._formatFileSize(file.size)}</span>
130
+ <button class="jux-fileupload-remove" data-index="${index}">×</button>
131
+ `;
132
+ const removeBtn = fileItem.querySelector('.jux-fileupload-remove');
133
+ removeBtn?.addEventListener('click', () => {
134
+ this.state.files = this.state.files.filter((_, i) => i !== index);
135
+ this._updateFileList();
136
+ this._triggerCallback('change', this.state.files);
137
+ });
138
+ this._fileListElement.appendChild(fileItem); // ✅ Non-null assertion safe here
139
+ });
140
+ }
141
+ _formatFileSize(bytes) {
142
+ if (bytes === 0)
143
+ return '0 Bytes';
144
+ const k = 1024;
145
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
146
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
147
+ return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
148
+ }
109
149
  /* ═════════════════════════════════════════════════════════════════
110
150
  * RENDER
111
151
  * ═════════════════════════════════════════════════════════════════ */
@@ -176,7 +216,7 @@ export class FileUpload extends FormInput {
176
216
  isUpdating = true;
177
217
  const files = Array.from(inputEl.files || []);
178
218
  this.state.files = files;
179
- this._updateFileList(files);
219
+ this._updateFileList();
180
220
  this._clearError();
181
221
  const transformed = transformToState(files);
182
222
  stateObj.set(transformed);
@@ -191,7 +231,7 @@ export class FileUpload extends FormInput {
191
231
  inputEl.addEventListener('change', () => {
192
232
  const files = Array.from(inputEl.files || []);
193
233
  this.state.files = files;
194
- this._updateFileList(files);
234
+ this._updateFileList();
195
235
  this._clearError();
196
236
  // 🎯 Fire the callback events
197
237
  this._triggerCallback('change', files);
@@ -200,7 +240,9 @@ export class FileUpload extends FormInput {
200
240
  }
201
241
  // Always add blur validation
202
242
  inputEl.addEventListener('blur', () => {
203
- this.validate();
243
+ if (this._hasBeenValidated) {
244
+ this.validate();
245
+ }
204
246
  });
205
247
  // Sync label changes
206
248
  const labelSync = this._syncBindings.find(b => b.property === 'label');
@@ -211,29 +253,12 @@ export class FileUpload extends FormInput {
211
253
  });
212
254
  }
213
255
  container.appendChild(wrapper);
214
- return this;
215
- }
216
- _updateFileList(files) {
217
- if (!this._fileListElement)
218
- return;
219
- this._fileListElement.innerHTML = '';
220
- if (files.length === 0) {
221
- this._fileListElement.textContent = 'No files selected';
222
- return;
223
- }
224
- files.forEach(file => {
225
- const fileItem = document.createElement('div');
226
- fileItem.className = 'jux-fileupload-item';
227
- fileItem.textContent = `${file.name} (${this._formatFileSize(file.size)})`;
228
- this._fileListElement.appendChild(fileItem);
256
+ requestAnimationFrame(() => {
257
+ if (window.lucide) {
258
+ window.lucide.createIcons();
259
+ }
229
260
  });
230
- }
231
- _formatFileSize(bytes) {
232
- if (bytes < 1024)
233
- return `${bytes} B`;
234
- if (bytes < 1024 * 1024)
235
- return `${(bytes / 1024).toFixed(1)} KB`;
236
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
261
+ return this;
237
262
  }
238
263
  }
239
264
  export function fileupload(id, options = {}) {
@@ -1,6 +1,6 @@
1
- import { FormInput, FormInputState } from './base/FormInput.js';
1
+ import { BaseComponent, BaseState } from './base/BaseComponent.js';
2
2
  import { renderIcon } from './icons.js';
3
- import { BaseComponent } from './base/BaseComponent.js';
3
+ import { formatIdAsLabel } from '../utils/formatId.js'; // ✅ Import
4
4
 
5
5
  // Event definitions
6
6
  const TRIGGER_EVENTS = [] as const;
@@ -19,29 +19,32 @@ export interface FileUploadOptions {
19
19
  onValidate?: (files: File[]) => boolean | string;
20
20
  }
21
21
 
22
- interface FileUploadState extends FormInputState {
22
+ interface FileUploadState extends BaseState {
23
23
  files: File[];
24
24
  accept: string;
25
25
  multiple: boolean;
26
26
  icon: string;
27
27
  }
28
28
 
29
- export class FileUpload extends FormInput<FileUploadState> {
29
+ export class FileUpload extends BaseComponent<FileUploadState> {
30
30
  private _fileListElement: HTMLElement | null = null;
31
31
 
32
32
  constructor(id: string, options: FileUploadOptions = {}) {
33
33
  super(id, {
34
+ visible: true,
35
+ disabled: options.disabled ?? false,
36
+ loading: false,
37
+ class: options.class ?? '',
38
+ style: options.style ?? '',
39
+ attributes: {},
40
+ label: options.label ?? formatIdAsLabel(id), // ✅ Auto-generate
41
+ required: options.required ?? false,
42
+ name: options.name ?? id,
43
+ errorMessage: undefined,
34
44
  files: [],
35
45
  accept: options.accept ?? '',
36
46
  multiple: options.multiple ?? false,
37
- icon: options.icon ?? 'upload',
38
- label: options.label ?? '',
39
- required: options.required ?? false,
40
- disabled: options.disabled ?? false,
41
- name: options.name ?? id,
42
- style: options.style ?? '',
43
- class: options.class ?? '',
44
- errorMessage: undefined
47
+ icon: options.icon ?? 'upload'
45
48
  });
46
49
 
47
50
  if (options.onValidate) {
@@ -61,13 +64,6 @@ export class FileUpload extends FormInput<FileUploadState> {
61
64
  * FLUENT API
62
65
  * ═════════════════════════════════════════════════════════════════ */
63
66
 
64
- // ✅ Inherited from FormInput/BaseComponent:
65
- // - label(), required(), name(), onValidate()
66
- // - validate(), isValid()
67
- // - style(), class()
68
- // - bind(), sync(), renderTo()
69
- // - disabled(), enable(), disable()
70
-
71
67
  accept(value: string): this {
72
68
  this.state.accept = value;
73
69
  return this;
@@ -89,9 +85,8 @@ export class FileUpload extends FormInput<FileUploadState> {
89
85
  (this._inputElement as HTMLInputElement).value = '';
90
86
  }
91
87
  if (this._fileListElement) {
92
- this._updateFileList([]);
88
+ this._fileListElement.innerHTML = '';
93
89
  }
94
- // 🎯 Fire the clear callback event
95
90
  this._triggerCallback('clear');
96
91
  return this;
97
92
  }
@@ -106,14 +101,27 @@ export class FileUpload extends FormInput<FileUploadState> {
106
101
 
107
102
  setValue(files: File[]): this {
108
103
  this.state.files = files;
109
- if (this._fileListElement) {
110
- this._updateFileList(files);
111
- }
104
+ this._updateFileList();
112
105
  return this;
113
106
  }
114
107
 
115
- getFiles(): File[] {
116
- return this.getValue();
108
+ validate(): boolean {
109
+ this._hasBeenValidated = true;
110
+ const files = this.getValue();
111
+ const result = this._validateValue(files);
112
+
113
+ if (result === true) {
114
+ this._clearError();
115
+ return true;
116
+ } else {
117
+ this._showError(result as string);
118
+ return false;
119
+ }
120
+ }
121
+
122
+ isValid(): boolean {
123
+ const files = this.getValue();
124
+ return this._validateValue(files) === true;
117
125
  }
118
126
 
119
127
  protected _validateValue(files: File[]): boolean | string {
@@ -140,16 +148,53 @@ export class FileUpload extends FormInput<FileUploadState> {
140
148
  input.type = 'file';
141
149
  input.className = 'jux-fileupload-input';
142
150
  input.id = `${this._id}-input`;
143
- input.name = name;
144
- input.required = required;
145
- input.disabled = disabled;
146
-
147
- if (accept) input.accept = accept;
148
- if (multiple) input.multiple = multiple;
151
+ input.name = name!;
152
+ input.accept = accept;
153
+ input.multiple = multiple;
154
+ input.required = required!;
155
+ input.disabled = disabled!;
156
+ input.style.display = 'none'; // Hidden, triggered by button
149
157
 
150
158
  return input;
151
159
  }
152
160
 
161
+ private _updateFileList(): void {
162
+ if (!this._fileListElement) return; // Safety check
163
+
164
+ this._fileListElement.innerHTML = '';
165
+
166
+ if (this.state.files.length === 0) {
167
+ return;
168
+ }
169
+
170
+ this.state.files.forEach((file, index) => {
171
+ const fileItem = document.createElement('div');
172
+ fileItem.className = 'jux-fileupload-item';
173
+ fileItem.innerHTML = `
174
+ <span class="jux-fileupload-filename">${file.name}</span>
175
+ <span class="jux-fileupload-filesize">${this._formatFileSize(file.size)}</span>
176
+ <button class="jux-fileupload-remove" data-index="${index}">×</button>
177
+ `;
178
+
179
+ const removeBtn = fileItem.querySelector('.jux-fileupload-remove');
180
+ removeBtn?.addEventListener('click', () => {
181
+ this.state.files = this.state.files.filter((_, i) => i !== index);
182
+ this._updateFileList();
183
+ this._triggerCallback('change', this.state.files);
184
+ });
185
+
186
+ this._fileListElement!.appendChild(fileItem); // ✅ Non-null assertion safe here
187
+ });
188
+ }
189
+
190
+ private _formatFileSize(bytes: number): string {
191
+ if (bytes === 0) return '0 Bytes';
192
+ const k = 1024;
193
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
194
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
195
+ return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
196
+ }
197
+
153
198
  /* ═════════════════════════════════════════════════════════════════
154
199
  * RENDER
155
200
  * ═════════════════════════════════════════════════════════════════ */
@@ -191,7 +236,7 @@ export class FileUpload extends FormInput<FileUploadState> {
191
236
  button.type = 'button';
192
237
  button.className = 'jux-fileupload-button';
193
238
  button.textContent = 'Choose File(s)';
194
- button.disabled = this.state.disabled;
239
+ button.disabled = this.state.disabled!;
195
240
 
196
241
  buttonContainer.appendChild(button);
197
242
  wrapper.appendChild(buttonContainer);
@@ -236,7 +281,7 @@ export class FileUpload extends FormInput<FileUploadState> {
236
281
 
237
282
  const files = Array.from(inputEl.files || []);
238
283
  this.state.files = files;
239
- this._updateFileList(files);
284
+ this._updateFileList();
240
285
  this._clearError();
241
286
 
242
287
  const transformed = transformToState(files);
@@ -253,7 +298,7 @@ export class FileUpload extends FormInput<FileUploadState> {
253
298
  inputEl.addEventListener('change', () => {
254
299
  const files = Array.from(inputEl.files || []);
255
300
  this.state.files = files;
256
- this._updateFileList(files);
301
+ this._updateFileList();
257
302
  this._clearError();
258
303
 
259
304
  // 🎯 Fire the callback events
@@ -264,7 +309,9 @@ export class FileUpload extends FormInput<FileUploadState> {
264
309
 
265
310
  // Always add blur validation
266
311
  inputEl.addEventListener('blur', () => {
267
- this.validate();
312
+ if (this._hasBeenValidated) {
313
+ this.validate();
314
+ }
268
315
  });
269
316
 
270
317
  // Sync label changes
@@ -277,31 +324,14 @@ export class FileUpload extends FormInput<FileUploadState> {
277
324
  }
278
325
 
279
326
  container.appendChild(wrapper);
280
- return this;
281
- }
282
327
 
283
- private _updateFileList(files: File[]): void {
284
- if (!this._fileListElement) return;
285
-
286
- this._fileListElement.innerHTML = '';
287
-
288
- if (files.length === 0) {
289
- this._fileListElement.textContent = 'No files selected';
290
- return;
291
- }
292
-
293
- files.forEach(file => {
294
- const fileItem = document.createElement('div');
295
- fileItem.className = 'jux-fileupload-item';
296
- fileItem.textContent = `${file.name} (${this._formatFileSize(file.size)})`;
297
- this._fileListElement!.appendChild(fileItem);
328
+ requestAnimationFrame(() => {
329
+ if ((window as any).lucide) {
330
+ (window as any).lucide.createIcons();
331
+ }
298
332
  });
299
- }
300
333
 
301
- private _formatFileSize(bytes: number): string {
302
- if (bytes < 1024) return `${bytes} B`;
303
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
304
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
334
+ return this;
305
335
  }
306
336
  }
307
337
 
@@ -1,5 +1,4 @@
1
- import { FormInput, FormInputState } from './base/FormInput.js';
2
- import { BaseComponent } from './base/BaseComponent.js';
1
+ import { BaseComponent, BaseState } from './base/BaseComponent.js';
3
2
  export interface InputOptions {
4
3
  type?: string;
5
4
  value?: string;
@@ -20,7 +19,7 @@ export interface InputOptions {
20
19
  style?: string;
21
20
  class?: string;
22
21
  }
23
- interface InputState extends FormInputState {
22
+ interface InputState extends BaseState {
24
23
  type: string;
25
24
  value: string;
26
25
  placeholder: string;
@@ -33,7 +32,7 @@ interface InputState extends FormInputState {
33
32
  maxLength?: number;
34
33
  pattern?: string;
35
34
  }
36
- export declare class Input extends FormInput<InputState> {
35
+ export declare class Input extends BaseComponent<InputState> {
37
36
  constructor(id: string, options?: InputOptions);
38
37
  protected getTriggerEvents(): readonly string[];
39
38
  protected getCallbackEvents(): readonly string[];
@@ -51,6 +50,8 @@ export declare class Input extends FormInput<InputState> {
51
50
  getValue(): string;
52
51
  setValue(value: string): this;
53
52
  getNumericValue(): number | null;
53
+ validate(): boolean;
54
+ isValid(): boolean;
54
55
  protected _validateValue(value: string): boolean | string;
55
56
  protected _buildInputElement(): HTMLElement;
56
57
  render(targetId?: string | HTMLElement | BaseComponent<any>): this;
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["input.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["input.ts"],"names":[],"mappings":"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"}
@@ -1,29 +1,36 @@
1
- import { FormInput } from './base/FormInput.js';
1
+ import { BaseComponent } from './base/BaseComponent.js';
2
2
  import { renderIcon } from './icons.js';
3
+ import { formatIdAsLabel } from '../utils/formatId.js'; // ✅ Import
3
4
  // Event definitions
4
5
  const TRIGGER_EVENTS = [];
5
6
  const CALLBACK_EVENTS = ['change', 'input'];
6
- export class Input extends FormInput {
7
+ export class Input extends BaseComponent {
7
8
  constructor(id, options = {}) {
8
9
  super(id, {
10
+ // ✅ BaseState properties
11
+ visible: true,
12
+ disabled: options.disabled ?? false,
13
+ loading: false,
14
+ class: options.class ?? '',
15
+ style: options.style ?? '',
16
+ attributes: {},
17
+ // ✅ Form-specific BaseState properties
18
+ label: options.label ?? formatIdAsLabel(id), // ✅ Auto-generate if not provided
19
+ required: options.required ?? false,
20
+ name: options.name ?? id,
21
+ errorMessage: undefined,
22
+ // ✅ Input-specific properties
9
23
  type: options.type ?? 'text',
10
24
  value: options.value ?? '',
11
25
  placeholder: options.placeholder ?? '',
12
- label: options.label ?? '', // ✅ Empty string = auto-generate in _renderLabel()
13
26
  icon: options.icon ?? '',
14
- required: options.required ?? false,
15
- disabled: options.disabled ?? false,
16
- name: options.name ?? id,
17
27
  rows: options.rows ?? 3,
18
28
  min: options.min,
19
29
  max: options.max,
20
30
  step: options.step,
21
31
  minLength: options.minLength,
22
32
  maxLength: options.maxLength,
23
- pattern: options.pattern,
24
- style: options.style ?? '',
25
- class: options.class ?? '',
26
- errorMessage: undefined
33
+ pattern: options.pattern
27
34
  });
28
35
  if (options.onValidate) {
29
36
  this._onValidate = options.onValidate;
@@ -38,12 +45,6 @@ export class Input extends FormInput {
38
45
  /* ═════════════════════════════════════════════════════════════════
39
46
  * FLUENT API
40
47
  * ═════════════════════════════════════════════════════════════════ */
41
- // ✅ Inherited from FormInput/BaseComponent:
42
- // - label(), required(), name(), onValidate()
43
- // - validate(), isValid()
44
- // - style(), class()
45
- // - bind(), sync(), renderTo()
46
- // - disabled(), enable(), disable()
47
48
  type(value) {
48
49
  this.state.type = value;
49
50
  return this;
@@ -88,7 +89,7 @@ export class Input extends FormInput {
88
89
  return this;
89
90
  }
90
91
  /* ═════════════════════════════════════════════════════════════════
91
- * FORM INPUT IMPLEMENTATION
92
+ * FORM INPUT IMPLEMENTATION (Override BaseComponent methods)
92
93
  * ═════════════════════════════════════════════════════════════════ */
93
94
  getValue() {
94
95
  return this.state.value;
@@ -104,6 +105,23 @@ export class Input extends FormInput {
104
105
  const num = Number(this.state.value);
105
106
  return isNaN(num) ? null : num;
106
107
  }
108
+ validate() {
109
+ this._hasBeenValidated = true;
110
+ const value = this.getValue();
111
+ const result = this._validateValue(value);
112
+ if (result === true) {
113
+ this._clearError();
114
+ return true;
115
+ }
116
+ else {
117
+ this._showError(result);
118
+ return false;
119
+ }
120
+ }
121
+ isValid() {
122
+ const value = this.getValue();
123
+ return this._validateValue(value) === true;
124
+ }
107
125
  _validateValue(value) {
108
126
  const { required, type, min, max, minLength, maxLength, pattern } = this.state;
109
127
  if (required && !value.trim()) {
@@ -188,7 +206,7 @@ export class Input extends FormInput {
188
206
  * ═════════════════════════════════════════════════════════════════ */
189
207
  render(targetId) {
190
208
  const container = this._setupContainer(targetId);
191
- const { icon, maxLength, type, style, class: className } = this.state;
209
+ const { icon, maxLength, type, style, class: className, label } = this.state;
192
210
  // Build wrapper
193
211
  const wrapper = document.createElement('div');
194
212
  wrapper.className = 'jux-input';
@@ -197,8 +215,8 @@ export class Input extends FormInput {
197
215
  wrapper.className += ` ${className}`;
198
216
  if (style)
199
217
  wrapper.setAttribute('style', style);
200
- // Label
201
- if (this.state.label) {
218
+ // Label - always render if exists or can be auto-generated
219
+ if (label || !label) { // Always render label
202
220
  wrapper.appendChild(this._renderLabel());
203
221
  }
204
222
  // Input container
@@ -231,23 +249,19 @@ export class Input extends FormInput {
231
249
  const input = inputEl;
232
250
  counterEl.textContent = `${input.value.length}/${maxLength}`;
233
251
  this.state.value = input.value;
234
- // 🎯 Fire the input callback event
235
252
  this._triggerCallback('input', input.value);
236
253
  });
237
254
  }
238
255
  else {
239
- // Fire input event even without counter
240
256
  inputEl.addEventListener('input', () => {
241
257
  const input = inputEl;
242
258
  this.state.value = input.value;
243
- // 🎯 Fire the input callback event
244
259
  this._triggerCallback('input', input.value);
245
260
  });
246
261
  }
247
262
  // Fire change event on blur
248
263
  inputEl.addEventListener('change', () => {
249
264
  const input = inputEl;
250
- // 🎯 Fire the change callback event
251
265
  this._triggerCallback('change', input.value);
252
266
  });
253
267
  // Wire events