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.
Files changed (56) 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/paragraph.d.ts +8 -0
  32. package/lib/components/paragraph.d.ts.map +1 -1
  33. package/lib/components/paragraph.js +33 -2
  34. package/lib/components/paragraph.ts +37 -2
  35. package/lib/components/radio.d.ts +5 -4
  36. package/lib/components/radio.d.ts.map +1 -1
  37. package/lib/components/radio.js +37 -14
  38. package/lib/components/radio.ts +40 -16
  39. package/lib/components/select.d.ts +5 -4
  40. package/lib/components/select.d.ts.map +1 -1
  41. package/lib/components/select.js +32 -11
  42. package/lib/components/select.ts +38 -16
  43. package/lib/components/switch.d.ts +5 -4
  44. package/lib/components/switch.d.ts.map +1 -1
  45. package/lib/components/switch.js +34 -11
  46. package/lib/components/switch.ts +42 -16
  47. package/lib/components/watcher.d.ts +195 -0
  48. package/lib/components/watcher.d.ts.map +1 -0
  49. package/lib/components/watcher.js +241 -0
  50. package/lib/components/watcher.ts +261 -0
  51. package/package.json +1 -1
  52. package/lib/components/base/FormInput.d.ts +0 -77
  53. package/lib/components/base/FormInput.d.ts.map +0 -1
  54. package/lib/components/base/FormInput.js +0 -171
  55. package/lib/components/base/FormInput.ts +0 -237
  56. package/lib/components/event-chain.ts +0 -31
@@ -1,20 +1,24 @@
1
- import { FormInput } from './base/FormInput.js';
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 FormInput {
6
+ export class Select extends BaseComponent {
6
7
  constructor(id, options = {}) {
7
8
  super(id, {
8
- options: options.options ?? [],
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
- name: options.name ?? id,
15
- style: options.style ?? '',
11
+ loading: false,
16
12
  class: options.class ?? '',
17
- errorMessage: undefined
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
- // ✅ Inherited from FormInput/BaseComponent:
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) {
@@ -1,5 +1,5 @@
1
- import { FormInput, FormInputState } from './base/FormInput.js';
2
- import { BaseComponent } from './base/BaseComponent.js';
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 FormInputState {
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 FormInput<SelectState> {
33
+ export class Select extends BaseComponent<SelectState> {
34
34
  constructor(id: string, options: SelectOptions = {}) {
35
35
  super(id, {
36
- options: options.options ?? [],
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
- name: options.name ?? id,
43
- style: options.style ?? '',
38
+ loading: false,
44
39
  class: options.class ?? '',
45
- errorMessage: undefined
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
- // ✅ Inherited from FormInput/BaseComponent:
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 { 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 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 FormInputState {
13
+ interface SwitchState extends BaseState {
15
14
  checked: boolean;
16
15
  value: string;
17
16
  }
18
- export declare class Switch extends FormInput<SwitchState> {
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,SAAS,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAKxD,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,cAAc;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,MAAO,SAAQ,SAAS,CAAC,WAAW,CAAC;gBAClC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB;IAkBnD,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,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;CAiHrE;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAE/E"}
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"}
@@ -1,19 +1,23 @@
1
- import { FormInput } from './base/FormInput.js';
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 FormInput {
6
+ export class Switch extends BaseComponent {
6
7
  constructor(id, options = {}) {
7
8
  super(id, {
8
- checked: options.checked ?? false,
9
- value: options.value ?? 'on',
10
- label: options.label ?? '',
11
- required: options.required ?? false,
9
+ visible: true,
12
10
  disabled: options.disabled ?? false,
13
- name: options.name ?? id,
14
- style: options.style ?? '',
11
+ loading: false,
15
12
  class: options.class ?? '',
16
- errorMessage: undefined
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
- // ✅ Inherited from FormInput/BaseComponent:
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.validate();
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);
@@ -1,5 +1,6 @@
1
- import { FormInput, FormInputState } from './base/FormInput.js';
2
- import { BaseComponent } from './base/BaseComponent.js';
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 FormInputState {
20
+ interface SwitchState extends BaseState {
20
21
  checked: boolean;
21
22
  value: string;
22
23
  }
23
24
 
24
- export class Switch extends FormInput<SwitchState> {
25
+ export class Switch extends BaseComponent<SwitchState> {
25
26
  constructor(id: string, options: SwitchOptions = {}) {
26
27
  super(id, {
27
- checked: options.checked ?? false,
28
- value: options.value ?? 'on',
29
- label: options.label ?? '',
30
- required: options.required ?? false,
28
+ visible: true,
31
29
  disabled: options.disabled ?? false,
32
- name: options.name ?? id,
33
- style: options.style ?? '',
30
+ loading: false,
34
31
  class: options.class ?? '',
35
- errorMessage: undefined
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
- // ✅ Inherited from FormInput/BaseComponent:
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.validate();
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"}