juxscript 1.1.10 → 1.1.13

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.
@@ -29,6 +29,12 @@ export declare abstract class BaseComponent<TState extends Record<string, any>>
29
29
  protected abstract getTriggerEvents(): readonly string[];
30
30
  protected abstract getCallbackEvents(): readonly string[];
31
31
  abstract render(targetId?: string): this;
32
+ /**
33
+ * REACTIVE UPDATE HOOK
34
+ * Called automatically when this.state[prop] changes.
35
+ * Override this in components to update the DOM without full re-render.
36
+ */
37
+ protected update(prop: string, value: any): void;
32
38
  /**
33
39
  * Set component style
34
40
  */
@@ -127,15 +133,6 @@ export declare abstract class BaseComponent<TState extends Record<string, any>>
127
133
  renderTo(juxComponent: any): this;
128
134
  /**
129
135
  * ✅ Read-only accessor for component state
130
- * Provides clear separation between setters (fluent methods) and getters
131
- *
132
- * @example
133
- * const myCard = card('example')
134
- * .title('Hello') // ✅ SETTER (fluent)
135
- * .content('World'); // ✅ SETTER (fluent)
136
- *
137
- * console.log(myCard.props.title); // ✅ GETTER: 'Hello'
138
- * console.log(myCard.props.content); // ✅ GETTER: 'World'
139
136
  */
140
137
  get props(): Readonly<TState>;
141
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"BaseComponent.d.ts","sourceRoot":"","sources":["BaseComponent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BaseComponent.d.ts","sourceRoot":"","sources":["BaseComponent.ts"],"names":[],"mappings":"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"}
@@ -18,7 +18,26 @@ export class BaseComponent {
18
18
  this._callbackHandlers = new Map();
19
19
  this._id = id;
20
20
  this.id = id;
21
- this.state = initialState;
21
+ // ✨ REACTIVE PROXY: Intercept state changes to trigger view updates automatically
22
+ this.state = new Proxy(initialState, {
23
+ set: (target, prop, value) => {
24
+ const key = prop;
25
+ if (target[key] !== value) {
26
+ target[key] = value;
27
+ this.update(prop, value);
28
+ }
29
+ return true;
30
+ }
31
+ });
32
+ }
33
+ /**
34
+ * REACTIVE UPDATE HOOK
35
+ * Called automatically when this.state[prop] changes.
36
+ * Override this in components to update the DOM without full re-render.
37
+ */
38
+ update(prop, value) {
39
+ // Default no-op. Children implement granular DOM updates here.
40
+ // Example: if (prop === 'title') document.getElementById(...).textContent = value;
22
41
  }
23
42
  /* ═════════════════════════════════════════════════════════════════
24
43
  * COMMON FLUENT API (Inherited by all components)
@@ -277,7 +296,7 @@ export class BaseComponent {
277
296
  handler(...args);
278
297
  }
279
298
  else {
280
- console.warn(`🔍 No handler found for "${eventName}"`);
299
+ // console.warn(`🔍 No handler found for "${eventName}"`);
281
300
  }
282
301
  }
283
302
  /* ═════════════════════════════════════════════════════════════════
@@ -347,15 +366,6 @@ export class BaseComponent {
347
366
  * ═════════════════════════════════════════════════════════════════ */
348
367
  /**
349
368
  * ✅ Read-only accessor for component state
350
- * Provides clear separation between setters (fluent methods) and getters
351
- *
352
- * @example
353
- * const myCard = card('example')
354
- * .title('Hello') // ✅ SETTER (fluent)
355
- * .content('World'); // ✅ SETTER (fluent)
356
- *
357
- * console.log(myCard.props.title); // ✅ GETTER: 'Hello'
358
- * console.log(myCard.props.content); // ✅ GETTER: 'World'
359
369
  */
