ezfw-core 1.0.21 → 1.0.23

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 (43) hide show
  1. package/components/EzBaseComponent.ts +100 -5
  2. package/components/EzComponent.ts +3 -3
  3. package/components/EzLabel.ts +12 -3
  4. package/components/avatar/EzAvatar.ts +84 -54
  5. package/components/badge/EzBadge.ts +43 -24
  6. package/components/button/EzButton.ts +5 -3
  7. package/components/button/EzButtonGroup.ts +7 -10
  8. package/components/card/EzCard.ts +2 -1
  9. package/components/chart/EzChart.ts +20 -15
  10. package/components/checkbox/EzCheckbox.ts +47 -43
  11. package/components/dataview/EzDataView.ts +14 -29
  12. package/components/dataview/modes/EzDataViewCards.ts +51 -41
  13. package/components/dataview/modes/EzDataViewGrid.ts +5 -2
  14. package/components/datepicker/EzDatePicker.ts +2 -2
  15. package/components/dialog/EzDialog.ts +84 -67
  16. package/components/dropdown/EzDropdown.ts +72 -58
  17. package/components/form/EzForm.ts +45 -37
  18. package/components/kanban/EzKanban.module.scss +221 -0
  19. package/components/kanban/EzKanban.ts +222 -0
  20. package/components/kanban/EzKanbanTypes.ts +166 -0
  21. package/components/kanban/board/EzKanbanBoard.ts +117 -0
  22. package/components/kanban/card/EzKanbanCard.module.scss +173 -0
  23. package/components/kanban/card/EzKanbanCard.ts +275 -0
  24. package/components/kanban/card/EzKanbanCardEditor.ts +209 -0
  25. package/components/kanban/column/EzKanbanColumn.ts +253 -0
  26. package/components/kanban/state/EzKanbanController.ts +373 -0
  27. package/components/kanban/state/EzKanbanDragDrop.ts +226 -0
  28. package/components/panel/EzPanel.ts +59 -68
  29. package/components/picker/EzPicker.module.scss +14 -0
  30. package/components/picker/EzPicker.ts +118 -0
  31. package/components/radio/EzRadio.ts +55 -47
  32. package/components/select/EzSelect.ts +48 -44
  33. package/components/skeleton/EzSkeleton.ts +31 -26
  34. package/components/switch/EzSwitch.ts +52 -44
  35. package/components/tabs/EzTabPanel.ts +52 -48
  36. package/components/textarea/EzTextarea.ts +69 -54
  37. package/components/timepicker/EzTimePicker.ts +2 -2
  38. package/components/tooltip/EzTooltip.ts +20 -33
  39. package/core/ez.ts +7 -0
  40. package/core/loader.ts +2 -0
  41. package/core/renderer.ts +80 -4
  42. package/core/styleShortcuts.ts +418 -0
  43. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { effect } from '@preact/signals';
2
2
  import tooltipStyles from './tooltip/EzTooltip.module.scss';
3
3
  import { cx } from '../utils/cssModules.js';
4
+ import { extractStyleShortcuts, mergeStyles, EzStyleShortcuts } from '../core/styleShortcuts.js';
4
5
 
5
6
  const tooltipCls = cx(tooltipStyles);
6
7
 
