juxscript 1.1.80 → 1.1.82
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/paragraph.d.ts +8 -0
- package/lib/components/paragraph.d.ts.map +1 -1
- package/lib/components/paragraph.js +33 -2
- package/lib/components/paragraph.ts +37 -2
- 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/lib/components/select.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
import {
|
|
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 = ['change'];
|
|
5
|
-
export class Select extends
|
|
6
|
+
export class Select extends BaseComponent {
|
|
6
7
|
constructor(id, options = {}) {
|
|
7
8
|
super(id, {
|
|
8
|
-
|
|
9
|
-
value: options.value ?? '',
|
|
10
|
-
placeholder: options.placeholder ?? 'Select an option',
|
|
11
|
-
label: options.label ?? '',
|
|
12
|
-
required: options.required ?? false,
|
|
9
|
+
visible: true,
|
|
13
10
|
disabled: options.disabled ?? false,
|
|
14
|
-
|
|
15
|
-
style: options.style ?? '',
|
|
11
|
+
loading: false,
|
|
16
12
|
class: options.class ?? '',
|
|
17
|
-
|
|
13
|
+
style: options.style ?? '',
|
|
14
|
+
attributes: {},
|
|
15
|
+
label: options.label ?? formatIdAsLabel(id), // ✅ Auto-generate
|
|
16
|
+
required: options.required ?? false,
|
|
17
|
+
name: options.name ?? id,
|
|
18
|
+
errorMessage: undefined,
|
|
19
|
+
options: options.options ?? [],
|
|
20
|
+
value: options.value ?? '',
|
|
21
|
+
placeholder: options.placeholder ?? 'Select an option'
|
|
18
22
|
});
|
|
19
23
|
if (options.onValidate) {
|
|
20
24
|
this._onValidate = options.onValidate;
|
|
@@ -29,7 +33,7 @@ export class Select extends FormInput {
|
|
|
29
33
|
/* ═════════════════════════════════════════════════════════════════
|
|
30
34
|
* FLUENT API
|
|
31
35
|
* ═════════════════════════════════════════════════════════════════ */
|
|
32
|
-
//
|
|
36
|
+
// BaseComponent:
|
|
33
37
|
// - label(), required(), name(), onValidate()
|
|
34
38
|
// - validate(), isValid()
|
|
35
39
|
// - style(), class()
|
|
@@ -63,6 +67,23 @@ export class Select extends FormInput {
|
|
|
63
67
|
}
|
|
64
68
|
return this;
|
|
65
69
|
}
|
|
70
|
+
validate() {
|
|
71
|
+
this._hasBeenValidated = true;
|
|
72
|
+
const value = this.getValue();
|
|
73
|
+
const result = this._validateValue(value);
|
|
74
|
+
if (result === true) {
|
|
75
|
+
this._clearError();
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this._showError(result);
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
isValid() {
|
|
84
|
+
const value = this.getValue();
|
|
85
|
+
return this._validateValue(value) === true;
|
|
86
|
+
}
|
|
66
87
|
_validateValue(value) {
|
|
67
88
|
const { required, options } = this.state;
|
|
68
89
|
if (required && !value) {
|
package/lib/components/select.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { BaseComponent, BaseState } from './base/BaseComponent.js';
|
|
2
|
+
import { formatIdAsLabel } from '../utils/formatId.js'; // ✅ Import
|
|
3
3
|
|
|
4
4
|
// Event definitions
|
|
5
5
|
const TRIGGER_EVENTS = [] as const;
|
|
@@ -24,25 +24,28 @@ export interface SelectOptions {
|
|
|
24
24
|
onValidate?: (value: string) => boolean | string;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
interface SelectState extends
|
|
27
|
+
interface SelectState extends BaseState {
|
|
28
28
|
options: SelectOption[];
|
|
29
29
|
value: string;
|
|
30
30
|
placeholder: string;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export class Select extends
|
|
33
|
+
export class Select extends BaseComponent<SelectState> {
|
|
34
34
|
constructor(id: string, options: SelectOptions = {}) {
|
|
35
35
|
super(id, {
|
|
36
|
-
|
|
37
|
-
value: options.value ?? '',
|
|
38
|
-
placeholder: options.placeholder ?? 'Select an option',
|
|
39
|
-
label: options.label ?? '',
|
|
40
|
-
required: options.required ?? false,
|
|
36
|
+
visible: true,
|
|
41
37
|
disabled: options.disabled ?? false,
|
|
42
|
-
|
|
43
|
-
style: options.style ?? '',
|
|
38
|
+
loading: false,
|
|
44
39
|
class: options.class ?? '',
|
|
45
|
-
|
|
40
|
+
style: options.style ?? '',
|
|
41
|
+
attributes: {},
|
|
42
|
+
label: options.label ?? formatIdAsLabel(id), // ✅ Auto-generate
|
|
43
|
+
required: options.required ?? false,
|
|
44
|
+
name: options.name ?? id,
|
|
45
|
+
errorMessage: undefined,
|
|
46
|
+
options: options.options ?? [],
|
|
47
|
+
value: options.value ?? '',
|
|
48
|
+
placeholder: options.placeholder ?? 'Select an option'
|
|
46
49
|
});
|
|
47
50
|
|
|
48
51
|
if (options.onValidate) {
|
|
@@ -62,7 +65,7 @@ export class Select extends FormInput<SelectState> {
|
|
|
62
65
|
* FLUENT API
|
|
63
66
|
* ═════════════════════════════════════════════════════════════════ */
|
|
64
67
|
|
|
65
|
-
//
|
|
68
|
+
// BaseComponent:
|
|
66
69
|
// - label(), required(), name(), onValidate()
|
|
67
70
|
// - validate(), isValid()
|
|
68
71
|
// - style(), class()
|
|
@@ -106,6 +109,25 @@ export class Select extends FormInput<SelectState> {
|
|
|
106
109
|
return this;
|
|
107
110
|
}
|
|
108
111
|
|
|
112
|
+
validate(): boolean {
|
|
113
|
+
this._hasBeenValidated = true;
|
|
114
|
+
const value = this.getValue();
|
|
115
|
+
const result = this._validateValue(value);
|
|
116
|
+
|
|
117
|
+
if (result === true) {
|
|
118
|
+
this._clearError();
|
|
119
|
+
return true;
|
|
120
|
+
} else {
|
|
121
|
+
this._showError(result as string);
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
isValid(): boolean {
|
|
127
|
+
const value = this.getValue();
|
|
128
|
+
return this._validateValue(value) === true;
|
|
129
|
+
}
|
|
130
|
+
|
|
109
131
|
protected _validateValue(value: string): boolean | string {
|
|
110
132
|
const { required, options } = this.state;
|
|
111
133
|
|
|
@@ -134,9 +156,9 @@ export class Select extends FormInput<SelectState> {
|
|
|
134
156
|
const select = document.createElement('select');
|
|
135
157
|
select.className = 'jux-input-element jux-select-element';
|
|
136
158
|
select.id = `${this._id}-input`;
|
|
137
|
-
select.name = name
|
|
138
|
-
select.required = required
|
|
139
|
-
select.disabled = disabled
|
|
159
|
+
select.name = name!;
|
|
160
|
+
select.required = required!;
|
|
161
|
+
select.disabled = disabled!;
|
|
140
162
|
|
|
141
163
|
// Placeholder option
|
|
142
164
|
if (placeholder) {
|
|
@@ -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 SwitchOptions {
|
|
4
3
|
checked?: boolean;
|
|
5
4
|
label?: string;
|
|
@@ -11,11 +10,11 @@ export interface SwitchOptions {
|
|
|
11
10
|
class?: string;
|
|
12
11
|
onValidate?: (checked: boolean) => boolean | string;
|
|
13
12
|
}
|
|
14
|
-
interface SwitchState extends
|
|
13
|
+
interface SwitchState extends BaseState {
|
|
15
14
|
checked: boolean;
|
|
16
15
|
value: string;
|
|
17
16
|
}
|
|
18
|
-
export declare class Switch extends
|
|
17
|
+
export declare class Switch extends BaseComponent<SwitchState> {
|
|
19
18
|
constructor(id: string, options?: SwitchOptions);
|
|
20
19
|
protected getTriggerEvents(): readonly string[];
|
|
21
20
|
protected getCallbackEvents(): readonly string[];
|
|
@@ -24,9 +23,11 @@ export declare class Switch extends FormInput<SwitchState> {
|
|
|
24
23
|
toggle(): this;
|
|
25
24
|
getValue(): boolean;
|
|
26
25
|
setValue(value: boolean): this;
|
|
26
|
+
validate(): boolean;
|
|
27
27
|
protected _validateValue(checked: boolean): boolean | string;
|
|
28
28
|
protected _buildInputElement(): HTMLElement;
|
|
29
29
|
render(targetId?: string | HTMLElement | BaseComponent<any>): this;
|
|
30
|
+
isValid(): boolean;
|
|
30
31
|
}
|
|
31
32
|
export declare function switchComponent(id: string, options?: SwitchOptions): Switch;
|
|
32
33
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAOnE,MAAM,WAAW,aAAa;IAC1B,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,WAAY,SAAQ,SAAS;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,MAAO,SAAQ,aAAa,CAAC,WAAW,CAAC;gBACtC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB;IAqBnD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAehD,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI7B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1B,MAAM,IAAI,IAAI;IAQd,QAAQ,IAAI,OAAO;IAInB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAQ9B,QAAQ,IAAI,OAAO;IAenB,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;IAoHlE,OAAO,IAAI,OAAO;CAIrB;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAE/E"}
|
package/lib/components/switch.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
import {
|
|
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 = ['change'];
|
|
5
|
-
export class Switch extends
|
|
6
|
+
export class Switch extends BaseComponent {
|
|
6
7
|
constructor(id, options = {}) {
|
|
7
8
|
super(id, {
|
|
8
|
-
|
|
9
|
-
value: options.value ?? 'on',
|
|
10
|
-
label: options.label ?? '',
|
|
11
|
-
required: options.required ?? false,
|
|
9
|
+
visible: true,
|
|
12
10
|
disabled: options.disabled ?? false,
|
|
13
|
-
|
|
14
|
-
style: options.style ?? '',
|
|
11
|
+
loading: false,
|
|
15
12
|
class: options.class ?? '',
|
|
16
|
-
|
|
13
|
+
style: options.style ?? '',
|
|
14
|
+
attributes: {},
|
|
15
|
+
label: options.label ?? formatIdAsLabel(id), // ✅ Auto-generate
|
|
16
|
+
required: options.required ?? false,
|
|
17
|
+
name: options.name ?? id,
|
|
18
|
+
errorMessage: undefined,
|
|
19
|
+
checked: options.checked ?? false,
|
|
20
|
+
value: options.value ?? 'on'
|
|
17
21
|
});
|
|
18
22
|
if (options.onValidate) {
|
|
19
23
|
this._onValidate = options.onValidate;
|
|
@@ -28,7 +32,7 @@ export class Switch extends FormInput {
|
|
|
28
32
|
/* ═════════════════════════════════════════════════════════════════
|
|
29
33
|
* FLUENT API
|
|
30
34
|
* ═════════════════════════════════════════════════════════════════ */
|
|
31
|
-
//
|
|
35
|
+
// BaseComponent:
|
|
32
36
|
// - label(), required(), name(), onValidate()
|
|
33
37
|
// - validate(), isValid()
|
|
34
38
|
// - style(), class()
|
|
@@ -57,6 +61,19 @@ export class Switch extends FormInput {
|
|
|
57
61
|
}
|
|
58
62
|
return this;
|
|
59
63
|
}
|
|
64
|
+
validate() {
|
|
65
|
+
this._hasBeenValidated = true;
|
|
66
|
+
const checked = this.getValue();
|
|
67
|
+
const result = this._validateValue(checked);
|
|
68
|
+
if (result === true) {
|
|
69
|
+
this._clearError();
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
this._showError(result);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
60
77
|
_validateValue(checked) {
|
|
61
78
|
const { required } = this.state;
|
|
62
79
|
if (required && !checked) {
|
|
@@ -167,7 +184,9 @@ export class Switch extends FormInput {
|
|
|
167
184
|
}
|
|
168
185
|
// Always add blur validation
|
|
169
186
|
inputEl.addEventListener('blur', () => {
|
|
170
|
-
this.
|
|
187
|
+
if (this._hasBeenValidated) {
|
|
188
|
+
this.validate();
|
|
189
|
+
}
|
|
171
190
|
});
|
|
172
191
|
// Sync label changes
|
|
173
192
|
const labelSync = this._syncBindings.find(b => b.property === 'label');
|
|
@@ -180,6 +199,10 @@ export class Switch extends FormInput {
|
|
|
180
199
|
container.appendChild(wrapper);
|
|
181
200
|
return this;
|
|
182
201
|
}
|
|
202
|
+
isValid() {
|
|
203
|
+
const checked = this.getValue();
|
|
204
|
+
return this._validateValue(checked) === true;
|
|
205
|
+
}
|
|
183
206
|
}
|
|
184
207
|
export function switchComponent(id, options = {}) {
|
|
185
208
|
return new Switch(id, options);
|
package/lib/components/switch.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { BaseComponent, BaseState } from './base/BaseComponent.js';
|
|
2
|
+
import { formatIdAsLabel } from '../utils/formatId.js'; // ✅ Import
|
|
3
|
+
|
|
3
4
|
// Event definitions
|
|
4
5
|
const TRIGGER_EVENTS = [] as const;
|
|
5
6
|
const CALLBACK_EVENTS = ['change'] as const;
|
|
@@ -16,23 +17,26 @@ export interface SwitchOptions {
|
|
|
16
17
|
onValidate?: (checked: boolean) => boolean | string;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
interface SwitchState extends
|
|
20
|
+
interface SwitchState extends BaseState {
|
|
20
21
|
checked: boolean;
|
|
21
22
|
value: string;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
export class Switch extends
|
|
25
|
+
export class Switch extends BaseComponent<SwitchState> {
|
|
25
26
|
constructor(id: string, options: SwitchOptions = {}) {
|
|
26
27
|
super(id, {
|
|
27
|
-
|
|
28
|
-
value: options.value ?? 'on',
|
|
29
|
-
label: options.label ?? '',
|
|
30
|
-
required: options.required ?? false,
|
|
28
|
+
visible: true,
|
|
31
29
|
disabled: options.disabled ?? false,
|
|
32
|
-
|
|
33
|
-
style: options.style ?? '',
|
|
30
|
+
loading: false,
|
|
34
31
|
class: options.class ?? '',
|
|
35
|
-
|
|
32
|
+
style: options.style ?? '',
|
|
33
|
+
attributes: {},
|
|
34
|
+
label: options.label ?? formatIdAsLabel(id), // ✅ Auto-generate
|
|
35
|
+
required: options.required ?? false,
|
|
36
|
+
name: options.name ?? id,
|
|
37
|
+
errorMessage: undefined,
|
|
38
|
+
checked: options.checked ?? false,
|
|
39
|
+
value: options.value ?? 'on'
|
|
36
40
|
});
|
|
37
41
|
|
|
38
42
|
if (options.onValidate) {
|
|
@@ -52,7 +56,7 @@ export class Switch extends FormInput<SwitchState> {
|
|
|
52
56
|
* FLUENT API
|
|
53
57
|
* ═════════════════════════════════════════════════════════════════ */
|
|
54
58
|
|
|
55
|
-
//
|
|
59
|
+
// BaseComponent:
|
|
56
60
|
// - label(), required(), name(), onValidate()
|
|
57
61
|
// - validate(), isValid()
|
|
58
62
|
// - style(), class()
|
|
@@ -88,6 +92,21 @@ export class Switch extends FormInput<SwitchState> {
|
|
|
88
92
|
return this;
|
|
89
93
|
}
|
|
90
94
|
|
|
95
|
+
validate(): boolean {
|
|
96
|
+
this._hasBeenValidated = true;
|
|
97
|
+
const checked = this.getValue();
|
|
98
|
+
const result = this._validateValue(checked);
|
|
99
|
+
|
|
100
|
+
if (result === true) {
|
|
101
|
+
this._clearError();
|
|
102
|
+
return true;
|
|
103
|
+
} else {
|
|
104
|
+
this._showError(result as string);
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
91
110
|
protected _validateValue(checked: boolean): boolean | string {
|
|
92
111
|
const { required } = this.state;
|
|
93
112
|
|
|
@@ -112,11 +131,11 @@ export class Switch extends FormInput<SwitchState> {
|
|
|
112
131
|
input.type = 'checkbox';
|
|
113
132
|
input.className = 'jux-switch-input';
|
|
114
133
|
input.id = `${this._id}-input`;
|
|
115
|
-
input.name = name
|
|
134
|
+
input.name = name!;
|
|
116
135
|
input.value = value;
|
|
117
136
|
input.checked = checked;
|
|
118
|
-
input.required = required
|
|
119
|
-
input.disabled = disabled
|
|
137
|
+
input.required = required!;
|
|
138
|
+
input.disabled = disabled!;
|
|
120
139
|
|
|
121
140
|
return input;
|
|
122
141
|
}
|
|
@@ -222,7 +241,9 @@ export class Switch extends FormInput<SwitchState> {
|
|
|
222
241
|
|
|
223
242
|
// Always add blur validation
|
|
224
243
|
inputEl.addEventListener('blur', () => {
|
|
225
|
-
this.
|
|
244
|
+
if (this._hasBeenValidated) {
|
|
245
|
+
this.validate();
|
|
246
|
+
}
|
|
226
247
|
});
|
|
227
248
|
|
|
228
249
|
// Sync label changes
|
|
@@ -238,6 +259,11 @@ export class Switch extends FormInput<SwitchState> {
|
|
|
238
259
|
|
|
239
260
|
return this;
|
|
240
261
|
}
|
|
262
|
+
|
|
263
|
+
isValid(): boolean {
|
|
264
|
+
const checked = this.getValue();
|
|
265
|
+
return this._validateValue(checked) === true;
|
|
266
|
+
}
|
|
241
267
|
}
|
|
242
268
|
|
|
243
269
|
export function switchComponent(id: string, options: SwitchOptions = {}): Switch {
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { BaseComponent } from "./base/BaseComponent.js";
|
|
2
|
+
/**
|
|
3
|
+
* 🔍 WATCHER - Simple Component Observer
|
|
4
|
+
*
|
|
5
|
+
* Watches JUX components and fires callbacks when their state changes.
|
|
6
|
+
* Think of it as a "subscribe to component updates" utility.
|
|
7
|
+
*
|
|
8
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
9
|
+
* BASIC USAGE
|
|
10
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
11
|
+
*
|
|
12
|
+
* ```javascript
|
|
13
|
+
* import { input, paragraph, watcher } from 'juxscript';
|
|
14
|
+
*
|
|
15
|
+
* const nameInput = input('name').render('app');
|
|
16
|
+
* const greeting = paragraph('greeting').render('app');
|
|
17
|
+
*
|
|
18
|
+
* // Watch nameInput and update greeting whenever it changes
|
|
19
|
+
* watcher('name-watcher')
|
|
20
|
+
* .watch(nameInput, () => {
|
|
21
|
+
* greeting.text(`Hello, ${nameInput.getValue()}!`);
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
26
|
+
* MULTIPLE COMPONENTS
|
|
27
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
28
|
+
*
|
|
29
|
+
* ```javascript
|
|
30
|
+
* const firstNameInput = input('firstName').render();
|
|
31
|
+
* const lastNameInput = input('lastName').render();
|
|
32
|
+
* const fullName = paragraph('fullName').render();
|
|
33
|
+
*
|
|
34
|
+
* const formWatcher = watcher('form');
|
|
35
|
+
*
|
|
36
|
+
* // Watch both inputs, same callback
|
|
37
|
+
* formWatcher
|
|
38
|
+
* .watch(firstNameInput, updateFullName)
|
|
39
|
+
* .watch(lastNameInput, updateFullName);
|
|
40
|
+
*
|
|
41
|
+
* function updateFullName() {
|
|
42
|
+
* const first = firstNameInput.getValue();
|
|
43
|
+
* const last = lastNameInput.getValue();
|
|
44
|
+
* fullName.text(`${first} ${last}`.trim());
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
49
|
+
* DECLARATIVE STYLE - Watch Many, Do One Thing
|
|
50
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
51
|
+
*
|
|
52
|
+
* ```javascript
|
|
53
|
+
* const price = input('price').render();
|
|
54
|
+
* const quantity = input('quantity').render();
|
|
55
|
+
* const discount = input('discount').render();
|
|
56
|
+
* const total = paragraph('total').render();
|
|
57
|
+
*
|
|
58
|
+
* // Update total whenever ANY input changes
|
|
59
|
+
* watcher('calculator')
|
|
60
|
+
* .watchMany([price, quantity, discount], () => {
|
|
61
|
+
* const p = parseFloat(price.getValue()) || 0;
|
|
62
|
+
* const q = parseInt(quantity.getValue()) || 0;
|
|
63
|
+
* const d = parseFloat(discount.getValue()) || 0;
|
|
64
|
+
*
|
|
65
|
+
* const subtotal = p * q;
|
|
66
|
+
* const finalTotal = subtotal - (subtotal * d / 100);
|
|
67
|
+
*
|
|
68
|
+
* total.text(`Total: $${finalTotal.toFixed(2)}`);
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
73
|
+
* STOP WATCHING
|
|
74
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
75
|
+
*
|
|
76
|
+
* ```javascript
|
|
77
|
+
* const myWatcher = watcher('temp');
|
|
78
|
+
* const myInput = input('field').render();
|
|
79
|
+
*
|
|
80
|
+
* const myCallback = () => console.log('Changed!');
|
|
81
|
+
*
|
|
82
|
+
* myWatcher.watch(myInput, myCallback);
|
|
83
|
+
*
|
|
84
|
+
* // Later: stop watching
|
|
85
|
+
* myWatcher.unwatch(myInput, myCallback);
|
|
86
|
+
*
|
|
87
|
+
* // Or stop watching ALL callbacks for this component
|
|
88
|
+
* myWatcher.unwatchAll(myInput);
|
|
89
|
+
*
|
|
90
|
+
* // Or clear everything
|
|
91
|
+
* myWatcher.clear();
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
95
|
+
* HOW IT WORKS
|
|
96
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
97
|
+
*
|
|
98
|
+
* 1. Watcher stores callbacks keyed by component._id
|
|
99
|
+
* 2. Component's Proxy detects state changes
|
|
100
|
+
* 3. Component calls watcher.notify(component) [if integrated]
|
|
101
|
+
* 4. Watcher runs all registered callbacks for that component
|
|
102
|
+
*
|
|
103
|
+
* Current limitation: Manual notification required. To auto-notify:
|
|
104
|
+
*
|
|
105
|
+
* ```javascript
|
|
106
|
+
* // In your component after state change:
|
|
107
|
+
* this._notifyWatchers();
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* Or integrate into BaseComponent.update():
|
|
111
|
+
*
|
|
112
|
+
* ```typescript
|
|
113
|
+
* update(prop: string, value: any): void {
|
|
114
|
+
* // ...existing update logic...
|
|
115
|
+
* this._watchers.forEach(w => w.notify(this));
|
|
116
|
+
* }
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export declare class Watcher {
|
|
120
|
+
private _id;
|
|
121
|
+
private _callbacks;
|
|
122
|
+
constructor(id: string);
|
|
123
|
+
/**
|
|
124
|
+
* Watch a component and run callback when it changes
|
|
125
|
+
*
|
|
126
|
+
* @param component - Component to watch
|
|
127
|
+
* @param callback - Function to run on change
|
|
128
|
+
* @returns this (for chaining)
|
|
129
|
+
*/
|
|
130
|
+
watch(component: BaseComponent<any>, callback: Function): this;
|
|
131
|
+
/**
|
|
132
|
+
* Watch multiple components with the same callback
|
|
133
|
+
*
|
|
134
|
+
* @param components - Array of components to watch
|
|
135
|
+
* @param callback - Function to run when ANY of them change
|
|
136
|
+
* @returns this (for chaining)
|
|
137
|
+
*/
|
|
138
|
+
watchMany(components: BaseComponent<any>[], callback: Function): this;
|
|
139
|
+
/**
|
|
140
|
+
* Stop watching a component (remove specific callback)
|
|
141
|
+
*
|
|
142
|
+
* @param component - Component to stop watching
|
|
143
|
+
* @param callback - Specific callback to remove
|
|
144
|
+
* @returns this (for chaining)
|
|
145
|
+
*/
|
|
146
|
+
unwatch(component: BaseComponent<any>, callback: Function): this;
|
|
147
|
+
/**
|
|
148
|
+
* Stop watching a component (remove ALL callbacks)
|
|
149
|
+
*
|
|
150
|
+
* @param component - Component to stop watching completely
|
|
151
|
+
* @returns this (for chaining)
|
|
152
|
+
*/
|
|
153
|
+
unwatchAll(component: BaseComponent<any>): this;
|
|
154
|
+
/**
|
|
155
|
+
* Notify all callbacks for a component (call this when component changes)
|
|
156
|
+
*
|
|
157
|
+
* @param component - Component that changed
|
|
158
|
+
* @param args - Optional arguments to pass to callbacks
|
|
159
|
+
*/
|
|
160
|
+
notify(component: BaseComponent<any>, ...args: any[]): void;
|
|
161
|
+
/**
|
|
162
|
+
* Clear all watched components and callbacks
|
|
163
|
+
*
|
|
164
|
+
* @returns this (for chaining)
|
|
165
|
+
*/
|
|
166
|
+
clear(): this;
|
|
167
|
+
/**
|
|
168
|
+
* Get list of component IDs being watched
|
|
169
|
+
*
|
|
170
|
+
* @returns Array of component IDs
|
|
171
|
+
*/
|
|
172
|
+
getWatchedIds(): string[];
|
|
173
|
+
/**
|
|
174
|
+
* Get count of callbacks for a component
|
|
175
|
+
*
|
|
176
|
+
* @param component - Component to check
|
|
177
|
+
* @returns Number of callbacks registered
|
|
178
|
+
*/
|
|
179
|
+
getCallbackCount(component: BaseComponent<any>): number;
|
|
180
|
+
/**
|
|
181
|
+
* Check if watching a component
|
|
182
|
+
*
|
|
183
|
+
* @param component - Component to check
|
|
184
|
+
* @returns true if watching this component
|
|
185
|
+
*/
|
|
186
|
+
isWatching(component: BaseComponent<any>): boolean;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Create a new watcher instance
|
|
190
|
+
*
|
|
191
|
+
* @param id - Unique identifier for this watcher
|
|
192
|
+
* @returns New Watcher instance
|
|
193
|
+
*/
|
|
194
|
+
export declare function watcher(id: string): Watcher;
|
|
195
|
+
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoHG;AAEH,qBAAa,OAAO;IAChB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,UAAU,CAAyC;gBAE/C,EAAE,EAAE,MAAM;IAItB;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAW9D;;;;;;OAMG;IACH,SAAS,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAKrE;;;;;;OAMG;IACH,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAgBhE;;;;;OAKG;IACH,UAAU,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IAK/C;;;;;OAKG;IACH,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAc3D;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAKb;;;;OAIG;IACH,aAAa,IAAI,MAAM,EAAE;IAIzB;;;;;OAKG;IACH,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,MAAM;IAIvD;;;;;OAKG;IACH,UAAU,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO;CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE3C"}
|