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.
- package/dom-structure-map.json +1 -1
- package/index.d.ts +2 -2
- package/index.d.ts.map +1 -1
- package/index.js +2 -2
- package/lib/components/badge.d.ts.map +1 -1
- package/lib/components/badge.js +2 -1
- package/lib/components/badge.ts +2 -1
- package/lib/components/base/BaseComponent.d.ts +55 -1
- package/lib/components/base/BaseComponent.d.ts.map +1 -1
- package/lib/components/base/BaseComponent.js +168 -2
- package/lib/components/base/BaseComponent.ts +203 -3
- package/lib/components/checkbox.d.ts +5 -4
- package/lib/components/checkbox.d.ts.map +1 -1
- package/lib/components/checkbox.js +33 -16
- package/lib/components/checkbox.ts +39 -22
- package/lib/components/datepicker.d.ts +5 -4
- package/lib/components/datepicker.d.ts.map +1 -1
- package/lib/components/datepicker.js +31 -16
- package/lib/components/datepicker.ts +37 -22
- package/lib/components/dropdown.d.ts.map +1 -1
- package/lib/components/dropdown.js +2 -1
- package/lib/components/dropdown.ts +2 -1
- package/lib/components/fileupload.d.ts +6 -6
- package/lib/components/fileupload.d.ts.map +1 -1
- package/lib/components/fileupload.js +77 -52
- package/lib/components/fileupload.ts +88 -58
- package/lib/components/input.d.ts +5 -4
- package/lib/components/input.d.ts.map +1 -1
- package/lib/components/input.js +38 -24
- package/lib/components/input.ts +48 -33
- package/lib/components/radio.d.ts +5 -4
- package/lib/components/radio.d.ts.map +1 -1
- package/lib/components/radio.js +37 -14
- package/lib/components/radio.ts +40 -16
- package/lib/components/select.d.ts +5 -4
- package/lib/components/select.d.ts.map +1 -1
- package/lib/components/select.js +32 -11
- package/lib/components/select.ts +38 -16
- package/lib/components/switch.d.ts +5 -4
- package/lib/components/switch.d.ts.map +1 -1
- package/lib/components/switch.js +34 -11
- package/lib/components/switch.ts +42 -16
- package/lib/components/watcher.d.ts +195 -0
- package/lib/components/watcher.d.ts.map +1 -0
- package/lib/components/watcher.js +241 -0
- package/lib/components/watcher.ts +261 -0
- package/package.json +1 -1
- package/lib/components/base/FormInput.d.ts +0 -77
- package/lib/components/base/FormInput.d.ts.map +0 -1
- package/lib/components/base/FormInput.js +0 -171
- package/lib/components/base/FormInput.ts +0 -237
- package/lib/components/event-chain.ts +0 -31
package/dom-structure-map.json
CHANGED
package/index.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ import { renderIcon, renderEmoji } from './lib/components/icons.js';
|
|
|
44
44
|
import { state } from './lib/reactivity/state.js';
|
|
45
45
|
import { registry } from './lib/components/registry.js';
|
|
46
46
|
import { stateHistory } from './lib/components/history/StateHistory.js';
|
|
47
|
-
import {
|
|
47
|
+
import { watcher } from './lib/components/watcher.js';
|
|
48
48
|
export { state, registry, stateHistory };
|
|
49
49
|
export declare const jux: {
|
|
50
50
|
alert: typeof alert;
|
|
@@ -199,6 +199,6 @@ export declare const jux: {
|
|
|
199
199
|
renderIcon: typeof renderIcon;
|
|
200
200
|
renderEmoji: typeof renderEmoji;
|
|
201
201
|
getOrCreateContainer: typeof getOrCreateContainer;
|
|
202
|
-
|
|
202
|
+
watcher: typeof watcher;
|
|
203
203
|
};
|
|
204
204
|
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
|
package/index.js
CHANGED
|
@@ -46,7 +46,7 @@ import { renderIcon, renderEmoji } from './lib/components/icons.js';
|
|
|
46
46
|
import { state } from './lib/reactivity/state.js';
|
|
47
47
|
import { registry } from './lib/components/registry.js'; // ✅ Import registry
|
|
48
48
|
import { stateHistory } from './lib/components/history/StateHistory.js'; // ✅ Import history
|
|
49
|
-
import {
|
|
49
|
+
import { watcher } from './lib/components/watcher.js';
|
|
50
50
|
export { state, registry, stateHistory }; // ✅ Export history
|
|
51
51
|
// Utilities
|
|
52
52
|
export const jux = {
|
|
@@ -97,5 +97,5 @@ export const jux = {
|
|
|
97
97
|
renderIcon,
|
|
98
98
|
renderEmoji,
|
|
99
99
|
getOrCreateContainer,
|
|
100
|
-
|
|
100
|
+
watcher
|
|
101
101
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAOnE,MAAM,WAAW,YAAY;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IAC/D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,UAAU,GAAG,SAAS,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,qBAAa,KAAM,SAAQ,aAAa,CAAC,UAAU,CAAC;gBACpC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB;IAUlD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAIhD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAwBtC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1B,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI;IAK1E,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAS1B,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;CA8BrE;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK,CAEnE"}
|
package/lib/components/badge.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
+
import { formatIdAsLabel } from '../utils/formatId.js'; // ✅ Import
|
|
2
3
|
// Event definitions
|
|
3
4
|
const TRIGGER_EVENTS = [];
|
|
4
5
|
const CALLBACK_EVENTS = [];
|
|
5
6
|
export class Badge extends BaseComponent {
|
|
6
7
|
constructor(id, options = {}) {
|
|
7
8
|
super(id, {
|
|
8
|
-
label: options.label ??
|
|
9
|
+
label: options.label ?? formatIdAsLabel(id), // ✅ Auto-generate from ID
|
|
9
10
|
variant: options.variant ?? 'default',
|
|
10
11
|
pill: options.pill ?? false,
|
|
11
12
|
style: options.style ?? '',
|
package/lib/components/badge.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseComponent, BaseState } from './base/BaseComponent.js';
|
|
2
|
+
import { formatIdAsLabel } from '../utils/formatId.js'; // ✅ Import
|
|
2
3
|
|
|
3
4
|
// Event definitions
|
|
4
5
|
const TRIGGER_EVENTS = [] as const;
|
|
@@ -21,7 +22,7 @@ type BadgeState = BaseState & {
|
|
|
21
22
|
export class Badge extends BaseComponent<BadgeState> {
|
|
22
23
|
constructor(id: string, options: BadgeOptions = {}) {
|
|
23
24
|
super(id, {
|
|
24
|
-
label: options.label ??
|
|
25
|
+
label: options.label ?? formatIdAsLabel(id), // ✅ Auto-generate from ID
|
|
25
26
|
variant: options.variant ?? 'default',
|
|
26
27
|
pill: options.pill ?? false,
|
|
27
28
|
style: options.style ?? '',
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { State } from '../../reactivity/state.js';
|
|
2
2
|
/**
|
|
3
3
|
* Base state interface that ALL component states must extend
|
|
4
|
-
* Contains properties managed by BaseComponent
|
|
5
4
|
*/
|
|
6
5
|
export interface BaseState {
|
|
7
6
|
visible?: boolean;
|
|
@@ -10,6 +9,10 @@ export interface BaseState {
|
|
|
10
9
|
class?: string;
|
|
11
10
|
style?: string;
|
|
12
11
|
attributes?: Record<string, string>;
|
|
12
|
+
label?: string;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
name?: string;
|
|
15
|
+
errorMessage?: string;
|
|
13
16
|
}
|
|
14
17
|
/**
|
|
15
18
|
* Abstract base class for all JUX components
|
|
@@ -38,6 +41,11 @@ export declare abstract class BaseComponent<TState extends BaseState = BaseState
|
|
|
38
41
|
protected _triggerHandlers: Map<string, Function>;
|
|
39
42
|
protected _callbackHandlers: Map<string, Function>;
|
|
40
43
|
protected _isUpdatingSync: boolean;
|
|
44
|
+
protected _inputElement: HTMLElement | null;
|
|
45
|
+
protected _labelElement: HTMLLabelElement | null;
|
|
46
|
+
protected _errorElement: HTMLElement | null;
|
|
47
|
+
protected _onValidate?: (value: any) => boolean | string;
|
|
48
|
+
protected _hasBeenValidated: boolean;
|
|
41
49
|
constructor(id: string, initialState: TState);
|
|
42
50
|
protected abstract getTriggerEvents(): readonly string[];
|
|
43
51
|
protected abstract getCallbackEvents(): readonly string[];
|
|
@@ -169,5 +177,51 @@ export declare abstract class BaseComponent<TState extends BaseState = BaseState
|
|
|
169
177
|
* const myState = component.props(); // ❌ Error: props is not a function
|
|
170
178
|
*/
|
|
171
179
|
get props(): Readonly<TState>;
|
|
180
|
+
/**
|
|
181
|
+
* Set label for form inputs
|
|
182
|
+
*/
|
|
183
|
+
label(value: string): this;
|
|
184
|
+
/**
|
|
185
|
+
* Set required state for form inputs
|
|
186
|
+
*/
|
|
187
|
+
required(value: boolean): this;
|
|
188
|
+
/**
|
|
189
|
+
* Set name attribute for form inputs
|
|
190
|
+
*/
|
|
191
|
+
name(value: string): this;
|
|
192
|
+
/**
|
|
193
|
+
* Set custom validation handler
|
|
194
|
+
*/
|
|
195
|
+
onValidate(handler: (value: any) => boolean | string): this;
|
|
196
|
+
/**
|
|
197
|
+
* Validate form input (override in form components)
|
|
198
|
+
*/
|
|
199
|
+
validate(): boolean;
|
|
200
|
+
/**
|
|
201
|
+
* Check if form input is valid (override in form components)
|
|
202
|
+
*/
|
|
203
|
+
isValid(): boolean;
|
|
204
|
+
/**
|
|
205
|
+
* Get current value (override in form components)
|
|
206
|
+
*/
|
|
207
|
+
getValue(): any;
|
|
208
|
+
/**
|
|
209
|
+
* Set current value (override in form components)
|
|
210
|
+
*/
|
|
211
|
+
setValue(value: any): this;
|
|
212
|
+
protected _showError(message: string): void;
|
|
213
|
+
protected _clearError(): void;
|
|
214
|
+
/**
|
|
215
|
+
* Build label element for form inputs
|
|
216
|
+
*/
|
|
217
|
+
protected _renderLabel(): HTMLLabelElement;
|
|
218
|
+
/**
|
|
219
|
+
* Build error element for form inputs
|
|
220
|
+
*/
|
|
221
|
+
protected _renderError(): HTMLElement;
|
|
222
|
+
/**
|
|
223
|
+
* Wire up two-way sync for form inputs
|
|
224
|
+
*/
|
|
225
|
+
protected _wireFormSync(inputElement: HTMLElement, eventName?: string): void;
|
|
172
226
|
}
|
|
173
227
|
//# sourceMappingURL=BaseComponent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseComponent.d.ts","sourceRoot":"","sources":["BaseComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"BaseComponent.d.ts","sourceRoot":"","sources":["BaseComponent.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getOrCreateContainer } from '../helpers.js';
|
|
2
2
|
import { registry } from '../registry.js';
|
|
3
|
-
import { stateHistory } from '../history/StateHistory.js';
|
|
3
|
+
import { stateHistory } from '../history/StateHistory.js';
|
|
4
|
+
import { formatIdAsLabel } from '../../utils/formatId.js'; // ✅ Import utility
|
|
4
5
|
/**
|
|
5
6
|
* Abstract base class for all JUX components
|
|
6
7
|
* Provides common storage, event routing, and lifecycle methods
|
|
@@ -18,7 +19,12 @@ export class BaseComponent {
|
|
|
18
19
|
this._syncBindings = [];
|
|
19
20
|
this._triggerHandlers = new Map();
|
|
20
21
|
this._callbackHandlers = new Map();
|
|
21
|
-
this._isUpdatingSync = false;
|
|
22
|
+
this._isUpdatingSync = false;
|
|
23
|
+
// Form-specific protected properties (only used by form components)
|
|
24
|
+
this._inputElement = null;
|
|
25
|
+
this._labelElement = null;
|
|
26
|
+
this._errorElement = null;
|
|
27
|
+
this._hasBeenValidated = false;
|
|
22
28
|
this._id = id;
|
|
23
29
|
this.id = id;
|
|
24
30
|
const stateWithDefaults = {
|
|
@@ -467,4 +473,164 @@ export class BaseComponent {
|
|
|
467
473
|
get props() {
|
|
468
474
|
return this.state;
|
|
469
475
|
}
|
|
476
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
477
|
+
* FORM INPUT API (Optional - only used by form components)
|
|
478
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
479
|
+
/**
|
|
480
|
+
* Set label for form inputs
|
|
481
|
+
*/
|
|
482
|
+
label(value) {
|
|
483
|
+
this.state.label = value;
|
|
484
|
+
if (this._labelElement) {
|
|
485
|
+
const requiredSpan = this._labelElement.querySelector('.jux-input-required');
|
|
486
|
+
this._labelElement.textContent = value;
|
|
487
|
+
if (requiredSpan)
|
|
488
|
+
this._labelElement.appendChild(requiredSpan);
|
|
489
|
+
}
|
|
490
|
+
return this;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Set required state for form inputs
|
|
494
|
+
*/
|
|
495
|
+
required(value) {
|
|
496
|
+
this.state.required = value;
|
|
497
|
+
return this;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Set name attribute for form inputs
|
|
501
|
+
*/
|
|
502
|
+
name(value) {
|
|
503
|
+
this.state.name = value;
|
|
504
|
+
return this;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Set custom validation handler
|
|
508
|
+
*/
|
|
509
|
+
onValidate(handler) {
|
|
510
|
+
this._onValidate = handler;
|
|
511
|
+
return this;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Validate form input (override in form components)
|
|
515
|
+
*/
|
|
516
|
+
validate() {
|
|
517
|
+
console.warn(`${this.constructor.name}.validate() not implemented`);
|
|
518
|
+
return true;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Check if form input is valid (override in form components)
|
|
522
|
+
*/
|
|
523
|
+
isValid() {
|
|
524
|
+
console.warn(`${this.constructor.name}.isValid() not implemented`);
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Get current value (override in form components)
|
|
529
|
+
*/
|
|
530
|
+
getValue() {
|
|
531
|
+
console.warn(`${this.constructor.name}.getValue() not implemented`);
|
|
532
|
+
return undefined;
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Set current value (override in form components)
|
|
536
|
+
*/
|
|
537
|
+
setValue(value) {
|
|
538
|
+
console.warn(`${this.constructor.name}.setValue() not implemented`);
|
|
539
|
+
return this;
|
|
540
|
+
}
|
|
541
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
542
|
+
* FORM VALIDATION HELPERS (Protected - for form components)
|
|
543
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
544
|
+
_showError(message) {
|
|
545
|
+
if (this._errorElement) {
|
|
546
|
+
this._errorElement.textContent = message;
|
|
547
|
+
this._errorElement.style.display = 'block';
|
|
548
|
+
}
|
|
549
|
+
if (this._inputElement) {
|
|
550
|
+
this._inputElement.classList.add('jux-input-invalid');
|
|
551
|
+
}
|
|
552
|
+
this.state.errorMessage = message;
|
|
553
|
+
}
|
|
554
|
+
_clearError() {
|
|
555
|
+
if (this._errorElement) {
|
|
556
|
+
this._errorElement.textContent = '';
|
|
557
|
+
this._errorElement.style.display = 'none';
|
|
558
|
+
}
|
|
559
|
+
if (this._inputElement) {
|
|
560
|
+
this._inputElement.classList.remove('jux-input-invalid');
|
|
561
|
+
}
|
|
562
|
+
this.state.errorMessage = undefined;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Build label element for form inputs
|
|
566
|
+
*/
|
|
567
|
+
_renderLabel() {
|
|
568
|
+
const label = this.state.label || formatIdAsLabel(this._id);
|
|
569
|
+
const required = this.state.required || false;
|
|
570
|
+
const labelEl = document.createElement('label');
|
|
571
|
+
labelEl.className = 'jux-input-label';
|
|
572
|
+
labelEl.htmlFor = `${this._id}-input`;
|
|
573
|
+
labelEl.textContent = label;
|
|
574
|
+
if (required) {
|
|
575
|
+
const requiredSpan = document.createElement('span');
|
|
576
|
+
requiredSpan.className = 'jux-input-required';
|
|
577
|
+
requiredSpan.textContent = ' *';
|
|
578
|
+
labelEl.appendChild(requiredSpan);
|
|
579
|
+
}
|
|
580
|
+
this._labelElement = labelEl;
|
|
581
|
+
return labelEl;
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Build error element for form inputs
|
|
585
|
+
*/
|
|
586
|
+
_renderError() {
|
|
587
|
+
const errorEl = document.createElement('div');
|
|
588
|
+
errorEl.className = 'jux-input-error';
|
|
589
|
+
errorEl.id = `${this._id}-error`;
|
|
590
|
+
errorEl.style.display = 'none';
|
|
591
|
+
this._errorElement = errorEl;
|
|
592
|
+
return errorEl;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Wire up two-way sync for form inputs
|
|
596
|
+
*/
|
|
597
|
+
_wireFormSync(inputElement, eventName = 'input') {
|
|
598
|
+
const valueSync = this._syncBindings.find(b => b.property === 'value');
|
|
599
|
+
if (valueSync) {
|
|
600
|
+
const { stateObj, toState, toComponent } = valueSync;
|
|
601
|
+
const transformToState = toState || ((v) => v);
|
|
602
|
+
const transformToComponent = toComponent || ((v) => v);
|
|
603
|
+
let isUpdating = false;
|
|
604
|
+
// State → Component
|
|
605
|
+
stateObj.subscribe((val) => {
|
|
606
|
+
if (isUpdating)
|
|
607
|
+
return;
|
|
608
|
+
const transformed = transformToComponent(val);
|
|
609
|
+
this.setValue(transformed);
|
|
610
|
+
});
|
|
611
|
+
// Component → State
|
|
612
|
+
inputElement.addEventListener(eventName, () => {
|
|
613
|
+
if (isUpdating)
|
|
614
|
+
return;
|
|
615
|
+
isUpdating = true;
|
|
616
|
+
const value = this.getValue();
|
|
617
|
+
const transformed = transformToState(value);
|
|
618
|
+
this._clearError();
|
|
619
|
+
stateObj.set(transformed);
|
|
620
|
+
setTimeout(() => { isUpdating = false; }, 0);
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
// Default behavior without sync
|
|
625
|
+
inputElement.addEventListener(eventName, () => {
|
|
626
|
+
this._clearError();
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
// Only validate on blur IF the field has been validated before
|
|
630
|
+
inputElement.addEventListener('blur', () => {
|
|
631
|
+
if (this._hasBeenValidated) {
|
|
632
|
+
this.validate();
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
}
|
|
470
636
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { State } from '../../reactivity/state.js';
|
|
2
2
|
import { getOrCreateContainer } from '../helpers.js';
|
|
3
3
|
import { registry } from '../registry.js';
|
|
4
|
-
import { stateHistory } from '../history/StateHistory.js';
|
|
4
|
+
import { stateHistory } from '../history/StateHistory.js';
|
|
5
|
+
import { formatIdAsLabel } from '../../utils/formatId.js'; // ✅ Import utility
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Base state interface that ALL component states must extend
|
|
8
|
-
* Contains properties managed by BaseComponent
|
|
9
9
|
*/
|
|
10
10
|
export interface BaseState {
|
|
11
11
|
visible?: boolean;
|
|
@@ -14,6 +14,11 @@ export interface BaseState {
|
|
|
14
14
|
class?: string;
|
|
15
15
|
style?: string;
|
|
16
16
|
attributes?: Record<string, string>;
|
|
17
|
+
// ✅ Form-specific properties (optional for all components)
|
|
18
|
+
label?: string;
|
|
19
|
+
required?: boolean;
|
|
20
|
+
name?: string;
|
|
21
|
+
errorMessage?: string;
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
/**
|
|
@@ -42,7 +47,14 @@ export abstract class BaseComponent<TState extends BaseState = BaseState> {
|
|
|
42
47
|
}> = [];
|
|
43
48
|
protected _triggerHandlers: Map<string, Function> = new Map();
|
|
44
49
|
protected _callbackHandlers: Map<string, Function> = new Map();
|
|
45
|
-
protected _isUpdatingSync: boolean = false;
|
|
50
|
+
protected _isUpdatingSync: boolean = false;
|
|
51
|
+
|
|
52
|
+
// Form-specific protected properties (only used by form components)
|
|
53
|
+
protected _inputElement: HTMLElement | null = null;
|
|
54
|
+
protected _labelElement: HTMLLabelElement | null = null;
|
|
55
|
+
protected _errorElement: HTMLElement | null = null;
|
|
56
|
+
protected _onValidate?: (value: any) => boolean | string;
|
|
57
|
+
protected _hasBeenValidated: boolean = false;
|
|
46
58
|
|
|
47
59
|
constructor(id: string, initialState: TState) {
|
|
48
60
|
this._id = id;
|
|
@@ -563,4 +575,192 @@ export abstract class BaseComponent<TState extends BaseState = BaseState> {
|
|
|
563
575
|
get props(): Readonly<TState> {
|
|
564
576
|
return this.state as Readonly<TState>;
|
|
565
577
|
}
|
|
578
|
+
|
|
579
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
580
|
+
* FORM INPUT API (Optional - only used by form components)
|
|
581
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Set label for form inputs
|
|
585
|
+
*/
|
|
586
|
+
label(value: string): this {
|
|
587
|
+
(this.state as any).label = value;
|
|
588
|
+
if (this._labelElement) {
|
|
589
|
+
const requiredSpan = this._labelElement.querySelector('.jux-input-required');
|
|
590
|
+
this._labelElement.textContent = value;
|
|
591
|
+
if (requiredSpan) this._labelElement.appendChild(requiredSpan);
|
|
592
|
+
}
|
|
593
|
+
return this;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Set required state for form inputs
|
|
598
|
+
*/
|
|
599
|
+
required(value: boolean): this {
|
|
600
|
+
(this.state as any).required = value;
|
|
601
|
+
return this;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Set name attribute for form inputs
|
|
606
|
+
*/
|
|
607
|
+
name(value: string): this {
|
|
608
|
+
(this.state as any).name = value;
|
|
609
|
+
return this;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Set custom validation handler
|
|
614
|
+
*/
|
|
615
|
+
onValidate(handler: (value: any) => boolean | string): this {
|
|
616
|
+
this._onValidate = handler;
|
|
617
|
+
return this;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Validate form input (override in form components)
|
|
622
|
+
*/
|
|
623
|
+
validate(): boolean {
|
|
624
|
+
console.warn(`${this.constructor.name}.validate() not implemented`);
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Check if form input is valid (override in form components)
|
|
630
|
+
*/
|
|
631
|
+
isValid(): boolean {
|
|
632
|
+
console.warn(`${this.constructor.name}.isValid() not implemented`);
|
|
633
|
+
return true;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Get current value (override in form components)
|
|
638
|
+
*/
|
|
639
|
+
getValue(): any {
|
|
640
|
+
console.warn(`${this.constructor.name}.getValue() not implemented`);
|
|
641
|
+
return undefined;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Set current value (override in form components)
|
|
646
|
+
*/
|
|
647
|
+
setValue(value: any): this {
|
|
648
|
+
console.warn(`${this.constructor.name}.setValue() not implemented`);
|
|
649
|
+
return this;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
653
|
+
* FORM VALIDATION HELPERS (Protected - for form components)
|
|
654
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
655
|
+
|
|
656
|
+
protected _showError(message: string): void {
|
|
657
|
+
if (this._errorElement) {
|
|
658
|
+
this._errorElement.textContent = message;
|
|
659
|
+
this._errorElement.style.display = 'block';
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (this._inputElement) {
|
|
663
|
+
this._inputElement.classList.add('jux-input-invalid');
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
(this.state as any).errorMessage = message;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
protected _clearError(): void {
|
|
670
|
+
if (this._errorElement) {
|
|
671
|
+
this._errorElement.textContent = '';
|
|
672
|
+
this._errorElement.style.display = 'none';
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
if (this._inputElement) {
|
|
676
|
+
this._inputElement.classList.remove('jux-input-invalid');
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
(this.state as any).errorMessage = undefined;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Build label element for form inputs
|
|
684
|
+
*/
|
|
685
|
+
protected _renderLabel(): HTMLLabelElement {
|
|
686
|
+
const label = (this.state as any).label || formatIdAsLabel(this._id);
|
|
687
|
+
const required = (this.state as any).required || false;
|
|
688
|
+
|
|
689
|
+
const labelEl = document.createElement('label');
|
|
690
|
+
labelEl.className = 'jux-input-label';
|
|
691
|
+
labelEl.htmlFor = `${this._id}-input`;
|
|
692
|
+
labelEl.textContent = label;
|
|
693
|
+
|
|
694
|
+
if (required) {
|
|
695
|
+
const requiredSpan = document.createElement('span');
|
|
696
|
+
requiredSpan.className = 'jux-input-required';
|
|
697
|
+
requiredSpan.textContent = ' *';
|
|
698
|
+
labelEl.appendChild(requiredSpan);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
this._labelElement = labelEl;
|
|
702
|
+
return labelEl;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Build error element for form inputs
|
|
707
|
+
*/
|
|
708
|
+
protected _renderError(): HTMLElement {
|
|
709
|
+
const errorEl = document.createElement('div');
|
|
710
|
+
errorEl.className = 'jux-input-error';
|
|
711
|
+
errorEl.id = `${this._id}-error`;
|
|
712
|
+
errorEl.style.display = 'none';
|
|
713
|
+
|
|
714
|
+
this._errorElement = errorEl;
|
|
715
|
+
return errorEl;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Wire up two-way sync for form inputs
|
|
720
|
+
*/
|
|
721
|
+
protected _wireFormSync(inputElement: HTMLElement, eventName: string = 'input'): void {
|
|
722
|
+
const valueSync = this._syncBindings.find(b => b.property === 'value');
|
|
723
|
+
|
|
724
|
+
if (valueSync) {
|
|
725
|
+
const { stateObj, toState, toComponent } = valueSync;
|
|
726
|
+
|
|
727
|
+
const transformToState = toState || ((v: any) => v);
|
|
728
|
+
const transformToComponent = toComponent || ((v: any) => v);
|
|
729
|
+
|
|
730
|
+
let isUpdating = false;
|
|
731
|
+
|
|
732
|
+
// State → Component
|
|
733
|
+
stateObj.subscribe((val: any) => {
|
|
734
|
+
if (isUpdating) return;
|
|
735
|
+
const transformed = transformToComponent(val);
|
|
736
|
+
this.setValue(transformed);
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
// Component → State
|
|
740
|
+
inputElement.addEventListener(eventName, () => {
|
|
741
|
+
if (isUpdating) return;
|
|
742
|
+
isUpdating = true;
|
|
743
|
+
|
|
744
|
+
const value = this.getValue();
|
|
745
|
+
const transformed = transformToState(value);
|
|
746
|
+
this._clearError();
|
|
747
|
+
|
|
748
|
+
stateObj.set(transformed);
|
|
749
|
+
|
|
750
|
+
setTimeout(() => { isUpdating = false; }, 0);
|
|
751
|
+
});
|
|
752
|
+
} else {
|
|
753
|
+
// Default behavior without sync
|
|
754
|
+
inputElement.addEventListener(eventName, () => {
|
|
755
|
+
this._clearError();
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Only validate on blur IF the field has been validated before
|
|
760
|
+
inputElement.addEventListener('blur', () => {
|
|
761
|
+
if (this._hasBeenValidated) {
|
|
762
|
+
this.validate();
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
}
|
|
566
766
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BaseComponent } from './base/BaseComponent.js';
|
|
1
|
+
import { BaseComponent, BaseState } from './base/BaseComponent.js';
|
|
3
2
|
export interface CheckboxOptions {
|
|
4
3
|
checked?: boolean;
|
|
5
4
|
label?: string;
|
|
@@ -11,11 +10,11 @@ export interface CheckboxOptions {
|
|
|
11
10
|
class?: string;
|
|
12
11
|
onValidate?: (checked: boolean) => boolean | string;
|
|
13
12
|
}
|
|
14
|
-
interface CheckboxState extends
|
|
13
|
+
interface CheckboxState extends BaseState {
|
|
15
14
|
checked: boolean;
|
|
16
15
|
value: string;
|
|
17
16
|
}
|
|
18
|
-
export declare class Checkbox extends
|
|
17
|
+
export declare class Checkbox extends BaseComponent<CheckboxState> {
|
|
19
18
|
constructor(id: string, options?: CheckboxOptions);
|
|
20
19
|
protected getTriggerEvents(): readonly string[];
|
|
21
20
|
protected getCallbackEvents(): readonly string[];
|
|
@@ -23,6 +22,8 @@ export declare class Checkbox extends FormInput<CheckboxState> {
|
|
|
23
22
|
value(value: string): this;
|
|
24
23
|
getValue(): boolean;
|
|
25
24
|
setValue(value: boolean): this;
|
|
25
|
+
validate(): boolean;
|
|
26
|
+
isValid(): boolean;
|
|
26
27
|
protected _validateValue(checked: boolean): boolean | string;
|
|
27
28
|
protected _buildInputElement(): HTMLElement;
|
|
28
29
|
render(targetId?: string | HTMLElement | BaseComponent<any>): this;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.d.ts","sourceRoot":"","sources":["checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"checkbox.d.ts","sourceRoot":"","sources":["checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAQnE,MAAM,WAAW,eAAe;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAG,MAAM,CAAC;CACvD;AAED,UAAU,aAAc,SAAQ,SAAS;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,QAAS,SAAQ,aAAa,CAAC,aAAa,CAAC;gBAC1C,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;IAqBrD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAQhD,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI7B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAS1B,QAAQ,IAAI,OAAO;IAInB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAQ9B,QAAQ,IAAI,OAAO;IAcnB,OAAO,IAAI,OAAO;IAKlB,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM;IAiB5D,SAAS,CAAC,kBAAkB,IAAI,WAAW;IAoB3C,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;CAmHrE;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAE5E"}
|