360
370
  get props() {
361
371
  return this.state;
@@ -31,7 +31,18 @@ export abstract class BaseComponent<TState extends Record<string, any>> {
31
31
  constructor(id: string, initialState: TState) {
32
32
  this._id = id;
33
33
  this.id = id;
34
- this.state = initialState;
34
+
35
+ // ✨ REACTIVE PROXY: Intercept state changes to trigger view updates automatically
36
+ this.state = new Proxy(initialState, {
37
+ set: (target, prop, value) => {
38
+ const key = prop as keyof TState;
39
+ if (target[key] !== value) {
40
+ target[key] = value;
41
+ this.update(prop as string, value);
42
+ }
43
+ return true;
44
+ }
45
+ });
35
46
  }
36
47
 
37
48
  /* ═════════════════════════════════════════════════════════════════
@@ -42,6 +53,16 @@ export abstract class BaseComponent<TState extends Record<string, any>> {
42
53
  protected abstract getCallbackEvents(): readonly string[];
43
54
  abstract render(targetId?: string): this;
44
55
 
56
+ /**
57
+ * REACTIVE UPDATE HOOK
58
+ * Called automatically when this.state[prop] changes.
59
+ * Override this in components to update the DOM without full re-render.
60
+ */
61
+ protected update(prop: string, value: any): void {
62
+ // Default no-op. Children implement granular DOM updates here.
63
+ // Example: if (prop === 'title') document.getElementById(...).textContent = value;
64
+ }
65
+
45
66
  /* ═════════════════════════════════════════════════════════════════
46
67
  * COMMON FLUENT API (Inherited by all components)
47
68
  * ═════════════════════════════════════════════════════════════════ */
@@ -324,7 +345,7 @@ export abstract class BaseComponent<TState extends Record<string, any>> {
324
345
  const handler = this._callbackHandlers.get(eventName)!;
325
346
  handler(...args);
326
347
  } else {
327
- console.warn(`🔍 No handler found for "${eventName}"`);
348
+ // console.warn(`🔍 No handler found for "${eventName}"`);
328
349
  }
329
350
  }
330
351
 
@@ -405,15 +426,6 @@ export abstract class BaseComponent<TState extends Record<string, any>> {
405
426
 
406
427
  /**
407
428
  * ✅ Read-only accessor for component state
408
- * Provides clear separation between setters (fluent methods) and getters
409
- *
410
- * @example
411
- * const myCard = card('example')
412
- * .title('Hello') // ✅ SETTER (fluent)
413
- * .content('World'); // ✅ SETTER (fluent)
414
- *
415
- * console.log(myCard.props.title); // ✅ GETTER: 'Hello'
416
- * console.log(myCard.props.content); // ✅ GETTER: 'World'
417
429
  */
418
430
  get props(): Readonly<TState> {
419
431
  return this.state as Readonly<TState>;
@@ -32,7 +32,10 @@ export declare class ChartComponent extends BaseComponent<ChartState> {
32
32
  title(text: string, display?: boolean): this;
33
33
  legend(display?: boolean, position?: 'top' | 'bottom' | 'left' | 'right'): this;
34
34
  tooltip(enabled?: boolean): this;
35
- update(mode?: 'resize' | 'reset' | 'none' | 'hide' | 'show' | 'default'): this;
35
+ /**
36
+ * Update chart with new data or configuration
37
+ */
38
+ updateChart(mode?: 'resize' | 'reset' | 'none' | 'hide' | 'show' | 'default'): this;
36
39
  reset(): this;
37
40
  destroy(): this;
38
41
  getChart(): Chart | null;
@@ -1 +1 @@
1
- {"version":3,"file":"chart.d.ts","sourceRoot":"","sources":["chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAsB,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI9F,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,cAAe,SAAQ,aAAa,CAAC,UAAU,CAAC;IACzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAyB;IAC/D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAsD;IAC7F,OAAO,CAAC,aAAa,CAAsB;gBAE/B,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,SAAiB,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC;IAS9E,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAQhD,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAoB5B,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAS5B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAS7B,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI;IAS5B,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI;IAa9B,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IASlC,UAAU,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IAIvC,mBAAmB,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IAIhD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,OAAc,GAAG,IAAI;IASlD,MAAM,CAAC,OAAO,GAAE,OAAc,EAAE,QAAQ,GAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAe,GAAG,IAAI;IAS5F,OAAO,CAAC,OAAO,GAAE,OAAc,GAAG,IAAI;IAatC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI;IAQ9E,KAAK,IAAI,IAAI;IAOb,OAAO,IAAI,IAAI;IASf,QAAQ,IAAI,KAAK,GAAG,IAAI;IAQxB,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;CAqClC;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,SAAiB,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,cAAc,CAExG"}
1
+ {"version":3,"file":"chart.d.ts","sourceRoot":"","sources":["chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAsB,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI9F,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,cAAe,SAAQ,aAAa,CAAC,UAAU,CAAC;IACzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAyB;IAC/D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAsD;IAC7F,OAAO,CAAC,aAAa,CAAsB;gBAE/B,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,SAAiB,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC;IAS9E,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAQhD,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAoB5B,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAS5B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAS7B,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI;IAS5B,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI;IAa9B,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IASlC,UAAU,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IAIvC,mBAAmB,CAAC,KAAK,GAAE,OAAc,GAAG,IAAI;IAIhD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,OAAc,GAAG,IAAI;IASlD,MAAM,CAAC,OAAO,GAAE,OAAc,EAAE,QAAQ,GAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAe,GAAG,IAAI;IAS5F,OAAO,CAAC,OAAO,GAAE,OAAc,GAAG,IAAI;IAatC;;OAEG;IACH,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI;IAOnF,KAAK,IAAI,IAAI;IAOb,OAAO,IAAI,IAAI;IASf,QAAQ,IAAI,KAAK,GAAG,IAAI;IAQxB,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;CAsDlC;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,SAAiB,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,cAAc,CAExG"}
@@ -117,10 +117,12 @@ export class ChartComponent extends BaseComponent {
117
117
  /* ═════════════════════════════════════════════════════════════════
118
118
  * CHART OPERATIONS
119
119
  * ═════════════════════════════════════════════════════════════════ */
120
- update(mode) {
120
+ /**
121
+ * Update chart with new data or configuration
122
+ */
123
+ updateChart(mode) {
121
124
  if (this.chartInstance) {
122
125
  this.chartInstance.update(mode);
123
- this._triggerCallback('update', this.chartInstance);
124
126
  }
125
127
  return this;
126
128
  }
@@ -169,6 +171,20 @@ export class ChartComponent extends BaseComponent {
169
171
  options: this.state.options
170
172
  };
171
173
  this.chartInstance = new Chart(canvas, config);
174
+ // Wire sync for data
175
+ this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
176
+ if (property === 'data') {
177
+ const transform = toComponent || ((v) => v);
178
+ stateObj.subscribe((val) => {
179
+ const transformed = transform(val);
180
+ this.state.data = transformed;
181
+ if (this.chartInstance) {
182
+ this.chartInstance.data = transformed;
183
+ this.chartInstance.update();
184
+ }
185
+ });
186
+ }
187
+ });
172
188
  // Wire events and syncs
173
189
  this._wireStandardEvents(container);
174
190
  this._wireAllSyncs();
@@ -152,10 +152,12 @@ export class ChartComponent extends BaseComponent<ChartState> {
152
152
  * CHART OPERATIONS
153
153
  * ═════════════════════════════════════════════════════════════════ */
154
154
 
155
- update(mode?: 'resize' | 'reset' | 'none' | 'hide' | 'show' | 'default'): this {
155
+ /**
156
+ * Update chart with new data or configuration
157
+ */
158
+ updateChart(mode?: 'resize' | 'reset' | 'none' | 'hide' | 'show' | 'default'): this {
156
159
  if (this.chartInstance) {
157
160
  this.chartInstance.update(mode);
158
- this._triggerCallback('update', this.chartInstance);
159
161
  }
160
162
  return this;
161
163
  }
@@ -213,6 +215,23 @@ export class ChartComponent extends BaseComponent<ChartState> {
213
215
 
214
216
  this.chartInstance = new Chart(canvas, config);
215
217
 
218
+ // Wire sync for data
219
+ this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
220
+ if (property === 'data') {
221
+ const transform = toComponent || ((v: any) => v);
222
+
223
+ stateObj.subscribe((val: any) => {
224
+ const transformed = transform(val);
225
+ this.state.data = transformed;
226
+
227
+ if (this.chartInstance) {
228
+ this.chartInstance.data = transformed;
229
+ this.chartInstance.update();
230
+ }
231
+ });
232
+ }
233
+ });
234
+
216
235
  // Wire events and syncs
217
236
  this._wireStandardEvents(container);
218
237
  this._wireAllSyncs();
@@ -5,7 +5,11 @@ export interface HeroOptions {
5
5
  content?: string;
6
6
  cta?: string;
7
7
  ctaLink?: string;
8
- backgroundImage?: string;
8
+ backgroundImage?: string | {
9
+ url: string;
10
+ size?: string;
11
+ repeat?: string;
12
+ };
9
13
  backgroundOverlay?: boolean;
10
14
  variant?: 'default' | 'centered' | 'split';
11
15
  centered?: boolean;
@@ -18,7 +22,11 @@ type HeroState = {
18
22
  content: string;
19
23
  cta: string;
20
24
  ctaLink: string;
21
- backgroundImage: string;
25
+ backgroundImage: {
26
+ url: string;
27
+ size: string;
28
+ repeat: string;
29
+ };
22
30
  backgroundOverlay: boolean;
23
31
  variant: string;
24
32
  centered: boolean;
@@ -29,12 +37,21 @@ export declare class Hero extends BaseComponent<HeroState> {
29
37
  constructor(id: string, options?: HeroOptions);
30
38
  protected getTriggerEvents(): readonly string[];
31
39
  protected getCallbackEvents(): readonly string[];
40
+ /**
41
+ * Called automatically by BaseComponent when state changes.
42
+ * Centralizes DOM manipulation so setters don't have to drill/repeat logic.
43
+ */
44
+ protected update(prop: string, value: any): void;
32
45
  title(value: string): this;
33
46
  subtitle(value: string): this;
34
47
  content(value: string): this;
35
48
  cta(value: string): this;
36
49
  ctaLink(value: string): this;
37
- backgroundImage(value: string): this;
50
+ backgroundImage(value: string | {
51
+ url: string;
52
+ size?: string;
53
+ repeat?: string;
54
+ }): this;
38
55
  backgroundOverlay(value: boolean): this;
39
56
  variant(value: string): this;
40
57
  centered(value: boolean): this;
@@ -1 +1 @@
1
- {"version":3,"file":"hero.d.ts","sourceRoot":"","sources":["hero.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAMxD,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,SAAS,GAAG;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,qBAAa,IAAK,SAAQ,aAAa,CAAC,SAAS,CAAC;gBACpC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB;IAgBjD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAQhD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7B,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK5B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKxB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK5B,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKpC,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKvC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK5B,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAS9B,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;CA2GhC;AAED,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,IAAI,CAEhE"}
1
+ {"version":3,"file":"hero.d.ts","sourceRoot":"","sources":["hero.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAMxD,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3E,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,SAAS,GAAG;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,iBAAiB,EAAE,OAAO,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,qBAAa,IAAK,SAAQ,aAAa,CAAC,SAAS,CAAC;gBACpC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB;IAoBjD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAQhD;;;OAGG;IACH,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IA+ChD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7B,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK5B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKxB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK5B,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAatF,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKvC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK5B,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAS9B,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;CAuEhC;AAED,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,IAAI,CAEhE"}
@@ -1,19 +1,22 @@
1
1
  import { BaseComponent } from './base/BaseComponent.js';
2
2
  // Event definitions - Hero is display-only, but CTA button can trigger actions
3
3
  const TRIGGER_EVENTS = [];
4
- const CALLBACK_EVENTS = ['ctaClick']; // ✅ When CTA button is clicked
4
+ const CALLBACK_EVENTS = ['ctaClick'];
5
5
  export class Hero extends BaseComponent {
6
6
  constructor(id, options = {}) {
7
+ const bgImage = typeof options.backgroundImage === 'string'
8
+ ? { url: options.backgroundImage, size: 'cover', repeat: 'no-repeat' }
9
+ : options.backgroundImage || { url: '', size: 'cover', repeat: 'no-repeat' };
7
10
  super(id, {
8
11
  title: options.title ?? '',
9
12
  subtitle: options.subtitle ?? '',
10
- content: options.content ?? '', // ✅ ADD
13
+ content: options.content ?? '',
11
14
  cta: options.cta ?? '',
12
15
  ctaLink: options.ctaLink ?? '#',
13
- backgroundImage: options.backgroundImage ?? '',
14
- backgroundOverlay: options.backgroundOverlay ?? false, // ✅ ADD
16
+ backgroundImage: { url: bgImage.url, size: bgImage.size || 'cover', repeat: bgImage.repeat || 'no-repeat' },
17
+ backgroundOverlay: options.backgroundOverlay ?? false,
15
18
  variant: options.variant ?? 'default',
16
- centered: options.centered ?? false, // ✅ ADD
19
+ centered: options.centered ?? false,
17
20
  style: options.style ?? '',
18
21
  class: options.class ?? ''
19
22
  });
@@ -25,10 +28,60 @@ export class Hero extends BaseComponent {
25
28
  return CALLBACK_EVENTS;
26
29
  }
27
30
  /* ═════════════════════════════════════════════════════════════════
28
- * FLUENT API
31
+ * REACTIVE DOM UPDATES
32
+ * ═════════════════════════════════════════════════════════════════ */
33
+ /**
34
+ * Called automatically by BaseComponent when state changes.
35
+ * Centralizes DOM manipulation so setters don't have to drill/repeat logic.
36
+ */
37
+ update(prop, value) {
38
+ const hero = document.getElementById(this._id);
39
+ if (!hero)
40
+ return; // Component not mounted/rendered yet
41
+ switch (prop) {
42
+ case 'title':
43
+ const titleEl = document.getElementById(`${this._id}-title`);
44
+ if (titleEl)
45
+ titleEl.textContent = value;
46
+ break;
47
+ case 'subtitle':
48
+ const subtitleEl = document.getElementById(`${this._id}-subtitle`);
49
+ if (subtitleEl)
50
+ subtitleEl.textContent = value;
51
+ break;
52
+ case 'content':
53
+ const contentEl = hero.querySelector('.jux-hero-body');
54
+ if (contentEl)
55
+ contentEl.innerHTML = value;
56
+ break;
57
+ case 'cta':
58
+ const ctaEl = hero.querySelector('.jux-hero-cta');
59
+ if (ctaEl)
60
+ ctaEl.textContent = value;
61
+ break;
62
+ case 'ctaLink':
63
+ const ctaLinkEl = hero.querySelector('.jux-hero-cta');
64
+ if (ctaLinkEl)
65
+ ctaLinkEl.href = value;
66
+ break;
67
+ case 'backgroundImage':
68
+ hero.style.backgroundImage = `url(${value.url})`;
69
+ hero.style.backgroundSize = value.size;
70
+ hero.style.backgroundRepeat = value.repeat;
71
+ break;
72
+ case 'centered':
73
+ if (value)
74
+ hero.classList.add('jux-hero-centered');
75
+ else
76
+ hero.classList.remove('jux-hero-centered');
77
+ break;
78
+ }
79
+ }
80
+ /* ═════════════════════════════════════════════════════════════════
81
+ * FLUENT API (Simplified - just updates state)
29
82
  * ═════════════════════════════════════════════════════════════════ */
30
83
  title(value) {
31
- this.state.title = value;
84
+ this.state.title = value; // Triggers update('title', value) via Proxy
32
85
  return this;
33
86
  }
34
87
  subtitle(value) {
@@ -48,7 +101,16 @@ export class Hero extends BaseComponent {
48
101
  return this;
49
102
  }
50
103
  backgroundImage(value) {
51
- this.state.backgroundImage = value;
104
+ if (typeof value === 'string') {
105
+ this.state.backgroundImage = { url: value, size: 'cover', repeat: 'no-repeat' };
106
+ }
107
+ else {
108
+ this.state.backgroundImage = {
109
+ url: value.url,
110
+ size: value.size || 'cover',
111
+ repeat: value.repeat || 'no-repeat'
112
+ };
113
+ }
52
114
  return this;
53
115
  }
54
116
  backgroundOverlay(value) {
@@ -78,8 +140,10 @@ export class Hero extends BaseComponent {
78
140
  hero.className += ` ${className}`;
79
141
  if (style)
80
142
  hero.setAttribute('style', style);
81
- if (backgroundImage) {
82
- hero.style.backgroundImage = `url(${backgroundImage})`;
143
+ if (backgroundImage.url) {
144
+ hero.style.backgroundImage = `url(${backgroundImage.url})`;
145
+ hero.style.backgroundSize = backgroundImage.size;
146
+ hero.style.backgroundRepeat = backgroundImage.repeat;
83
147
  if (backgroundOverlay) {
84
148
  const overlay = document.createElement('div');
85
149
  overlay.className = 'jux-hero-overlay';
@@ -121,41 +185,7 @@ export class Hero extends BaseComponent {
121
185
  }
122
186
  hero.appendChild(contentContainer);
123
187
  this._wireStandardEvents(hero);
124
- this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
125
- if (property === 'title') {
126
- const transform = toComponent || ((v) => String(v));
127
- stateObj.subscribe((val) => {
128
- const transformed = transform(val);
129
- const titleEl = document.getElementById(`${this._id}-title`);
130
- if (titleEl) {
131
- titleEl.textContent = transformed;
132
- }
133
- this.state.title = transformed;
134
- });
135
- }
136
- else if (property === 'subtitle') {
137
- const transform = toComponent || ((v) => String(v));
138
- stateObj.subscribe((val) => {
139
- const transformed = transform(val);
140
- const subtitleEl = document.getElementById(`${this._id}-subtitle`);
141
- if (subtitleEl) {
142
- subtitleEl.textContent = transformed;
143
- }
144
- this.state.subtitle = transformed;
145
- });
146
- }
147
- else if (property === 'content') {
148
- const transform = toComponent || ((v) => String(v));
149
- stateObj.subscribe((val) => {
150
- const transformed = transform(val);
151
- const contentEl = hero.querySelector('.jux-hero-body');
152
- if (contentEl) {
153
- contentEl.innerHTML = transformed;
154
- }
155
- this.state.content = transformed;
156
- });
157
- }
158
- });
188
+ this._wireAllSyncs(); // Use base method
159
189
  container.appendChild(hero);
160
190
  return this;
161
191
  }
@@ -2,18 +2,18 @@ import { BaseComponent } from './base/BaseComponent.js';
2
2
 
3
3
  // Event definitions - Hero is display-only, but CTA button can trigger actions
4
4
  const TRIGGER_EVENTS = [] as const;
5
- const CALLBACK_EVENTS = ['ctaClick'] as const; // ✅ When CTA button is clicked
5
+ const CALLBACK_EVENTS = ['ctaClick'] as const;
6
6
 
7
7
  export interface HeroOptions {
8
8
  title?: string;
9
9
  subtitle?: string;
10
- content?: string; // ✅ ADD: Generates jux-hero-body div
11
- cta?: string; // ✅ KEEP: Generates jux-hero-cta anchor
10
+ content?: string;
11
+ cta?: string;
12
12
  ctaLink?: string;
13
- backgroundImage?: string;
14
- backgroundOverlay?: boolean; // ✅ ADD: Generates jux-hero-overlay div
13
+ backgroundImage?: string | { url: string; size?: string; repeat?: string };
14
+ backgroundOverlay?: boolean;
15
15
  variant?: 'default' | 'centered' | 'split';
16
- centered?: boolean; // ✅ ADD: Affects container class
16
+ centered?: boolean;
17
17
  style?: string;
18
18
  class?: string;
19
19
  }
@@ -21,29 +21,33 @@ export interface HeroOptions {
21
21
  type HeroState = {
22
22
  title: string;
23
23
  subtitle: string;
24
- content: string; // ✅ ADD: For jux-hero-body
24
+ content: string;
25
25
  cta: string;
26
26
  ctaLink: string;
27
- backgroundImage: string;
28
- backgroundOverlay: boolean; // ✅ ADD: For overlay div
27
+ backgroundImage: { url: string; size: string; repeat: string };
28
+ backgroundOverlay: boolean;
29
29
  variant: string;
30
- centered: boolean; // ✅ ADD: For layout variant
30
+ centered: boolean;
31
31
  style: string;
32
32
  class: string;
33
33
  };
34
34
 
35
35
  export class Hero extends BaseComponent<HeroState> {
36
36
  constructor(id: string, options: HeroOptions = {}) {
37
+ const bgImage = typeof options.backgroundImage === 'string'
38
+ ? { url: options.backgroundImage, size: 'cover', repeat: 'no-repeat' }
39
+ : options.backgroundImage || { url: '', size: 'cover', repeat: 'no-repeat' };
40
+
37
41
  super(id, {
38
42
  title: options.title ?? '',
39
43
  subtitle: options.subtitle ?? '',
40
- content: options.content ?? '', // ✅ ADD
44
+ content: options.content ?? '',
41
45
  cta: options.cta ?? '',
42
46
  ctaLink: options.ctaLink ?? '#',
43
- backgroundImage: options.backgroundImage ?? '',
44
- backgroundOverlay: options.backgroundOverlay ?? false, // ✅ ADD
47
+ backgroundImage: { url: bgImage.url, size: bgImage.size || 'cover', repeat: bgImage.repeat || 'no-repeat' },
48
+ backgroundOverlay: options.backgroundOverlay ?? false,
45
49
  variant: options.variant ?? 'default',
46
- centered: options.centered ?? false, // ✅ ADD
50
+ centered: options.centered ?? false,
47
51
  style: options.style ?? '',
48
52
  class: options.class ?? ''
49
53
  });
@@ -58,11 +62,62 @@ export class Hero extends BaseComponent<HeroState> {
58
62
  }
59
63
 
60
64
  /* ═════════════════════════════════════════════════════════════════
61
- * FLUENT API
65
+ * REACTIVE DOM UPDATES
66
+ * ═════════════════════════════════════════════════════════════════ */
67
+
68
+ /**
69
+ * Called automatically by BaseComponent when state changes.
70
+ * Centralizes DOM manipulation so setters don't have to drill/repeat logic.
71
+ */
72
+ protected update(prop: string, value: any): void {
73
+ const hero = document.getElementById(this._id);
74
+ if (!hero) return; // Component not mounted/rendered yet
75
+
76
+ switch (prop) {
77
+ case 'title':
78
+ const titleEl = document.getElementById(`${this._id}-title`);
79
+ if (titleEl) titleEl.textContent = value;
80
+ break;
81
+
82
+ case 'subtitle':
83
+ const subtitleEl = document.getElementById(`${this._id}-subtitle`);
84
+ if (subtitleEl) subtitleEl.textContent = value;
85
+ break;
86
+
87
+ case 'content':
88
+ const contentEl = hero.querySelector('.jux-hero-body');
89
+ if (contentEl) contentEl.innerHTML = value;
90
+ break;
91
+
92
+ case 'cta':
93
+ const ctaEl = hero.querySelector('.jux-hero-cta') as HTMLElement;
94
+ if (ctaEl) ctaEl.textContent = value;
95
+ break;
96
+
97
+ case 'ctaLink':
98
+ const ctaLinkEl = hero.querySelector('.jux-hero-cta') as HTMLAnchorElement;
99
+ if (ctaLinkEl) ctaLinkEl.href = value;
100
+ break;
101
+
102
+ case 'backgroundImage':
103
+ hero.style.backgroundImage = `url(${value.url})`;
104
+ hero.style.backgroundSize = value.size;
105
+ hero.style.backgroundRepeat = value.repeat;
106
+ break;
107
+
108
+ case 'centered':
109
+ if (value) hero.classList.add('jux-hero-centered');
110
+ else hero.classList.remove('jux-hero-centered');
111
+ break;
112
+ }
113
+ }
114
+
115
+ /* ═════════════════════════════════════════════════════════════════
116
+ * FLUENT API (Simplified - just updates state)
62
117
  * ═════════════════════════════════════════════════════════════════ */
63
118
 
64
119
  title(value: string): this {
65
- this.state.title = value;
120
+ this.state.title = value; // Triggers update('title', value) via Proxy
66
121
  return this;
67
122
  }
68
123
 
@@ -71,7 +126,7 @@ export class Hero extends BaseComponent<HeroState> {
71
126
  return this;
72
127
  }
73
128
 
74
- content(value: string): this { // ✅ ADD: Fluent method for content
129
+ content(value: string): this {
75
130
  this.state.content = value;
76
131
  return this;
77
132
  }
@@ -86,12 +141,20 @@ export class Hero extends BaseComponent<HeroState> {
86
141
  return this;
87
142
  }
88
143
 
89
- backgroundImage(value: string): this {
90
- this.state.backgroundImage = value;
144
+ backgroundImage(value: string | { url: string; size?: string; repeat?: string }): this {
145
+ if (typeof value === 'string') {
146
+ this.state.backgroundImage = { url: value, size: 'cover', repeat: 'no-repeat' };
147
+ } else {
148
+ this.state.backgroundImage = {
149
+ url: value.url,
150
+ size: value.size || 'cover',
151
+ repeat: value.repeat || 'no-repeat'
152
+ };
153
+ }
91
154
  return this;
92
155
  }
93
156
 
94
- backgroundOverlay(value: boolean): this { // ✅ ADD: Fluent method for overlay
157
+ backgroundOverlay(value: boolean): this {
95
158
  this.state.backgroundOverlay = value;
96
159
  return this;
97
160
  }
@@ -101,7 +164,7 @@ export class Hero extends BaseComponent<HeroState> {
101
164
  return this;
102
165
  }
103
166
 
104
- centered(value: boolean): this { // ✅ ADD: Fluent method for centered
167
+ centered(value: boolean): this {
105
168
  this.state.centered = value;
106
169
  return this;
107
170
  }
@@ -122,8 +185,10 @@ export class Hero extends BaseComponent<HeroState> {
122
185
  if (className) hero.className += ` ${className}`;
123
186
  if (style) hero.setAttribute('style', style);
124
187
 
125
- if (backgroundImage) {
126
- hero.style.backgroundImage = `url(${backgroundImage})`;
188
+ if (backgroundImage.url) {
189
+ hero.style.backgroundImage = `url(${backgroundImage.url})`;
190
+ hero.style.backgroundSize = backgroundImage.size;
191
+ hero.style.backgroundRepeat = backgroundImage.repeat;
127
192
  if (backgroundOverlay) {
128
193
  const overlay = document.createElement('div');
129
194
  overlay.className = 'jux-hero-overlay';
@@ -174,45 +239,7 @@ export class Hero extends BaseComponent<HeroState> {
174
239
  hero.appendChild(contentContainer);
175
240
 
176
241
  this._wireStandardEvents(hero);
177
-
178
- this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
179
- if (property === 'title') {
180
- const transform = toComponent || ((v: any) => String(v));
181
-
182
- stateObj.subscribe((val: any) => {
183
- const transformed = transform(val);
184
- const titleEl = document.getElementById(`${this._id}-title`);
185
- if (titleEl) {
186
- titleEl.textContent = transformed;
187
- }
188
- this.state.title = transformed;
189
- });
190
- }
191
- else if (property === 'subtitle') {
192
- const transform = toComponent || ((v: any) => String(v));
193
-
194
- stateObj.subscribe((val: any) => {
195
- const transformed = transform(val);
196
- const subtitleEl = document.getElementById(`${this._id}-subtitle`);
197
- if (subtitleEl) {
198
- subtitleEl.textContent = transformed;
199
- }
200
- this.state.subtitle = transformed;
201
- });
202
- }
203
- else if (property === 'content') {
204
- const transform = toComponent || ((v: any) => String(v));
205
-
206
- stateObj.subscribe((val: any) => {
207
- const transformed = transform(val);
208
- const contentEl = hero.querySelector('.jux-hero-body');
209
- if (contentEl) {
210
- contentEl.innerHTML = transformed;
211
- }
212
- this.state.content = transformed;
213
- });
214
- }
215
- });
242
+ this._wireAllSyncs(); // Use base method
216
243
 
217
244
  container.appendChild(hero);
218
245
  return this;
@@ -222,3 +249,4 @@ export class Hero extends BaseComponent<HeroState> {
222
249
  export function hero(id: string, options: HeroOptions = {}): Hero {
223
250
  return new Hero(id, options);
224
251
  }
252
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.10",
3
+ "version": "1.1.13",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",