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.
- package/components/EzBaseComponent.ts +100 -5
- package/components/EzComponent.ts +3 -3
- package/components/EzLabel.ts +12 -3
- package/components/avatar/EzAvatar.ts +84 -54
- package/components/badge/EzBadge.ts +43 -24
- package/components/button/EzButton.ts +5 -3
- package/components/button/EzButtonGroup.ts +7 -10
- package/components/card/EzCard.ts +2 -1
- package/components/chart/EzChart.ts +20 -15
- package/components/checkbox/EzCheckbox.ts +47 -43
- package/components/dataview/EzDataView.ts +14 -29
- package/components/dataview/modes/EzDataViewCards.ts +51 -41
- package/components/dataview/modes/EzDataViewGrid.ts +5 -2
- package/components/datepicker/EzDatePicker.ts +2 -2
- package/components/dialog/EzDialog.ts +84 -67
- package/components/dropdown/EzDropdown.ts +72 -58
- package/components/form/EzForm.ts +45 -37
- package/components/kanban/EzKanban.module.scss +221 -0
- package/components/kanban/EzKanban.ts +222 -0
- package/components/kanban/EzKanbanTypes.ts +166 -0
- package/components/kanban/board/EzKanbanBoard.ts +117 -0
- package/components/kanban/card/EzKanbanCard.module.scss +173 -0
- package/components/kanban/card/EzKanbanCard.ts +275 -0
- package/components/kanban/card/EzKanbanCardEditor.ts +209 -0
- package/components/kanban/column/EzKanbanColumn.ts +253 -0
- package/components/kanban/state/EzKanbanController.ts +373 -0
- package/components/kanban/state/EzKanbanDragDrop.ts +226 -0
- package/components/panel/EzPanel.ts +59 -68
- package/components/picker/EzPicker.module.scss +14 -0
- package/components/picker/EzPicker.ts +118 -0
- package/components/radio/EzRadio.ts +55 -47
- package/components/select/EzSelect.ts +48 -44
- package/components/skeleton/EzSkeleton.ts +31 -26
- package/components/switch/EzSwitch.ts +52 -44
- package/components/tabs/EzTabPanel.ts +52 -48
- package/components/textarea/EzTextarea.ts +69 -54
- package/components/timepicker/EzTimePicker.ts +2 -2
- package/components/tooltip/EzTooltip.ts +20 -33
- package/core/ez.ts +7 -0
- package/core/loader.ts +2 -0
- package/core/renderer.ts +80 -4
- package/core/styleShortcuts.ts +418 -0
- package/package.json +1 -1
|
@@ -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 SelectOption {
|
|
8
12
|
value: string | number;
|
|
9
13
|
label: string;
|
|
@@ -40,71 +44,71 @@ export class EzSelect extends EzBaseComponent {
|
|
|
40
44
|
this.onSelect = config.onSelect || null;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
render(): HTMLDivElement {
|
|
44
|
-
|
|
45
|
-
this.el.className = cls('select');
|
|
46
|
-
|
|
47
|
+
async render(): Promise<HTMLDivElement> {
|
|
48
|
+
const classes = [cls('select')];
|
|
47
49
|
if (this.config.cls) {
|
|
48
50
|
const clsValue = this.config.cls;
|
|
49
51
|
if (Array.isArray(clsValue)) {
|
|
50
|
-
clsValue.
|
|
52
|
+
classes.push(...clsValue.filter(Boolean) as string[]);
|
|
51
53
|
} else if (typeof clsValue === 'string') {
|
|
52
|
-
|
|
54
|
+
classes.push(clsValue);
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
this.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
this.el = await ez._createElement({
|
|
59
|
+
eztype: 'div',
|
|
60
|
+
cls: classes.join(' '),
|
|
61
|
+
items: [
|
|
62
|
+
{
|
|
63
|
+
eztype: 'button',
|
|
64
|
+
type: 'button',
|
|
65
|
+
cls: cls('selectTrigger'),
|
|
66
|
+
items: [
|
|
67
|
+
{ eztype: 'span', cls: cls('selectTriggerText') },
|
|
68
|
+
{ eztype: 'span', cls: cls('selectArrow'), html: '▾' }
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
eztype: 'div',
|
|
73
|
+
cls: cls('selectDropdown')
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}) as HTMLDivElement;
|
|
77
|
+
|
|
78
|
+
this._trigger = this.el.querySelector(`.${cls('selectTrigger')}`);
|
|
79
|
+
this._triggerText = this.el.querySelector(`.${cls('selectTriggerText')}`);
|
|
80
|
+
this._dropdown = this.el.querySelector(`.${cls('selectDropdown')}`);
|
|
73
81
|
|
|
74
82
|
this._buildOptions();
|
|
75
|
-
this.el.appendChild(this._dropdown);
|
|
76
|
-
|
|
77
83
|
this._updateDisplay();
|
|
78
84
|
this._bindEvents();
|
|
79
85
|
|
|
80
86
|
return this.el;
|
|
81
87
|
}
|
|
82
88
|
|
|
83
|
-
private _buildOptions(): void {
|
|
89
|
+
private async _buildOptions(): Promise<void> {
|
|
84
90
|
if (!this._dropdown) return;
|
|
85
91
|
this._dropdown.innerHTML = '';
|
|
86
92
|
|
|
87
|
-
this.options
|
|
88
|
-
const item = document.createElement('div');
|
|
89
|
-
item.className = cls('selectOption');
|
|
90
|
-
|
|
93
|
+
for (const opt of this.options) {
|
|
91
94
|
const value = typeof opt === 'object' ? opt.value : opt;
|
|
92
95
|
const label = typeof opt === 'object' ? opt.label : String(opt);
|
|
93
96
|
|
|
94
|
-
item
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
const item = await ez._createElement({
|
|
98
|
+
eztype: 'div',
|
|
99
|
+
cls: value === this.value
|
|
100
|
+
? [cls('selectOption'), cls('isSelected')].join(' ')
|
|
101
|
+
: cls('selectOption'),
|
|
102
|
+
'data-value': String(value),
|
|
103
|
+
text: label,
|
|
104
|
+
onClick: (e: MouseEvent) => {
|
|
105
|
+
e.stopPropagation();
|
|
106
|
+
this._selectOption(value);
|
|
107
|
+
}
|
|
104
108
|
});
|
|
105
109
|
|
|
106
|
-
this._dropdown
|
|
107
|
-
}
|
|
110
|
+
this._dropdown.appendChild(item);
|
|
111
|
+
}
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
private _updateDisplay(): void {
|
|
@@ -150,7 +154,7 @@ export class EzSelect extends EzBaseComponent {
|
|
|
150
154
|
}
|
|
151
155
|
};
|
|
152
156
|
|
|
153
|
-
document.addEventListener('click', this._outsideClickHandler);
|
|
157
|
+
document.addEventListener('click', this._outsideClickHandler, true);
|
|
154
158
|
|
|
155
159
|
this._trigger.addEventListener('keydown', (e) => {
|
|
156
160
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
@@ -232,7 +236,7 @@ export class EzSelect extends EzBaseComponent {
|
|
|
232
236
|
|
|
233
237
|
destroy(): void {
|
|
234
238
|
if (this._outsideClickHandler) {
|
|
235
|
-
document.removeEventListener('click', this._outsideClickHandler);
|
|
239
|
+
document.removeEventListener('click', this._outsideClickHandler, true);
|
|
236
240
|
}
|
|
237
241
|
}
|
|
238
242
|
}
|
|
@@ -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 EzSkeletonConfig extends EzBaseComponentConfig {
|
|
8
12
|
variant?: 'text' | 'circle' | 'rectangular';
|
|
9
13
|
animation?: 'pulse' | 'wave' | 'none';
|
|
@@ -18,53 +22,54 @@ export interface EzSkeletonConfig extends EzBaseComponentConfig {
|
|
|
18
22
|
export class EzSkeleton extends EzBaseComponent {
|
|
19
23
|
declare config: EzSkeletonConfig;
|
|
20
24
|
|
|
21
|
-
render(): HTMLElement {
|
|
25
|
+
async render(): Promise<HTMLElement> {
|
|
22
26
|
const cfg = this.config;
|
|
23
27
|
|
|
24
28
|
if (cfg.count && cfg.count > 1) {
|
|
25
|
-
const
|
|
26
|
-
wrapper.className = cls('skeletonGroup');
|
|
27
|
-
|
|
28
|
-
if (cfg.gap) {
|
|
29
|
-
wrapper.style.gap = typeof cfg.gap === 'number' ? `${cfg.gap}px` : cfg.gap;
|
|
30
|
-
}
|
|
31
|
-
|
|
29
|
+
const skeletonItems: unknown[] = [];
|
|
32
30
|
for (let i = 0; i < cfg.count; i++) {
|
|
33
|
-
|
|
34
|
-
wrapper.appendChild(skeleton);
|
|
31
|
+
skeletonItems.push(this._buildSkeletonConfig(cfg));
|
|
35
32
|
}
|
|
36
33
|
|
|
34
|
+
const wrapper = await ez._createElement({
|
|
35
|
+
eztype: 'div',
|
|
36
|
+
cls: cls('skeletonGroup'),
|
|
37
|
+
style: cfg.gap ? { gap: typeof cfg.gap === 'number' ? `${cfg.gap}px` : cfg.gap } : undefined,
|
|
38
|
+
items: skeletonItems
|
|
39
|
+
}) as HTMLElement;
|
|
40
|
+
|
|
37
41
|
return wrapper;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
return this.
|
|
44
|
+
return await ez._createElement(this._buildSkeletonConfig(cfg)) as HTMLElement;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
private
|
|
44
|
-
const
|
|
45
|
-
skeleton.className = cls(
|
|
46
|
-
'skeleton',
|
|
47
|
-
cfg.variant || 'text',
|
|
48
|
-
cfg.animation || 'pulse',
|
|
49
|
-
cfg.rounded && 'rounded'
|
|
50
|
-
);
|
|
47
|
+
private _buildSkeletonConfig(cfg: EzSkeletonConfig): unknown {
|
|
48
|
+
const style: Record<string, string> = {};
|
|
51
49
|
|
|
52
50
|
if (cfg.width) {
|
|
53
|
-
|
|
51
|
+
style.width = typeof cfg.width === 'number' ? `${cfg.width}px` : cfg.width;
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
if (cfg.height) {
|
|
57
|
-
|
|
55
|
+
style.height = typeof cfg.height === 'number' ? `${cfg.height}px` : cfg.height;
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
if (cfg.variant === 'circle') {
|
|
61
59
|
const size = cfg.size || 40;
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
style.width = `${size}px`;
|
|
61
|
+
style.height = `${size}px`;
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
return {
|
|
65
|
+
eztype: 'div',
|
|
66
|
+
cls: cls(
|
|
67
|
+
'skeleton',
|
|
68
|
+
cfg.variant || 'text',
|
|
69
|
+
cfg.animation || 'pulse',
|
|
70
|
+
cfg.rounded && 'rounded'
|
|
71
|
+
),
|
|
72
|
+
style: Object.keys(style).length > 0 ? style : undefined
|
|
73
|
+
};
|
|
69
74
|
}
|
|
70
75
|
}
|
|
@@ -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 EzSwitchConfig extends EzBaseComponentConfig {
|
|
8
12
|
size?: 'sm' | 'lg';
|
|
9
13
|
disabled?: boolean;
|
|
@@ -21,63 +25,67 @@ export class EzSwitch extends EzBaseComponent {
|
|
|
21
25
|
private _input: HTMLInputElement | null = null;
|
|
22
26
|
private _error: HTMLDivElement | null = null;
|
|
23
27
|
|
|
24
|
-
render(): HTMLLabelElement {
|
|
28
|
+
async render(): Promise<HTMLLabelElement> {
|
|
25
29
|
const cfg = this.config;
|
|
26
30
|
|
|
27
|
-
const wrapper = document.createElement('label');
|
|
28
|
-
wrapper.className = cls(
|
|
29
|
-
'switch',
|
|
30
|
-
cfg.size,
|
|
31
|
-
cfg.disabled && 'disabled',
|
|
32
|
-
cfg.labelPosition === 'left' && 'labelLeft'
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
const input = document.createElement('input');
|
|
36
|
-
input.type = 'checkbox';
|
|
37
|
-
input.className = cls('input');
|
|
38
|
-
input.checked = !!cfg.value;
|
|
39
|
-
|
|
40
|
-
if (cfg.disabled) input.disabled = true;
|
|
41
|
-
if (cfg.name) input.name = cfg.name;
|
|
42
|
-
|
|
43
31
|
if (cfg.name && cfg.formData) {
|
|
44
32
|
this.config.bind = `${cfg.formData}.${cfg.name}`;
|
|
45
33
|
}
|
|
46
34
|
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
onChange((e.target as HTMLInputElement).checked);
|
|
35
|
+
const items: unknown[] = [
|
|
36
|
+
{
|
|
37
|
+
eztype: 'input',
|
|
38
|
+
type: 'checkbox',
|
|
39
|
+
cls: cls('input'),
|
|
40
|
+
checked: !!cfg.value,
|
|
41
|
+
disabled: cfg.disabled,
|
|
42
|
+
name: cfg.name
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
eztype: 'span',
|
|
46
|
+
cls: cls('track'),
|
|
47
|
+
items: [{ eztype: 'span', cls: cls('thumb') }]
|
|
61
48
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
wrapper.appendChild(input);
|
|
65
|
-
wrapper.appendChild(track);
|
|
49
|
+
];
|
|
66
50
|
|
|
67
51
|
if (cfg.label) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
52
|
+
items.push({
|
|
53
|
+
eztype: 'span',
|
|
54
|
+
cls: cls('label'),
|
|
55
|
+
text: cfg.label
|
|
56
|
+
});
|
|
72
57
|
}
|
|
73
58
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
59
|
+
items.push({
|
|
60
|
+
eztype: 'div',
|
|
61
|
+
cls: cls('fieldError')
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const wrapper = await ez._createElement({
|
|
65
|
+
eztype: 'label',
|
|
66
|
+
cls: cls(
|
|
67
|
+
'switch',
|
|
68
|
+
cfg.size,
|
|
69
|
+
cfg.disabled && 'disabled',
|
|
70
|
+
cfg.labelPosition === 'left' && 'labelLeft'
|
|
71
|
+
),
|
|
72
|
+
items
|
|
73
|
+
}) as HTMLLabelElement;
|
|
77
74
|
|
|
78
75
|
this._wrapper = wrapper;
|
|
79
|
-
this._input = input;
|
|
80
|
-
this._error =
|
|
76
|
+
this._input = wrapper.querySelector('input');
|
|
77
|
+
this._error = wrapper.querySelector(`.${cls('fieldError')}`);
|
|
78
|
+
|
|
79
|
+
if (this._input) {
|
|
80
|
+
this.applyCommonBindings(this._input);
|
|
81
|
+
|
|
82
|
+
const onChange = this._createOnChangeHandler();
|
|
83
|
+
this._input.addEventListener('change', e => {
|
|
84
|
+
if (onChange) {
|
|
85
|
+
onChange((e.target as HTMLInputElement).checked);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
81
89
|
|
|
82
90
|
return wrapper;
|
|
83
91
|
}
|
|
@@ -4,6 +4,7 @@ import { EzBaseComponent, EzBaseComponentConfig } from '../EzBaseComponent.js';
|
|
|
4
4
|
|
|
5
5
|
declare const ez: {
|
|
6
6
|
_createElement(config: unknown, controller?: string | null, parent?: unknown): Promise<HTMLElement>;
|
|
7
|
+
_createChildElements(items: unknown[], controller: string | null, parent: unknown): Promise<Node[]>;
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
const cls = cx(styles);
|
|
@@ -134,19 +135,19 @@ export class EzTabPanel extends EzBaseComponent {
|
|
|
134
135
|
|
|
135
136
|
async render(): Promise<HTMLElement> {
|
|
136
137
|
const cfg = this.config;
|
|
137
|
-
const el = document.createElement('div');
|
|
138
138
|
|
|
139
|
-
el.
|
|
139
|
+
const el = await ez._createElement({
|
|
140
|
+
eztype: 'div',
|
|
141
|
+
cls: cls('tabPanel', cfg.variant),
|
|
142
|
+
style: cfg.style,
|
|
143
|
+
items: [
|
|
144
|
+
{ eztype: 'div', cls: cls('tabHeader') },
|
|
145
|
+
{ eztype: 'div', cls: cls('tabContent') }
|
|
146
|
+
]
|
|
147
|
+
}, cfg.controller || null, this) as HTMLElement;
|
|
140
148
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
this._headerEl = document.createElement('div');
|
|
146
|
-
this._headerEl.classList.add(cls('tabHeader'));
|
|
147
|
-
|
|
148
|
-
this._contentEl = document.createElement('div');
|
|
149
|
-
this._contentEl.classList.add(cls('tabContent'));
|
|
149
|
+
this._headerEl = el.querySelector(`.${cls('tabHeader')}`);
|
|
150
|
+
this._contentEl = el.querySelector(`.${cls('tabContent')}`);
|
|
150
151
|
|
|
151
152
|
const tabs = cfg.tabs || [];
|
|
152
153
|
|
|
@@ -160,10 +161,6 @@ export class EzTabPanel extends EzBaseComponent {
|
|
|
160
161
|
await this._createTab(tab, i);
|
|
161
162
|
}
|
|
162
163
|
|
|
163
|
-
el.appendChild(this._headerEl);
|
|
164
|
-
el.appendChild(this._contentEl);
|
|
165
|
-
|
|
166
|
-
this.applyStyles(el);
|
|
167
164
|
this.el = el;
|
|
168
165
|
|
|
169
166
|
if (activeTabId != null) {
|
|
@@ -178,53 +175,60 @@ export class EzTabPanel extends EzBaseComponent {
|
|
|
178
175
|
return el;
|
|
179
176
|
}
|
|
180
177
|
|
|
181
|
-
private
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
this._tabConfigs.set(tabId, tab);
|
|
185
|
-
|
|
186
|
-
const tabBtn = document.createElement('button');
|
|
187
|
-
tabBtn.classList.add(cls('tab'));
|
|
188
|
-
tabBtn.setAttribute('data-tab-id', String(tabId));
|
|
178
|
+
private _buildTabButtonConfig(tab: TabConfig, tabId: string | number): unknown {
|
|
179
|
+
const buttonItems: unknown[] = [];
|
|
189
180
|
|
|
190
181
|
if (tab.icon) {
|
|
191
|
-
|
|
192
|
-
icon.className = tab.icon;
|
|
193
|
-
tabBtn.appendChild(icon);
|
|
182
|
+
buttonItems.push({ eztype: 'i', cls: tab.icon });
|
|
194
183
|
}
|
|
195
184
|
|
|
196
185
|
if (tab.title) {
|
|
197
|
-
|
|
198
|
-
span.textContent = tab.title;
|
|
199
|
-
tabBtn.appendChild(span);
|
|
186
|
+
buttonItems.push({ eztype: 'span', text: tab.title });
|
|
200
187
|
}
|
|
201
188
|
|
|
202
189
|
if (tab.closable) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
e
|
|
208
|
-
|
|
190
|
+
buttonItems.push({
|
|
191
|
+
eztype: 'span',
|
|
192
|
+
cls: cls('tabClose'),
|
|
193
|
+
items: [{ eztype: 'i', cls: 'fa-solid fa-xmark' }],
|
|
194
|
+
onClick: (e: MouseEvent) => {
|
|
195
|
+
e.stopPropagation();
|
|
196
|
+
this.removeTab(tabId);
|
|
197
|
+
}
|
|
209
198
|
});
|
|
210
|
-
tabBtn.appendChild(closeBtn);
|
|
211
199
|
}
|
|
212
200
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
201
|
+
return {
|
|
202
|
+
eztype: 'button',
|
|
203
|
+
type: 'button',
|
|
204
|
+
cls: cls('tab'),
|
|
205
|
+
'data-tab-id': String(tabId),
|
|
206
|
+
items: buttonItems,
|
|
207
|
+
onClick: () => this.setActiveTab(tabId)
|
|
208
|
+
};
|
|
209
|
+
}
|
|
216
210
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
211
|
+
private async _buildTabPaneConfig(tab: TabConfig, tabId: string | number): Promise<unknown> {
|
|
212
|
+
return {
|
|
213
|
+
eztype: 'div',
|
|
214
|
+
cls: cls('tabPane'),
|
|
215
|
+
'data-tab-id': String(tabId),
|
|
216
|
+
items: tab.items || []
|
|
217
|
+
};
|
|
218
|
+
}
|
|
220
219
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
220
|
+
private async _createTab(tab: TabConfig, index: number): Promise<string | number> {
|
|
221
|
+
const tabId = tab.id ?? index;
|
|
222
|
+
|
|
223
|
+
this._tabConfigs.set(tabId, tab);
|
|
224
|
+
|
|
225
|
+
const tabBtnConfig = this._buildTabButtonConfig(tab, tabId);
|
|
226
|
+
const tabBtn = await ez._createElement(tabBtnConfig, null, this) as HTMLElement;
|
|
227
|
+
this._headerEl!.appendChild(tabBtn);
|
|
228
|
+
this._tabElements.set(tabId, tabBtn);
|
|
227
229
|
|
|
230
|
+
const paneConfig = await this._buildTabPaneConfig(tab, tabId);
|
|
231
|
+
const pane = await ez._createElement(paneConfig, this.config.controller || null, this) as HTMLElement;
|
|
228
232
|
this._contentEl!.appendChild(pane);
|
|
229
233
|
this._contentElements.set(tabId, pane);
|
|
230
234
|
|
|
@@ -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 EzTextareaConfig extends EzBaseComponentConfig {
|
|
8
12
|
size?: 'sm' | 'lg';
|
|
9
13
|
disabled?: boolean;
|
|
@@ -29,77 +33,88 @@ export class EzTextarea extends EzBaseComponent {
|
|
|
29
33
|
private _error: HTMLDivElement | null = null;
|
|
30
34
|
private _counter: HTMLDivElement | null = null;
|
|
31
35
|
|
|
32
|
-
render(): HTMLDivElement {
|
|
36
|
+
async render(): Promise<HTMLDivElement> {
|
|
33
37
|
const cfg = this.config;
|
|
34
38
|
|
|
35
|
-
const wrapper = document.createElement('div');
|
|
36
|
-
wrapper.className = cls(
|
|
37
|
-
'textareaGroup',
|
|
38
|
-
cfg.size,
|
|
39
|
-
cfg.disabled && 'disabled',
|
|
40
|
-
cfg.resize === false && 'noResize',
|
|
41
|
-
cfg.rows && 'hasRows'
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
const textarea = document.createElement('textarea');
|
|
45
|
-
textarea.className = cls('textarea');
|
|
46
|
-
textarea.placeholder = cfg.placeholder || '';
|
|
47
|
-
if (cfg.value !== undefined) textarea.value = cfg.value;
|
|
48
|
-
|
|
49
|
-
if (cfg.rows) textarea.rows = cfg.rows;
|
|
50
|
-
const paddingY = cfg.size === 'sm' ? 16 : cfg.size === 'lg' ? 24 : 20;
|
|
51
|
-
if (cfg.minRows) textarea.style.minHeight = `calc(${cfg.minRows * 1.5}em + ${paddingY}px)`;
|
|
52
|
-
if (cfg.maxRows) textarea.style.maxHeight = `calc(${cfg.maxRows * 1.5}em + ${paddingY}px)`;
|
|
53
|
-
if (cfg.maxLength) textarea.maxLength = cfg.maxLength;
|
|
54
|
-
if (cfg.disabled) textarea.disabled = true;
|
|
55
|
-
if (cfg.readonly) textarea.readOnly = true;
|
|
56
|
-
|
|
57
39
|
if (cfg.name && cfg.formData) {
|
|
58
40
|
this.config.bind = `${cfg.formData}.${cfg.name}`;
|
|
59
41
|
}
|
|
60
42
|
|
|
61
|
-
|
|
62
|
-
|
|
43
|
+
const paddingY = cfg.size === 'sm' ? 16 : cfg.size === 'lg' ? 24 : 20;
|
|
44
|
+
const textareaStyle: Record<string, string> = {};
|
|
45
|
+
if (cfg.minRows) textareaStyle.minHeight = `calc(${cfg.minRows * 1.5}em + ${paddingY}px)`;
|
|
46
|
+
if (cfg.maxRows) textareaStyle.maxHeight = `calc(${cfg.maxRows * 1.5}em + ${paddingY}px)`;
|
|
47
|
+
|
|
48
|
+
const items: unknown[] = [
|
|
49
|
+
{
|
|
50
|
+
eztype: 'textarea',
|
|
51
|
+
cls: cls('textarea'),
|
|
52
|
+
placeholder: cfg.placeholder || '',
|
|
53
|
+
value: cfg.value,
|
|
54
|
+
rows: cfg.rows,
|
|
55
|
+
maxLength: cfg.maxLength,
|
|
56
|
+
disabled: cfg.disabled,
|
|
57
|
+
readOnly: cfg.readonly,
|
|
58
|
+
'data-ez-field': cfg.name,
|
|
59
|
+
style: Object.keys(textareaStyle).length > 0 ? textareaStyle : undefined
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
if (cfg.showCount) {
|
|
64
|
+
items.push({
|
|
65
|
+
eztype: 'div',
|
|
66
|
+
cls: cls('counter')
|
|
67
|
+
});
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
|
|
70
|
+
items.push({
|
|
71
|
+
eztype: 'div',
|
|
72
|
+
cls: cls('fieldError')
|
|
73
|
+
});
|
|
66
74
|
|
|
67
|
-
const
|
|
75
|
+
const wrapper = await ez._createElement({
|
|
76
|
+
eztype: 'div',
|
|
77
|
+
cls: cls(
|
|
78
|
+
'textareaGroup',
|
|
79
|
+
cfg.size,
|
|
80
|
+
cfg.disabled && 'disabled',
|
|
81
|
+
cfg.resize === false && 'noResize',
|
|
82
|
+
cfg.rows && 'hasRows'
|
|
83
|
+
),
|
|
84
|
+
items
|
|
85
|
+
}) as HTMLDivElement;
|
|
68
86
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
87
|
+
this._wrapper = wrapper;
|
|
88
|
+
this._textarea = wrapper.querySelector('textarea');
|
|
89
|
+
this._error = wrapper.querySelector(`.${cls('fieldError')}`);
|
|
90
|
+
this._counter = wrapper.querySelector(`.${cls('counter')}`);
|
|
73
91
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
92
|
+
if (this._textarea) {
|
|
93
|
+
this.applyCommonBindings(this._textarea);
|
|
77
94
|
|
|
78
|
-
|
|
79
|
-
this._updateCounter((e.target as HTMLTextAreaElement).value.length);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
95
|
+
const onChange = this._createOnChangeHandler();
|
|
82
96
|
|
|
83
|
-
|
|
97
|
+
this._textarea.addEventListener('input', e => {
|
|
98
|
+
if (onChange) {
|
|
99
|
+
onChange((e.target as HTMLTextAreaElement).value);
|
|
100
|
+
}
|
|
84
101
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this._counter = counter;
|
|
89
|
-
this._updateCounter(0);
|
|
90
|
-
wrapper.appendChild(counter);
|
|
91
|
-
}
|
|
102
|
+
if (cfg.autoResize) {
|
|
103
|
+
this._autoResize(this._textarea!);
|
|
104
|
+
}
|
|
92
105
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
if (cfg.showCount && this._counter) {
|
|
107
|
+
this._updateCounter((e.target as HTMLTextAreaElement).value.length);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
96
110
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
111
|
+
if (cfg.showCount) {
|
|
112
|
+
this._updateCounter(0);
|
|
113
|
+
}
|
|
100
114
|
|
|
101
|
-
|
|
102
|
-
|
|
115
|
+
if (cfg.autoResize) {
|
|
116
|
+
requestAnimationFrame(() => this._autoResize(this._textarea!));
|
|
117
|
+
}
|
|
103
118
|
}
|
|
104
119
|
|
|
105
120
|
return wrapper;
|