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.
- package/lib/components/base/BaseComponent.d.ts +6 -9
- package/lib/components/base/BaseComponent.d.ts.map +1 -1
- package/lib/components/base/BaseComponent.js +21 -11
- package/lib/components/base/BaseComponent.ts +23 -11
- package/lib/components/chart.d.ts +4 -1
- package/lib/components/chart.d.ts.map +1 -1
- package/lib/components/chart.js +18 -2
- package/lib/components/chart.ts +21 -2
- package/lib/components/hero.d.ts +20 -3
- package/lib/components/hero.d.ts.map +1 -1
- package/lib/components/hero.js +75 -45
- package/lib/components/hero.ts +90 -62
- package/package.json +1 -1
|
@@ -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":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAGlD;;;;;;;;GAQG;AACH,8BAAsB,aAAa,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAElE,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,WAAW,GAAG,IAAI,CAAQ;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IAGX,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAM;IACtE,SAAS,CAAC,aAAa,EAAE,KAAK,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,OAAO,CAAC,EAAE,QAAQ,CAAC;QACnB,WAAW,CAAC,EAAE,QAAQ,CAAA;KACzB,CAAC,CAAM;IACR,SAAS,CAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAa;IAC9D,SAAS,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAa;gBAEnD,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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"}
|
package/lib/components/chart.js
CHANGED
|
@@ -117,10 +117,12 @@ export class ChartComponent extends BaseComponent {
|
|
|
117
117
|
/* ═════════════════════════════════════════════════════════════════
|
|
118
118
|
* CHART OPERATIONS
|
|
119
119
|
* ═════════════════════════════════════════════════════════════════ */
|
|
120
|
-
|
|
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();
|
package/lib/components/chart.ts
CHANGED
|
@@ -152,10 +152,12 @@ export class ChartComponent extends BaseComponent<ChartState> {
|
|
|
152
152
|
* CHART OPERATIONS
|
|
153
153
|
* ═════════════════════════════════════════════════════════════════ */
|
|
154
154
|
|
|
155
|
-
|
|
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();
|
package/lib/components/hero.d.ts
CHANGED
|
@@ -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:
|
|
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
|
|
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;
|
|
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"}
|
package/lib/components/hero.js
CHANGED
|
@@ -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'];
|
|
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 ?? '',
|
|
13
|
+
content: options.content ?? '',
|
|
11
14
|
cta: options.cta ?? '',
|
|
12
15
|
ctaLink: options.ctaLink ?? '#',
|
|
13
|
-
backgroundImage:
|
|
14
|
-
backgroundOverlay: options.backgroundOverlay ?? false,
|
|
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,
|
|
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
|
-
*
|
|
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
|
-
|
|
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.
|
|
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
|
}
|
package/lib/components/hero.ts
CHANGED
|
@@ -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;
|
|
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;
|
|
11
|
-
cta?: string;
|
|
10
|
+
content?: string;
|
|
11
|
+
cta?: string;
|
|
12
12
|
ctaLink?: string;
|
|
13
|
-
backgroundImage?: string;
|
|
14
|
-
backgroundOverlay?: boolean;
|
|
13
|
+
backgroundImage?: string | { url: string; size?: string; repeat?: string };
|
|
14
|
+
backgroundOverlay?: boolean;
|
|
15
15
|
variant?: 'default' | 'centered' | 'split';
|
|
16
|
-
centered?: boolean;
|
|
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;
|
|
24
|
+
content: string;
|
|
25
25
|
cta: string;
|
|
26
26
|
ctaLink: string;
|
|
27
|
-
backgroundImage: string;
|
|
28
|
-
backgroundOverlay: boolean;
|
|
27
|
+
backgroundImage: { url: string; size: string; repeat: string };
|
|
28
|
+
backgroundOverlay: boolean;
|
|
29
29
|
variant: string;
|
|
30
|
-
centered: boolean;
|
|
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 ?? '',
|
|
44
|
+
content: options.content ?? '',
|
|
41
45
|
cta: options.cta ?? '',
|
|
42
46
|
ctaLink: options.ctaLink ?? '#',
|
|
43
|
-
backgroundImage:
|
|
44
|
-
backgroundOverlay: options.backgroundOverlay ?? false,
|
|
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,
|
|
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
|
-
*
|
|
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 {
|
|
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
|
-
|
|
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 {
|
|
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 {
|
|
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
|
+
|