@@ -11,6 +12,7 @@ const tooltipCls = cx(tooltipStyles);
11
12
  declare const ez: {
12
13
  _controllers: Record<string, EzController | undefined>;
13
14
  getController(name: string): EzController | null;
15
+ getControllerSync(name: string): EzController | null;
14
16
  getDeepValue(obj: unknown, path: string[]): unknown;
15
17
  setDeepValue(obj: unknown, path: string[], value: unknown): void;
16
18
  _createElement(config: EzComponentConfig): Promise<HTMLElement>;
@@ -19,6 +21,7 @@ declare const ez: {
19
21
 
20
22
  interface EzController {
21
23
  state: Record<string, unknown>;
24
+ _computed?: Record<string, { value: unknown }>;
22
25
  [key: string]: unknown;
23
26
  }
24
27
 
@@ -46,6 +49,8 @@ interface BindConfig {
46
49
  text?: string | (() => string);
47
50
  }
48
51
 
52
+ type StyleValue = string | number | undefined;
53
+
49
54
  export interface EzComponentConfig {
50
55
  controller?: string | null;
51
56
  bind?: string | BindConfig;
@@ -58,6 +63,73 @@ export interface EzComponentConfig {
58
63
  _styleModule?: StyleModule;
59
64
  onChange?: string | ((value: unknown) => void);
60
65
  itemRender?: (item: unknown, index: number, meta: ItemRenderMeta) => EzComponentConfig | null;
66
+
67
+ // Style shortcuts - Spacing
68
+ p?: StyleValue;
69
+ pt?: StyleValue;
70
+ pr?: StyleValue;
71
+ pb?: StyleValue;
72
+ pl?: StyleValue;
73
+ px?: StyleValue;
74
+ py?: StyleValue;
75
+ m?: StyleValue;
76
+ mt?: StyleValue;
77
+ mr?: StyleValue;
78
+ mb?: StyleValue;
79
+ ml?: StyleValue;
80
+ mx?: StyleValue;
81
+ my?: StyleValue;
82
+ gap?: StyleValue;
83
+
84
+ // Style shortcuts - Sizing
85
+ w?: StyleValue;
86
+ h?: StyleValue;
87
+ minW?: StyleValue;
88
+ maxW?: StyleValue;
89
+ minH?: StyleValue;
90
+ maxH?: StyleValue;
91
+
92
+ // Style shortcuts - Flexbox
93
+ justify?: string;
94
+ align?: string;
95
+ alignSelf?: string;
96
+ wrap?: string | boolean;
97
+
98
+ // Style shortcuts - Typography
99
+ fs?: StyleValue;
100
+ fw?: StyleValue;
101
+ ta?: string;
102
+ lh?: StyleValue;
103
+
104
+ // Style shortcuts - Visual
105
+ bg?: string;
106
+ color?: string;
107
+ rounded?: StyleValue | boolean;
108
+ br?: StyleValue | boolean;
109
+ brt?: StyleValue;
110
+ brb?: StyleValue;
111
+ brl?: StyleValue;
112
+ brr?: StyleValue;
113
+ brtl?: StyleValue;
114
+ brtr?: StyleValue;
115
+ brbl?: StyleValue;
116
+ brbr?: StyleValue;
117
+ shadow?: string;
118
+ opacity?: number;
119
+
120
+ // Style shortcuts - Layout
121
+ d?: string;
122
+ pos?: string;
123
+ z?: number;
124
+ overflow?: string;
125
+ top?: StyleValue;
126
+ right?: StyleValue;
127
+ bottom?: StyleValue;
128
+ left?: StyleValue;
129
+
130
+ // Wrapper for grouping shortcuts
131
+ ezStyle?: EzStyleShortcuts;
132
+
61
133
  [key: string]: unknown;
62
134
  }
63
135
 
@@ -292,10 +364,15 @@ export class EzBaseComponent {
292
364
  props = bind.data.split('.');
293
365
  }
294
366
 
367
+ // Track render version to cancel stale async renders
368
+ let currentRenderVersion = 0;
369
+
295
370
  const stop = effect(() => {
371
+ const renderVersion = ++currentRenderVersion;
372
+
296
373
  (async () => {
297
374
  const itemFn = this.config.itemRender;
298
- const controller = ez.getController(activeCtrl!);
375
+ const controller = ez.getControllerSync(activeCtrl!);
299
376
  let data = ez.getDeepValue(controller?.state, props!) as unknown[] | unknown;
300
377
 
301
378
  // If not found in state, check computed properties
@@ -311,6 +388,9 @@ export class EzBaseComponent {
311
388
  data = [data];
312
389
  }
313
390
 
391
+ // Check if this render is still current before modifying DOM
392
+ if (renderVersion !== currentRenderVersion) return;
393
+
314
394
  el.innerHTML = '';
315
395
 
316
396
  if (Array.isArray(data)) {
@@ -318,8 +398,10 @@ export class EzBaseComponent {
318
398
  (el as HTMLElement & { _ezListRendered: boolean })._ezListRendered = true;
319
399
  el.setAttribute("data-ez-list", "true");
320
400
 
321
- el.innerHTML = '';
322
401
  for (let i = 0; i < data.length; i++) {
402
+ // Check if render is still current before each iteration
403
+ if (renderVersion !== currentRenderVersion) return;
404
+
323
405
  if (data[i] == null) {
324
406
  if (import.meta.env.DEV) {
325
407
  console.warn(`[Ez] bind.data: Item at index ${i} is null/undefined. Controller: "${activeCtrl}", path: "${props!.join('.')}". Skipping.`);
@@ -340,12 +422,16 @@ export class EzBaseComponent {
340
422
  }
341
423
  // Only inherit CSS if child doesn't have its own CSS module
342
424
  const childHasOwnCss = childCfg.css ||
343
- (childCfg.eztype && ez.hasStyles(childCfg.eztype));
425
+ (typeof childCfg.eztype === 'string' && ez.hasStyles(childCfg.eztype));
344
426
  if (!childHasOwnCss && this.config.css) {
345
427
  childCfg.css = this.config.css;
346
428
  childCfg._styleModule = this.config._styleModule;
347
429
  }
348
430
  const childEl = await ez._createElement(childCfg);
431
+
432
+ // Final check before appending
433
+ if (renderVersion !== currentRenderVersion) return;
434
+
349
435
  el.appendChild(childEl);
350
436
  }
351
437
  }
@@ -541,8 +627,17 @@ export class EzBaseComponent {
541
627
  }
542
628
 
543
629
  applyStyles(el: HTMLElement): void {
544
- if (this.config.style && typeof this.config.style === 'object') {
545
- Object.assign(el.style, this.config.style);
630
+ // Extract style shortcuts from config
631
+ const { styles: shortcutStyles } = extractStyleShortcuts(this.config as Record<string, unknown>);
632
+
633
+ // Merge shortcuts with explicit style (explicit style takes priority)
634
+ const finalStyles = mergeStyles(
635
+ shortcutStyles,
636
+ this.config.style as Record<string, string> | undefined
637
+ );
638
+
639
+ if (Object.keys(finalStyles).length > 0) {
640
+ Object.assign(el.style, finalStyles);
546
641
  }
547
642
  }
548
643
 
@@ -29,7 +29,7 @@ export class EzComponent extends EzBaseComponent {
29
29
 
30
30
  async render(): Promise<HTMLElement> {
31
31
  const el = document.createElement('div');
32
- const { layout, style = {} } = this.config;
32
+ const { layout } = this.config;
33
33
 
34
34
  // 📦 Predefined layouts
35
35
  if (layout === 'hbox') {
@@ -42,8 +42,8 @@ export class EzComponent extends EzBaseComponent {
42
42
  el.style.flexDirection = 'column';
43
43
  }
44
44
 
45
- // 🎨 Additional inline styles
46
- Object.assign(el.style, style);
45
+ // 🎨 Apply styles (includes shortcuts like p, m, bg, etc.)
46
+ this.applyStyles(el);
47
47
 
48
48
  if (this.config.flex) {
49
49
  el.style.flex = String(this.config.flex);
@@ -1,5 +1,9 @@
1
1
  import { EzBaseComponent, EzBaseComponentConfig } from './EzBaseComponent.js';
2
2
 
3
+ declare const ez: {
4
+ _createElement(config: unknown): Promise<HTMLElement>;
5
+ };
6
+
3
7
  export interface EzLabelConfig extends EzBaseComponentConfig {
4
8
  text?: string;
5
9
  }
@@ -12,10 +16,15 @@ export class EzLabel extends EzBaseComponent {
12
16
  this.config = config;
13
17
  }
14
18
 
15
- render(): HTMLSpanElement {
16
- const el = document.createElement('span');
17
- this.applyCommonBindings(el);
19
+ async render(): Promise<HTMLSpanElement> {
20
+ const el = await ez._createElement({
21
+ eztype: 'span',
22
+ text: this.config.text
23
+ }) as HTMLSpanElement;
24
+
25
+ this.applyCls(el);
18
26
  this.applyStyles(el);
27
+ this.applyCommonBindings(el);
19
28
 
20
29
  return el;
21
30
  }
@@ -4,6 +4,10 @@ import { EzBaseComponent, EzBaseComponentConfig } from '../EzBaseComponent.js';
4
4
 
5
5
  const cls = cx(styles);
6
6
 
7
+ declare const ez: {
8
+ _createElement(config: unknown): Promise<HTMLElement>;
9
+ };
10
+
7
11
  const STATUS_MAP: Record<string, string> = {
8
12
  'online': 'statusOnline',
9
13
  'offline': 'statusOffline',
@@ -33,82 +37,108 @@ export class EzAvatar extends EzBaseComponent {
33
37
  this.config = config;
34
38
  }
35
39
 
36
- render(): HTMLDivElement {
37
- const el = document.createElement('div');
40
+ async render(): Promise<HTMLDivElement> {
41
+ const items: unknown[] = [];
38
42
 
39
- el.classList.add(cls('avatar'));
43
+ // Image or initials
44
+ if (this.config.src) {
45
+ items.push({
46
+ eztype: 'img',
47
+ cls: cls('avatarImg'),
48
+ src: this.config.src,
49
+ alt: this.config.alt || this.config.name || ''
50
+ });
51
+ } else {
52
+ items.push({
53
+ eztype: 'span',
54
+ cls: cls('avatarInitials'),
55
+ text: this._getInitials()
56
+ });
57
+ }
40
58
 
41
- if (this.config.width || this.config.height) {
42
- const width = this.config.width || this.config.height;
43
- const height = this.config.height || this.config.width;
59
+ // Status indicator
60
+ if (this.config.status) {
61
+ const statusClass = STATUS_MAP[this.config.status] || 'statusOffline';
62
+ items.push({
63
+ eztype: 'span',
64
+ cls: cls('avatarStatus', statusClass)
65
+ });
66
+ }
44
67
 
45
- el.style.width = typeof width === 'number' ? `${width}px` : String(width);
46
- el.style.height = typeof height === 'number' ? `${height}px` : String(height);
68
+ const el = await ez._createElement({
69
+ eztype: 'div',
70
+ cls: this._buildClasses(),
71
+ style: this._buildStyles(),
72
+ onClick: this.config.onClick ? (e: MouseEvent) => {
73
+ this.config.onClick!(e, this);
74
+ } : undefined,
75
+ items
76
+ }) as HTMLDivElement;
47
77
 
48
- const sizeNum = typeof width === 'number' ? width : parseInt(String(width), 10);
49
- if (sizeNum) {
50
- el.style.fontSize = `${Math.round(sizeNum * 0.4)}px`;
51
- }
52
- }
53
- else if (this.config.size) {
54
- if (typeof this.config.size === 'number') {
55
- el.style.width = `${this.config.size}px`;
56
- el.style.height = `${this.config.size}px`;
57
- el.style.fontSize = `${Math.round(this.config.size * 0.4)}px`;
58
- }
59
- else {
60
- el.classList.add(cls(this.config.size));
78
+ // Handle image error - fallback to initials
79
+ if (this.config.src) {
80
+ const img = el.querySelector('img');
81
+ if (img) {
82
+ img.onerror = async () => {
83
+ img.remove();
84
+ const initialsEl = await ez._createElement({
85
+ eztype: 'span',
86
+ cls: cls('avatarInitials'),
87
+ text: this._getInitials()
88
+ });
89
+ el.insertBefore(initialsEl, el.firstChild);
90
+ };
61
91
  }
62
92
  }
63
93
 
94
+ this.applyStyles(el);
95
+
96
+ return el;
97
+ }
98
+
99
+ private _buildClasses(): string[] {
100
+ const classes: string[] = [cls('avatar')];
101
+
64
102
  if (this.config.variant) {
65
- el.classList.add(cls(this.config.variant));
103
+ classes.push(cls(this.config.variant));
66
104
  }
67
105
 
68
106
  if (this.config.color) {
69
- el.classList.add(cls(this.config.color));
107
+ classes.push(cls(this.config.color));
70
108
  }
71
109
 
72
110
  if (this.config.onClick) {
73
- el.classList.add(cls('clickable'));
74
- el.addEventListener('click', e => {
75
- this.config.onClick!(e, this);
76
- });
111
+ classes.push(cls('clickable'));
77
112
  }
78
113
 
79
- if (this.config.src) {
80
- const img = document.createElement('img');
81
- img.className = cls('avatarImg');
82
- img.src = this.config.src;
83
- img.alt = this.config.alt || this.config.name || '';
114
+ if (typeof this.config.size === 'string') {
115
+ classes.push(cls(this.config.size));
116
+ }
84
117
 
85
- img.onerror = () => {
86
- img.remove();
87
- el.appendChild(this._createInitials());
88
- };
118
+ return classes;
119
+ }
89
120
 
90
- el.appendChild(img);
91
- } else {
92
- el.appendChild(this._createInitials());
93
- }
121
+ private _buildStyles(): Record<string, string> | undefined {
122
+ const styles: Record<string, string> = {};
94
123
 
95
- if (this.config.status) {
96
- const status = document.createElement('span');
97
- const statusClass = STATUS_MAP[this.config.status] || 'statusOffline';
98
- status.className = cls('avatarStatus', statusClass);
99
- el.appendChild(status);
100
- }
124
+ if (this.config.width || this.config.height) {
125
+ const width = this.config.width || this.config.height;
126
+ const height = this.config.height || this.config.width;
101
127
 
102
- this.applyStyles(el);
128
+ styles.width = typeof width === 'number' ? `${width}px` : String(width);
129
+ styles.height = typeof height === 'number' ? `${height}px` : String(height);
103
130
 
104
- return el;
105
- }
131
+ const sizeNum = typeof width === 'number' ? width : parseInt(String(width), 10);
132
+ if (sizeNum) {
133
+ styles.fontSize = `${Math.round(sizeNum * 0.4)}px`;
134
+ }
135
+ } else if (typeof this.config.size === 'number') {
136
+ styles.width = `${this.config.size}px`;
137
+ styles.height = `${this.config.size}px`;
138
+ styles.fontSize = `${Math.round(this.config.size * 0.4)}px`;
139
+ }
106
140
 
107
- private _createInitials(): HTMLSpanElement {
108
- const initialsEl = document.createElement('span');
109
- initialsEl.className = cls('avatarInitials');
110
- initialsEl.textContent = this._getInitials();
111
- return initialsEl;
141
+ return Object.keys(styles).length > 0 ? styles : undefined;
112
142
  }
113
143
 
114
144
  private _getInitials(): string {
@@ -4,6 +4,10 @@ import { EzBaseComponent, EzBaseComponentConfig } from '../EzBaseComponent.js';
4
4
 
5
5
  const cls = cx(styles);
6
6
 
7
+ declare const ez: {
8
+ _createElement(config: unknown): Promise<HTMLElement>;
9
+ };
10
+
7
11
  export interface EzBadgeConfig extends EzBaseComponentConfig {
8
12
  variant?: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';
9
13
  size?: 'sm' | 'lg';
@@ -21,53 +25,68 @@ export class EzBadge extends EzBaseComponent {
21
25
  declare config: EzBadgeConfig;
22
26
  declare el: HTMLSpanElement;
23
27
 
24
- render(): HTMLSpanElement {
28
+ async render(): Promise<HTMLSpanElement> {
25
29
  const cfg = this.config;
26
30
 
27
- const badge = document.createElement('span');
28
- badge.className = cls(
31
+ const classes = cls(
29
32
  'badge',
30
33
  cfg.variant || 'default',
31
34
  cfg.size,
32
35
  cfg.pill && 'pill',
33
36
  cfg.outline && 'outline',
34
- cfg.dot && 'dot'
37
+ cfg.dot && 'dot',
38
+ cfg.onClick && 'clickable'
35
39
  );
36
40
 
41
+ // Dot badge has no content
37
42
  if (cfg.dot) {
43
+ const badge = await ez._createElement({
44
+ eztype: 'span',
45
+ cls: classes
46
+ }) as HTMLSpanElement;
47
+
48
+ this.applyStyles(badge);
49
+ this.el = badge;
38
50
  return badge;
39
51
  }
40
52
 
53
+ const items: unknown[] = [];
54
+
41
55
  if (cfg.icon) {
42
- const icon = document.createElement('i');
43
- icon.className = cls('icon', cfg.icon);
44
- badge.appendChild(icon);
56
+ items.push({
57
+ eztype: 'i',
58
+ cls: [cls('icon'), cfg.icon].join(' ')
59
+ });
45
60
  }
46
61
 
47
62
  if (cfg.text !== undefined) {
48
- const text = document.createElement('span');
49
- text.className = cls('text');
50
- text.textContent = String(cfg.text);
51
- badge.appendChild(text);
63
+ items.push({
64
+ eztype: 'span',
65
+ cls: cls('text'),
66
+ text: String(cfg.text)
67
+ });
52
68
  }
53
69
 
54
70
  if (cfg.closable) {
55
- const close = document.createElement('button');
56
- close.type = 'button';
57
- close.className = cls('close');
58
- close.innerHTML = '<i class="fa-solid fa-xmark"></i>';
59
- close.addEventListener('click', (e: MouseEvent) => {
60
- e.stopPropagation();
61
- if (cfg.onClose) cfg.onClose(e);
62
- badge.remove();
71
+ items.push({
72
+ eztype: 'button',
73
+ type: 'button',
74
+ cls: cls('close'),
75
+ items: [{ eztype: 'i', cls: 'fa-solid fa-xmark' }],
76
+ onClick: (e: MouseEvent) => {
77
+ e.stopPropagation();
78
+ if (cfg.onClose) cfg.onClose(e);
79
+ this.el?.remove();
80
+ }
63
81
  });
64
- badge.appendChild(close);
65
82
  }
66
83
 
67
- if (cfg.onClick) {
68
- badge.classList.add(cls('clickable'));
69
- badge.addEventListener('click', cfg.onClick);
70
- }
84
+ const badge = await ez._createElement({
85
+ eztype: 'span',
86
+ cls: classes,
87
+ onClick: cfg.onClick,
88
+ items
89
+ }) as HTMLSpanElement;
71
90
 
72
91
  this.applyStyles(badge);
73
92
  this.el = badge;
@@ -124,7 +124,7 @@ export class EzButton extends EzBaseComponent {
124
124
  return items;
125
125
  }
126
126
 
127
- private _applyLoadingState(el: HTMLButtonElement, loading: boolean): void {
127
+ private async _applyLoadingState(el: HTMLButtonElement, loading: boolean): Promise<void> {
128
128
  const spinnerClass = cls('spinner');
129
129
 
130
130
  if (loading) {
@@ -132,8 +132,10 @@ export class EzButton extends EzBaseComponent {
132
132
  el.disabled = true;
133
133
 
134
134
  if (!el.querySelector(`.${spinnerClass}`)) {
135
- const spinner = document.createElement('span');
136
- spinner.className = spinnerClass;
135
+ const spinner = await ez._createElement({
136
+ eztype: 'span',
137
+ cls: spinnerClass
138
+ });
137
139
  el.insertBefore(spinner, el.firstChild);
138
140
  }
139
141
  } else {
@@ -25,20 +25,17 @@ export class EzButtonGroup extends EzBaseComponent {
25
25
 
26
26
  async render(): Promise<HTMLDivElement> {
27
27
  const cfg = this.config;
28
- const el = document.createElement('div');
29
-
30
- el.classList.add(cls('buttonGroup'));
31
28
 
29
+ const classes = [cls('buttonGroup')];
32
30
  if (cfg.vertical) {
33
- el.classList.add(cls('buttonGroupVertical'));
31
+ classes.push(cls('buttonGroupVertical'));
34
32
  }
35
33
 
36
- if (Array.isArray(cfg.items)) {
37
- for (const item of cfg.items) {
38
- const child = await ez._createElement(item, cfg.controller || null, this);
39
- el.appendChild(child);
40
- }
41
- }
34
+ const el = await ez._createElement({
35
+ eztype: 'div',
36
+ cls: classes.join(' '),
37
+ items: cfg.items || []
38
+ }, cfg.controller || null, this) as HTMLDivElement;
42
39
 
43
40
  this.applyStyles(el);
44
41
  this.el = el;
@@ -69,10 +69,11 @@ export class EzCard extends EzBaseComponent {
69
69
  result.push(this._buildHeader());
70
70
  }
71
71
 
72
- // Body
72
+ // Body - propagate parent CSS to children
73
73
  result.push({
74
74
  eztype: 'div',
75
75
  cls: noPadding ? [cls('body'), cls('noPadding')] : cls('body'),
76
+ css: this.config.css,
76
77
  items: items
77
78
  });
78
79
 
@@ -2,6 +2,7 @@ import { EzBaseComponent, EzBaseComponentConfig } from '../EzBaseComponent.js';
2
2
  import styles from './EzChart.module.scss';
3
3
 
4
4
  declare const ez: {
5
+ _createElement(config: unknown): Promise<HTMLElement>;
5
6
  registerComponent(name: string, component: unknown): void;
6
7
  };
7
8
 
@@ -123,23 +124,27 @@ export class EzChart extends EzBaseComponent {
123
124
 
124
125
  const { height = 280, cls = '' } = this.config;
125
126
 
126
- const el = document.createElement('div');
127
- el.className = `${styles.container} ${cls}`.trim();
128
- if (height) {
129
- el.style.height = typeof height === 'number' ? `${height}px` : height;
130
- }
131
-
132
- const canvas = document.createElement('canvas');
133
- el.appendChild(canvas);
134
-
135
- this.applyStyles(el);
136
-
137
- requestAnimationFrame(() => {
138
- this._initChart(canvas);
139
- });
127
+ const el = await ez._createElement({
128
+ eztype: 'div',
129
+ cls: [styles.container, cls].filter(Boolean).join(' '),
130
+ style: {
131
+ height: height ? (typeof height === 'number' ? `${height}px` : height) : undefined,
132
+ ...this.config.style as object
133
+ },
134
+ items: [
135
+ {
136
+ eztype: 'canvas',
137
+ _ezAfterRender: (canvas: HTMLCanvasElement) => {
138
+ this._canvas = canvas;
139
+ requestAnimationFrame(() => {
140
+ this._initChart(canvas);
141
+ });
142
+ }
143
+ }
144
+ ]
145
+ }) as HTMLElement;
140
146
 
141
147
  this._el = el;
142
- this._canvas = canvas;
143
148
  return el;
144
149
  }
145
150