@shival99/z-ui 2.1.28 → 2.1.30
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/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs +2 -2
- package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-table.mjs +721 -719
- package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -1
- package/package.json +1 -1
- package/types/shival99-z-ui-components-z-calendar.d.ts +4 -4
- package/types/shival99-z-ui-components-z-select.d.ts +1 -1
|
@@ -58,754 +58,272 @@ const Z_TABLE_DEFAULT_MAX_VISIBLE_ACTIONS = 3;
|
|
|
58
58
|
/** Default size variant for the overflow dropdown trigger button */
|
|
59
59
|
const Z_TABLE_DEFAULT_DROPDOWN_BUTTON_SIZE = 'sm';
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}, ...(ngDevMode ? [{ debugName: "allActions" }] : []));
|
|
79
|
-
shouldShowAsButtons = computed(() => {
|
|
80
|
-
const actions = this.allActions();
|
|
81
|
-
const maxVisible = this.zConfig().maxVisible ?? Z_TABLE_DEFAULT_MAX_VISIBLE_ACTIONS;
|
|
82
|
-
return actions.length <= maxVisible;
|
|
83
|
-
}, ...(ngDevMode ? [{ debugName: "shouldShowAsButtons" }] : []));
|
|
84
|
-
actionStates = computed(() => {
|
|
85
|
-
const row = this.zRow();
|
|
86
|
-
const actions = this.allActions();
|
|
87
|
-
const states = {};
|
|
88
|
-
for (const action of actions) {
|
|
89
|
-
const isHidden = typeof action.hidden === 'function' ? action.hidden(row) : (action.hidden ?? false);
|
|
90
|
-
const isDisabled = typeof action.disabled === 'function' ? action.disabled(row) : (action.disabled ?? false);
|
|
91
|
-
const isLoading = typeof action.loading === 'function' ? action.loading(row) : (action.loading ?? false);
|
|
92
|
-
states[action.key] = {
|
|
93
|
-
visible: !isHidden,
|
|
94
|
-
loading: isLoading,
|
|
95
|
-
disabled: isDisabled || isLoading,
|
|
96
|
-
tooltipState: this._getTooltipState(action.tooltip),
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
return states;
|
|
100
|
-
}, ...(ngDevMode ? [{ debugName: "actionStates" }] : []));
|
|
101
|
-
dropdownItems = computed(() => {
|
|
102
|
-
const row = this.zRow();
|
|
103
|
-
return this.allActions().map(action => {
|
|
104
|
-
const isDisabled = typeof action.disabled === 'function' ? action.disabled(row) : (action.disabled ?? false);
|
|
105
|
-
const isLoading = typeof action.loading === 'function' ? action.loading(row) : (action.loading ?? false);
|
|
106
|
-
return {
|
|
107
|
-
label: action.label ?? action.key,
|
|
108
|
-
icon: action.icon,
|
|
109
|
-
iconSize: action?.iconSize || '18',
|
|
110
|
-
loading: isLoading,
|
|
111
|
-
disabled: isDisabled || isLoading,
|
|
112
|
-
class: action.class,
|
|
113
|
-
divide: action.divide,
|
|
114
|
-
onClick: () => {
|
|
115
|
-
if (isDisabled || isLoading) {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
this._emitActionClick(action);
|
|
119
|
-
},
|
|
120
|
-
};
|
|
121
|
-
});
|
|
122
|
-
}, ...(ngDevMode ? [{ debugName: "dropdownItems" }] : []));
|
|
123
|
-
_getTooltipState(tooltip) {
|
|
124
|
-
if (!tooltip) {
|
|
125
|
-
return { content: '', alwaysShow: false };
|
|
126
|
-
}
|
|
127
|
-
if (typeof tooltip === 'string') {
|
|
128
|
-
return { content: tooltip, alwaysShow: true };
|
|
129
|
-
}
|
|
61
|
+
// ─── Column Visibility Pre-filter ────────────────────────────────────────────
|
|
62
|
+
/**
|
|
63
|
+
* Recursively filters columns based on their `visible` property.
|
|
64
|
+
* This runs BEFORE TanStack table creation — columns excluded here
|
|
65
|
+
* won't generate ColumnDef entries at all (unlike columnVisibility state
|
|
66
|
+
* which hides columns but keeps them in the column model).
|
|
67
|
+
*/
|
|
68
|
+
const filterVisibleColumns = (columns) => columns
|
|
69
|
+
.filter(col => {
|
|
70
|
+
const { visible } = col;
|
|
71
|
+
if (visible === undefined) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return typeof visible === 'function' ? visible() : visible;
|
|
75
|
+
})
|
|
76
|
+
.map(col => {
|
|
77
|
+
if (col.columns && col.columns.length > 0) {
|
|
130
78
|
return {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
position: tooltip.position,
|
|
134
|
-
arrow: tooltip.arrow,
|
|
135
|
-
offset: tooltip.offset,
|
|
136
|
-
maxWidth: tooltip.maxWidth,
|
|
79
|
+
...col,
|
|
80
|
+
columns: filterVisibleColumns(col.columns),
|
|
137
81
|
};
|
|
138
82
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
83
|
+
return col;
|
|
84
|
+
});
|
|
85
|
+
// ─── Config Type Guards ──────────────────────────────────────────────────────
|
|
86
|
+
/**
|
|
87
|
+
* Checks if a config value is a plain object (config struct) vs a primitive/template.
|
|
88
|
+
* Used to distinguish shorthand content (string/TemplateRef) from full config objects
|
|
89
|
+
* like ZTableHeaderColumnConfig, ZTableBodyColumnConfig, etc.
|
|
90
|
+
*/
|
|
91
|
+
const isObjectConfig = (config) => {
|
|
92
|
+
if (!config || typeof config !== 'object') {
|
|
93
|
+
return false;
|
|
146
94
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
95
|
+
return config.constructor === Object;
|
|
96
|
+
};
|
|
97
|
+
/** Type guard: is this a full header config object (not just content shorthand)? */
|
|
98
|
+
const isHeaderConfig = (config) => isObjectConfig(config);
|
|
99
|
+
/** Type guard: is this a full body config object (not just content shorthand)? */
|
|
100
|
+
const isBodyConfig = (config) => isObjectConfig(config);
|
|
101
|
+
/** Type guard: is this a full footer config object (not just content shorthand)? */
|
|
102
|
+
const isFooterConfig = (config) => isObjectConfig(config);
|
|
103
|
+
// ─── Config Extractors ───────────────────────────────────────────────────────
|
|
104
|
+
/**
|
|
105
|
+
* Internal helper that normalizes header/footer config into a consistent shape.
|
|
106
|
+
* Handles both shorthand (just content) and full config objects.
|
|
107
|
+
*/
|
|
108
|
+
const getHeaderOrFooterConfigInternal = (col, type, footerRowIndex = 0) => {
|
|
109
|
+
const empty = {
|
|
110
|
+
content: undefined,
|
|
111
|
+
class: undefined,
|
|
112
|
+
style: undefined,
|
|
113
|
+
align: undefined,
|
|
114
|
+
tooltip: undefined,
|
|
115
|
+
rowSpan: undefined,
|
|
116
|
+
colSpan: undefined,
|
|
117
|
+
contentClass: undefined,
|
|
118
|
+
contentStyle: undefined,
|
|
119
|
+
};
|
|
120
|
+
if (!col) {
|
|
121
|
+
return empty;
|
|
153
122
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
action,
|
|
160
|
-
});
|
|
123
|
+
const footer = Array.isArray(col.footer) ? col.footer[footerRowIndex] : col.footer;
|
|
124
|
+
const config = type === 'header' ? col.header : footer;
|
|
125
|
+
const isConfigFn = type === 'header' ? isHeaderConfig : isFooterConfig;
|
|
126
|
+
if (!isConfigFn(config)) {
|
|
127
|
+
return { ...empty, content: config };
|
|
161
128
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
type="button"
|
|
199
|
-
z-button
|
|
200
|
-
zTypeIcon="lucideEllipsis"
|
|
201
|
-
[zSize]="zDropdownButtonSize()"
|
|
202
|
-
zType="outline"
|
|
203
|
-
[zWave]="false"
|
|
204
|
-
></button>
|
|
205
|
-
</z-dropdown-menu>
|
|
206
|
-
}
|
|
207
|
-
</div>
|
|
208
|
-
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "component", type: ZDropdownMenuComponent, selector: "z-dropdown-menu", inputs: ["zItems", "zLabel", "zIcon", "zButtonType", "zPosition", "zButtonSize", "zOffset", "zMinWidth", "zMaxWidth", "zDisabled", "zWave"], outputs: ["zOnItemClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
209
|
-
}
|
|
210
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableActionsComponent, decorators: [{
|
|
211
|
-
type: Component,
|
|
212
|
-
args: [{ selector: 'z-table-actions', imports: [ZButtonComponent, ZTooltipDirective, ZDropdownMenuComponent], standalone: true, template: `
|
|
213
|
-
<div class="z-table-actions flex items-center justify-center gap-1">
|
|
214
|
-
@if (shouldShowAsButtons()) {
|
|
215
|
-
@for (action of allActions(); track action.key) {
|
|
216
|
-
@if (actionStates()[action.key].visible) {
|
|
217
|
-
<button
|
|
218
|
-
type="button"
|
|
219
|
-
z-button
|
|
220
|
-
z-tooltip
|
|
221
|
-
[zType]="action.type ?? 'outline'"
|
|
222
|
-
[zSize]="action.size ?? 'sm'"
|
|
223
|
-
[zTypeIcon]="action.icon"
|
|
224
|
-
zSizeIcon="14"
|
|
225
|
-
[zLabel]="action.label ?? ''"
|
|
226
|
-
[zLoading]="actionStates()[action.key].loading"
|
|
227
|
-
[zDisabled]="actionStates()[action.key].disabled"
|
|
228
|
-
[class]="action.class ?? ''"
|
|
229
|
-
[zContent]="actionStates()[action.key].tooltipState.content"
|
|
230
|
-
[zAlwaysShow]="actionStates()[action.key].tooltipState.alwaysShow"
|
|
231
|
-
[zArrow]="actionStates()[action.key].tooltipState.arrow ?? true"
|
|
232
|
-
[zOffset]="actionStates()[action.key].tooltipState.offset ?? 8"
|
|
233
|
-
[zMaxWidth]="actionStates()[action.key].tooltipState.maxWidth ?? '250px'"
|
|
234
|
-
(click)="_onActionClick(action, $event)"
|
|
235
|
-
></button>
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
} @else {
|
|
239
|
-
<z-dropdown-menu
|
|
240
|
-
[zItems]="dropdownItems()"
|
|
241
|
-
zPosition="bottom-right"
|
|
242
|
-
[zButtonSize]="zDropdownButtonSize()"
|
|
243
|
-
[zMinWidth]="160"
|
|
244
|
-
(zOnItemClick)="_onDropdownItemClick($event)"
|
|
245
|
-
>
|
|
246
|
-
<button
|
|
247
|
-
type="button"
|
|
248
|
-
z-button
|
|
249
|
-
zTypeIcon="lucideEllipsis"
|
|
250
|
-
[zSize]="zDropdownButtonSize()"
|
|
251
|
-
zType="outline"
|
|
252
|
-
[zWave]="false"
|
|
253
|
-
></button>
|
|
254
|
-
</z-dropdown-menu>
|
|
255
|
-
}
|
|
256
|
-
</div>
|
|
257
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
|
|
258
|
-
}], propDecorators: { zConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zConfig", required: true }] }], zRow: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRow", required: true }] }], zRowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRowId", required: true }] }], zDropdownButtonSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDropdownButtonSize", required: false }] }], zActionClick: [{ type: i0.Output, args: ["zActionClick"] }] } });
|
|
259
|
-
|
|
260
|
-
class ZTableContentEditorComponent {
|
|
261
|
-
zValue = input(...(ngDevMode ? [undefined, { debugName: "zValue" }] : []));
|
|
262
|
-
zConfig = input.required(...(ngDevMode ? [{ debugName: "zConfig" }] : []));
|
|
263
|
-
zCommit = output();
|
|
264
|
-
zCancel = output();
|
|
265
|
-
draftValue = signal(null, ...(ngDevMode ? [{ debugName: "draftValue" }] : []));
|
|
266
|
-
controlClass = computed(() => zMergeClasses('z-table-embedded-control', this.zConfig().class), ...(ngDevMode ? [{ debugName: "controlClass" }] : []));
|
|
267
|
-
inputType = computed(() => this.zConfig().type === 'number' ? 'number' : 'text', ...(ngDevMode ? [{ debugName: "inputType" }] : []));
|
|
268
|
-
_host = inject(ElementRef);
|
|
269
|
-
_finished = false;
|
|
270
|
-
_inputControl = null;
|
|
271
|
-
_selectControl = null;
|
|
272
|
-
_calendarControl = null;
|
|
273
|
-
_activated = false;
|
|
274
|
-
_ignoreNextCalendarChange = false;
|
|
275
|
-
constructor() {
|
|
276
|
-
effect(() => {
|
|
277
|
-
const value = this.zValue();
|
|
278
|
-
this.draftValue.set(value ?? null);
|
|
279
|
-
});
|
|
280
|
-
afterNextRender(() => this._activateControl());
|
|
129
|
+
const typedConfig = config;
|
|
130
|
+
return {
|
|
131
|
+
content: typedConfig.content,
|
|
132
|
+
class: typedConfig.class,
|
|
133
|
+
style: typedConfig.style,
|
|
134
|
+
align: typedConfig.align,
|
|
135
|
+
tooltip: typedConfig.tooltip,
|
|
136
|
+
rowSpan: typedConfig.rowSpan,
|
|
137
|
+
colSpan: typedConfig.colSpan,
|
|
138
|
+
contentClass: typedConfig.contentClass,
|
|
139
|
+
contentStyle: typedConfig.contentStyle,
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
/** Extract and normalize header config from a column definition */
|
|
143
|
+
const getHeaderConfig = (col) => getHeaderOrFooterConfigInternal(col, 'header');
|
|
144
|
+
/**
|
|
145
|
+
* Extract and normalize body config from a column definition.
|
|
146
|
+
* Resolves dynamic properties (class, style, rowSpan, etc.) when CellContext is provided.
|
|
147
|
+
*/
|
|
148
|
+
const getBodyConfig = (col, ctx) => {
|
|
149
|
+
const empty = {
|
|
150
|
+
content: undefined,
|
|
151
|
+
type: 'default',
|
|
152
|
+
tagColor: 'primary',
|
|
153
|
+
class: undefined,
|
|
154
|
+
style: undefined,
|
|
155
|
+
align: undefined,
|
|
156
|
+
rowSpan: undefined,
|
|
157
|
+
colSpan: undefined,
|
|
158
|
+
contentClass: undefined,
|
|
159
|
+
contentStyle: undefined,
|
|
160
|
+
tooltip: undefined,
|
|
161
|
+
popover: undefined,
|
|
162
|
+
};
|
|
163
|
+
if (!col) {
|
|
164
|
+
return empty;
|
|
281
165
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
queueMicrotask(() => this._activateControl());
|
|
166
|
+
if (!isBodyConfig(col.body)) {
|
|
167
|
+
return { ...empty, content: col.body };
|
|
285
168
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
169
|
+
const { body } = col;
|
|
170
|
+
const rowSpan = typeof body.rowSpan === 'function' && ctx ? body.rowSpan(ctx) : body.rowSpan;
|
|
171
|
+
const colSpan = typeof body.colSpan === 'function' && ctx ? body.colSpan(ctx) : body.colSpan;
|
|
172
|
+
const classValue = typeof body.class === 'function' && ctx ? body.class(ctx) : body.class;
|
|
173
|
+
const styleValue = typeof body.style === 'function' && ctx ? body.style(ctx) : body.style;
|
|
174
|
+
const contentClass = typeof body.contentClass === 'function' && ctx ? body.contentClass(ctx) : body.contentClass;
|
|
175
|
+
const contentStyle = typeof body.contentStyle === 'function' && ctx ? body.contentStyle(ctx) : body.contentStyle;
|
|
176
|
+
const tooltip = typeof body.tooltip === 'function' && ctx ? body.tooltip(ctx) : body.tooltip;
|
|
177
|
+
const popover = typeof body.popover === 'function' && ctx ? body.popover(ctx) : body.popover;
|
|
178
|
+
const tagColor = typeof body.tagColor === 'function' && ctx ? body.tagColor(ctx) : body.tagColor;
|
|
179
|
+
return {
|
|
180
|
+
content: body.content,
|
|
181
|
+
type: body.type || 'default',
|
|
182
|
+
tagColor: tagColor || 'primary',
|
|
183
|
+
class: classValue,
|
|
184
|
+
style: styleValue,
|
|
185
|
+
align: body.align,
|
|
186
|
+
rowSpan: typeof rowSpan === 'number' ? rowSpan : undefined,
|
|
187
|
+
colSpan: typeof colSpan === 'number' ? colSpan : undefined,
|
|
188
|
+
contentClass,
|
|
189
|
+
contentStyle: contentStyle,
|
|
190
|
+
tooltip,
|
|
191
|
+
popover,
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
const getFooterConfig = (col, footerRowIndex = 0) => getHeaderOrFooterConfigInternal(col, 'footer', footerRowIndex);
|
|
195
|
+
/** Ưu tiên label riêng, sau đó dùng tooltip dạng chuỗi cho action trong dropdown. */
|
|
196
|
+
const getZTableActionDropdownLabel = (action) => action.label ?? (typeof action.tooltip === 'string' ? action.tooltip : action.key);
|
|
197
|
+
// ─── Shortcut Accessors ──────────────────────────────────────────────────────
|
|
198
|
+
// These convenience functions extract a single property from the relevant config.
|
|
199
|
+
const getHeaderContent = (col) => getHeaderConfig(col).content;
|
|
200
|
+
const getBodyContent = (col) => {
|
|
201
|
+
if (!col?.body) {
|
|
202
|
+
return undefined;
|
|
289
203
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
204
|
+
return isBodyConfig(col.body) ? col.body.content : col.body;
|
|
205
|
+
};
|
|
206
|
+
const getFooterContent = (col, footerRowIndex = 0) => getFooterConfig(col, footerRowIndex).content;
|
|
207
|
+
const getBodyRowSpan = (col, ctx) => getBodyConfig(col, ctx).rowSpan;
|
|
208
|
+
const getBodyColSpan = (col, ctx) => getBodyConfig(col, ctx).colSpan;
|
|
209
|
+
const getHeaderRowSpan = (col) => getHeaderConfig(col).rowSpan;
|
|
210
|
+
const getHeaderColSpan = (col) => getHeaderConfig(col).colSpan;
|
|
211
|
+
const getFooterRowSpan = (col, footerRowIndex = 0) => getFooterConfig(col, footerRowIndex).rowSpan;
|
|
212
|
+
const getFooterColSpan = (col, footerRowIndex = 0) => getFooterConfig(col, footerRowIndex).colSpan;
|
|
213
|
+
// ─── Icon Syntax Parsing ─────────────────────────────────────────────────────
|
|
214
|
+
/**
|
|
215
|
+
* Parses inline icon syntax: `"Total [icon:lucideTrendingUp|size:16|class:text-green] Revenue"`
|
|
216
|
+
* Returns an array of text and icon segments for rendering by ZTableIconTextComponent.
|
|
217
|
+
*/
|
|
218
|
+
function parseIconString(content) {
|
|
219
|
+
if (!content || typeof content !== 'string') {
|
|
220
|
+
return [{ type: 'text', value: content || '' }];
|
|
293
221
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
222
|
+
const parts = [];
|
|
223
|
+
const iconRegex = /\[icon:([^\]]+)\]/g;
|
|
224
|
+
let lastIndex = 0;
|
|
225
|
+
let match;
|
|
226
|
+
while ((match = iconRegex.exec(content)) !== null) {
|
|
227
|
+
if (match.index > lastIndex) {
|
|
228
|
+
const textPart = content.slice(lastIndex, match.index);
|
|
229
|
+
if (textPart) {
|
|
230
|
+
parts.push({ type: 'text', value: textPart });
|
|
231
|
+
}
|
|
298
232
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
233
|
+
const iconContent = match[1];
|
|
234
|
+
const attrs = iconContent.split('|');
|
|
235
|
+
const iconName = attrs[0];
|
|
236
|
+
const iconPart = { type: 'icon', value: iconName };
|
|
237
|
+
for (let i = 1; i < attrs.length; i++) {
|
|
238
|
+
const [key, val] = attrs[i].split(':');
|
|
239
|
+
if (key === 'size') {
|
|
240
|
+
iconPart.size = parseInt(val, 10);
|
|
241
|
+
}
|
|
242
|
+
if (key === 'class') {
|
|
243
|
+
iconPart.class = val;
|
|
244
|
+
}
|
|
245
|
+
if (key === 'strokeWidth') {
|
|
246
|
+
iconPart.strokeWidth = parseFloat(val);
|
|
247
|
+
}
|
|
305
248
|
}
|
|
306
|
-
|
|
249
|
+
parts.push(iconPart);
|
|
250
|
+
lastIndex = match.index + match[0].length;
|
|
307
251
|
}
|
|
308
|
-
|
|
309
|
-
|
|
252
|
+
if (lastIndex < content.length) {
|
|
253
|
+
parts.push({ type: 'text', value: content.slice(lastIndex) });
|
|
310
254
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (this._finished) {
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
this._finished = true;
|
|
321
|
-
this.zCancel.emit();
|
|
255
|
+
return parts.length > 0 ? parts : [{ type: 'text', value: content }];
|
|
256
|
+
}
|
|
257
|
+
/** Removes all `[icon:...]` syntax from a string, returning plain text */
|
|
258
|
+
function stripIconSyntax(content) {
|
|
259
|
+
if (!content || typeof content !== 'string') {
|
|
260
|
+
return content || '';
|
|
322
261
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
262
|
+
return content.replace(/\[icon:[^\]]+\]/g, '').trim();
|
|
263
|
+
}
|
|
264
|
+
/** Returns true if the content string contains at least one `[icon:...]` segment */
|
|
265
|
+
function hasIconSyntax(content) {
|
|
266
|
+
if (!content || typeof content !== 'string') {
|
|
267
|
+
return false;
|
|
329
268
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
this._activated = true;
|
|
341
|
-
this._selectControl?.focus();
|
|
342
|
-
trigger.click();
|
|
343
|
-
return;
|
|
269
|
+
return /\[icon:[^\]]+\]/.test(content);
|
|
270
|
+
}
|
|
271
|
+
// ─── Column Lookup ───────────────────────────────────────────────────────────
|
|
272
|
+
/** Recursively search for a column config by ID within a (possibly nested) column array */
|
|
273
|
+
const findColumnConfig = (columnId, columns) => {
|
|
274
|
+
for (const col of columns) {
|
|
275
|
+
if (col.id === columnId) {
|
|
276
|
+
return col;
|
|
344
277
|
}
|
|
345
|
-
if (
|
|
346
|
-
|
|
347
|
-
|
|
278
|
+
if (col.columns) {
|
|
279
|
+
const found = findColumnConfig(columnId, col.columns);
|
|
280
|
+
if (found) {
|
|
281
|
+
return found;
|
|
348
282
|
}
|
|
349
|
-
this._activated = true;
|
|
350
|
-
this._ignoreNextCalendarChange = true;
|
|
351
|
-
this._calendarControl?.open();
|
|
352
|
-
requestAnimationFrame(() => this._focusCalendarInput());
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
if (!this._inputControl) {
|
|
356
|
-
return;
|
|
357
283
|
}
|
|
358
|
-
this._activated = true;
|
|
359
|
-
this._inputControl?.focus();
|
|
360
284
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
285
|
+
return undefined;
|
|
286
|
+
};
|
|
287
|
+
const getZTableColumnType = (column, columnId) => {
|
|
288
|
+
if (column?.type) {
|
|
289
|
+
return column.type;
|
|
364
290
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
@switch (zConfig().type) {
|
|
368
|
-
@case ('select') {
|
|
369
|
-
<z-select
|
|
370
|
-
#embeddedControl
|
|
371
|
-
[class]="controlClass()"
|
|
372
|
-
[style]="zConfig().style"
|
|
373
|
-
[zSize]="zConfig().size"
|
|
374
|
-
[zMode]="zConfig().selectMode"
|
|
375
|
-
[zConfig]="zConfig().selectConfig"
|
|
376
|
-
[zShowSearch]="zConfig().selectShowSearch"
|
|
377
|
-
[zAllowClear]="zConfig().allowClear"
|
|
378
|
-
[zWrap]="zConfig().selectWrap"
|
|
379
|
-
[zLoading]="zConfig().loading"
|
|
380
|
-
[zLoadingOutline]="true"
|
|
381
|
-
[zDisabled]="zConfig().disabled"
|
|
382
|
-
[zReadonly]="zConfig().readonly"
|
|
383
|
-
[zMaxTagCount]="zConfig().maxTagCount"
|
|
384
|
-
[zPlaceholder]="zConfig().placeholder"
|
|
385
|
-
[zOptions]="zConfig().options"
|
|
386
|
-
[ngModel]="zValue()"
|
|
387
|
-
[ngModelOptions]="{ standalone: true }"
|
|
388
|
-
(ngModelChange)="onSelectChange($event)"
|
|
389
|
-
(zOnBlur)="commitDraft()"
|
|
390
|
-
(keydown)="onEditorKeydown($event)"
|
|
391
|
-
(zControl)="onSelectControl($event)"
|
|
392
|
-
/>
|
|
393
|
-
}
|
|
394
|
-
@case ('date') {
|
|
395
|
-
<z-calendar
|
|
396
|
-
#embeddedControl
|
|
397
|
-
[class]="controlClass()"
|
|
398
|
-
[style]="zConfig().style"
|
|
399
|
-
[zSize]="zConfig().size"
|
|
400
|
-
zMode="single"
|
|
401
|
-
[zFormat]="zConfig().dateFormat"
|
|
402
|
-
[zValueType]="zConfig().dateValueType"
|
|
403
|
-
[zMinDate]="zConfig().minDate"
|
|
404
|
-
[zMaxDate]="zConfig().maxDate"
|
|
405
|
-
[zAllowClear]="zConfig().allowClear"
|
|
406
|
-
[zLoading]="zConfig().loading"
|
|
407
|
-
[zLoadingOutline]="true"
|
|
408
|
-
[zDisabled]="zConfig().disabled"
|
|
409
|
-
[zReadonly]="zConfig().readonly"
|
|
410
|
-
[ngModel]="$any(zValue())"
|
|
411
|
-
[ngModelOptions]="{ standalone: true }"
|
|
412
|
-
(zChange)="onCalendarChange($event)"
|
|
413
|
-
(keydown)="onEditorKeydown($event)"
|
|
414
|
-
(zControl)="onCalendarControl($event)"
|
|
415
|
-
/>
|
|
416
|
-
}
|
|
417
|
-
@default {
|
|
418
|
-
<z-input
|
|
419
|
-
#embeddedControl
|
|
420
|
-
[class]="controlClass()"
|
|
421
|
-
[style]="zConfig().style"
|
|
422
|
-
[zSize]="zConfig().size"
|
|
423
|
-
[zType]="inputType()"
|
|
424
|
-
[zAlign]="zConfig().align"
|
|
425
|
-
[zPlaceholder]="zConfig().placeholder"
|
|
426
|
-
[zPrefix]="zConfig().prefix"
|
|
427
|
-
[zSuffix]="zConfig().suffix"
|
|
428
|
-
[zMin]="zConfig().min"
|
|
429
|
-
[zMax]="zConfig().max"
|
|
430
|
-
[zStep]="zConfig().step ?? 1"
|
|
431
|
-
[zShowArrows]="zConfig().type === 'number'"
|
|
432
|
-
[zMask]="zConfig().mask"
|
|
433
|
-
[zDecimalPlaces]="zConfig().decimalPlaces"
|
|
434
|
-
[zAllowNegative]="zConfig().allowNegative"
|
|
435
|
-
[zThousandSeparator]="zConfig().thousandSeparator"
|
|
436
|
-
[zDecimalMarker]="zConfig().decimalMarker"
|
|
437
|
-
[zAllowClear]="zConfig().allowClear"
|
|
438
|
-
[zLoading]="zConfig().loading"
|
|
439
|
-
[zLoadingOutline]="true"
|
|
440
|
-
[zDisabled]="zConfig().disabled"
|
|
441
|
-
[zReadonly]="zConfig().readonly"
|
|
442
|
-
[ngModel]="$any(zValue())"
|
|
443
|
-
[ngModelOptions]="{ standalone: true }"
|
|
444
|
-
(ngModelChange)="draftValue.set($event)"
|
|
445
|
-
(zOnBlur)="commitDraft()"
|
|
446
|
-
(zOnEnter)="commitDraft()"
|
|
447
|
-
(zOnKeydown)="onEditorKeydown($event)"
|
|
448
|
-
(zControl)="onInputControl($event)"
|
|
449
|
-
/>
|
|
450
|
-
}
|
|
291
|
+
if (column && isBodyConfig(column.body) && column.body.actions) {
|
|
292
|
+
return 'actions';
|
|
451
293
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
type: Component,
|
|
456
|
-
args: [{ selector: 'z-table-content-editor', imports: [FormsModule, ZCalendarComponent, ZInputComponent, ZSelectComponent], standalone: true, template: `
|
|
457
|
-
@switch (zConfig().type) {
|
|
458
|
-
@case ('select') {
|
|
459
|
-
<z-select
|
|
460
|
-
#embeddedControl
|
|
461
|
-
[class]="controlClass()"
|
|
462
|
-
[style]="zConfig().style"
|
|
463
|
-
[zSize]="zConfig().size"
|
|
464
|
-
[zMode]="zConfig().selectMode"
|
|
465
|
-
[zConfig]="zConfig().selectConfig"
|
|
466
|
-
[zShowSearch]="zConfig().selectShowSearch"
|
|
467
|
-
[zAllowClear]="zConfig().allowClear"
|
|
468
|
-
[zWrap]="zConfig().selectWrap"
|
|
469
|
-
[zLoading]="zConfig().loading"
|
|
470
|
-
[zLoadingOutline]="true"
|
|
471
|
-
[zDisabled]="zConfig().disabled"
|
|
472
|
-
[zReadonly]="zConfig().readonly"
|
|
473
|
-
[zMaxTagCount]="zConfig().maxTagCount"
|
|
474
|
-
[zPlaceholder]="zConfig().placeholder"
|
|
475
|
-
[zOptions]="zConfig().options"
|
|
476
|
-
[ngModel]="zValue()"
|
|
477
|
-
[ngModelOptions]="{ standalone: true }"
|
|
478
|
-
(ngModelChange)="onSelectChange($event)"
|
|
479
|
-
(zOnBlur)="commitDraft()"
|
|
480
|
-
(keydown)="onEditorKeydown($event)"
|
|
481
|
-
(zControl)="onSelectControl($event)"
|
|
482
|
-
/>
|
|
483
|
-
}
|
|
484
|
-
@case ('date') {
|
|
485
|
-
<z-calendar
|
|
486
|
-
#embeddedControl
|
|
487
|
-
[class]="controlClass()"
|
|
488
|
-
[style]="zConfig().style"
|
|
489
|
-
[zSize]="zConfig().size"
|
|
490
|
-
zMode="single"
|
|
491
|
-
[zFormat]="zConfig().dateFormat"
|
|
492
|
-
[zValueType]="zConfig().dateValueType"
|
|
493
|
-
[zMinDate]="zConfig().minDate"
|
|
494
|
-
[zMaxDate]="zConfig().maxDate"
|
|
495
|
-
[zAllowClear]="zConfig().allowClear"
|
|
496
|
-
[zLoading]="zConfig().loading"
|
|
497
|
-
[zLoadingOutline]="true"
|
|
498
|
-
[zDisabled]="zConfig().disabled"
|
|
499
|
-
[zReadonly]="zConfig().readonly"
|
|
500
|
-
[ngModel]="$any(zValue())"
|
|
501
|
-
[ngModelOptions]="{ standalone: true }"
|
|
502
|
-
(zChange)="onCalendarChange($event)"
|
|
503
|
-
(keydown)="onEditorKeydown($event)"
|
|
504
|
-
(zControl)="onCalendarControl($event)"
|
|
505
|
-
/>
|
|
506
|
-
}
|
|
507
|
-
@default {
|
|
508
|
-
<z-input
|
|
509
|
-
#embeddedControl
|
|
510
|
-
[class]="controlClass()"
|
|
511
|
-
[style]="zConfig().style"
|
|
512
|
-
[zSize]="zConfig().size"
|
|
513
|
-
[zType]="inputType()"
|
|
514
|
-
[zAlign]="zConfig().align"
|
|
515
|
-
[zPlaceholder]="zConfig().placeholder"
|
|
516
|
-
[zPrefix]="zConfig().prefix"
|
|
517
|
-
[zSuffix]="zConfig().suffix"
|
|
518
|
-
[zMin]="zConfig().min"
|
|
519
|
-
[zMax]="zConfig().max"
|
|
520
|
-
[zStep]="zConfig().step ?? 1"
|
|
521
|
-
[zShowArrows]="zConfig().type === 'number'"
|
|
522
|
-
[zMask]="zConfig().mask"
|
|
523
|
-
[zDecimalPlaces]="zConfig().decimalPlaces"
|
|
524
|
-
[zAllowNegative]="zConfig().allowNegative"
|
|
525
|
-
[zThousandSeparator]="zConfig().thousandSeparator"
|
|
526
|
-
[zDecimalMarker]="zConfig().decimalMarker"
|
|
527
|
-
[zAllowClear]="zConfig().allowClear"
|
|
528
|
-
[zLoading]="zConfig().loading"
|
|
529
|
-
[zLoadingOutline]="true"
|
|
530
|
-
[zDisabled]="zConfig().disabled"
|
|
531
|
-
[zReadonly]="zConfig().readonly"
|
|
532
|
-
[ngModel]="$any(zValue())"
|
|
533
|
-
[ngModelOptions]="{ standalone: true }"
|
|
534
|
-
(ngModelChange)="draftValue.set($event)"
|
|
535
|
-
(zOnBlur)="commitDraft()"
|
|
536
|
-
(zOnEnter)="commitDraft()"
|
|
537
|
-
(zOnKeydown)="onEditorKeydown($event)"
|
|
538
|
-
(zControl)="onInputControl($event)"
|
|
539
|
-
/>
|
|
540
|
-
}
|
|
294
|
+
const id = column?.id ?? columnId;
|
|
295
|
+
if (id === 'select') {
|
|
296
|
+
return 'select';
|
|
541
297
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
// ─── Column Visibility Pre-filter ────────────────────────────────────────────
|
|
546
|
-
/**
|
|
547
|
-
* Recursively filters columns based on their `visible` property.
|
|
548
|
-
* This runs BEFORE TanStack table creation — columns excluded here
|
|
549
|
-
* won't generate ColumnDef entries at all (unlike columnVisibility state
|
|
550
|
-
* which hides columns but keeps them in the column model).
|
|
551
|
-
*/
|
|
552
|
-
const filterVisibleColumns = (columns) => columns
|
|
553
|
-
.filter(col => {
|
|
554
|
-
const { visible } = col;
|
|
555
|
-
if (visible === undefined) {
|
|
556
|
-
return true;
|
|
298
|
+
if (id === 'expand') {
|
|
299
|
+
return 'expand';
|
|
557
300
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
.map(col => {
|
|
561
|
-
if (col.columns && col.columns.length > 0) {
|
|
562
|
-
return {
|
|
563
|
-
...col,
|
|
564
|
-
columns: filterVisibleColumns(col.columns),
|
|
565
|
-
};
|
|
301
|
+
if (id === 'rowDrag') {
|
|
302
|
+
return 'rowDrag';
|
|
566
303
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
// ─── Config Type Guards ──────────────────────────────────────────────────────
|
|
570
|
-
/**
|
|
571
|
-
* Checks if a config value is a plain object (config struct) vs a primitive/template.
|
|
572
|
-
* Used to distinguish shorthand content (string/TemplateRef) from full config objects
|
|
573
|
-
* like ZTableHeaderColumnConfig, ZTableBodyColumnConfig, etc.
|
|
574
|
-
*/
|
|
575
|
-
const isObjectConfig = (config) => {
|
|
576
|
-
if (!config || typeof config !== 'object') {
|
|
577
|
-
return false;
|
|
304
|
+
if (id === 'actionRowPin' || id === 'actions') {
|
|
305
|
+
return 'rowPin';
|
|
578
306
|
}
|
|
579
|
-
return
|
|
307
|
+
return 'data';
|
|
580
308
|
};
|
|
581
|
-
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
/** Type guard: is this a full footer config object (not just content shorthand)? */
|
|
586
|
-
const isFooterConfig = (config) => isObjectConfig(config);
|
|
587
|
-
// ─── Config Extractors ───────────────────────────────────────────────────────
|
|
309
|
+
const getZTableColumnTypeById = (columnId, columns) => getZTableColumnType(findColumnConfig(columnId, columns), columnId);
|
|
310
|
+
const isZTableColumnType = (column, type) => getZTableColumnType(column) === type;
|
|
311
|
+
const isZTableColumnTypeById = (columnId, columns, type) => getZTableColumnTypeById(columnId, columns) === type;
|
|
312
|
+
// ─── Span Calculation ────────────────────────────────────────────────────────
|
|
588
313
|
/**
|
|
589
|
-
*
|
|
590
|
-
*
|
|
314
|
+
* Walk down a chain of placeholder headers to find the deepest real header.
|
|
315
|
+
* Used to calculate how many rows a header cell should span in multi-level headers.
|
|
316
|
+
* Returns null if the header is already the deepest (no spanning needed).
|
|
591
317
|
*/
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
contentClass: undefined,
|
|
602
|
-
contentStyle: undefined,
|
|
603
|
-
};
|
|
604
|
-
if (!col) {
|
|
605
|
-
return empty;
|
|
606
|
-
}
|
|
607
|
-
const footer = Array.isArray(col.footer) ? col.footer[footerRowIndex] : col.footer;
|
|
608
|
-
const config = type === 'header' ? col.header : footer;
|
|
609
|
-
const isConfigFn = type === 'header' ? isHeaderConfig : isFooterConfig;
|
|
610
|
-
if (!isConfigFn(config)) {
|
|
611
|
-
return { ...empty, content: config };
|
|
612
|
-
}
|
|
613
|
-
const typedConfig = config;
|
|
614
|
-
return {
|
|
615
|
-
content: typedConfig.content,
|
|
616
|
-
class: typedConfig.class,
|
|
617
|
-
style: typedConfig.style,
|
|
618
|
-
align: typedConfig.align,
|
|
619
|
-
tooltip: typedConfig.tooltip,
|
|
620
|
-
rowSpan: typedConfig.rowSpan,
|
|
621
|
-
colSpan: typedConfig.colSpan,
|
|
622
|
-
contentClass: typedConfig.contentClass,
|
|
623
|
-
contentStyle: typedConfig.contentStyle,
|
|
624
|
-
};
|
|
625
|
-
};
|
|
626
|
-
/** Extract and normalize header config from a column definition */
|
|
627
|
-
const getHeaderConfig = (col) => getHeaderOrFooterConfigInternal(col, 'header');
|
|
628
|
-
/**
|
|
629
|
-
* Extract and normalize body config from a column definition.
|
|
630
|
-
* Resolves dynamic properties (class, style, rowSpan, etc.) when CellContext is provided.
|
|
631
|
-
*/
|
|
632
|
-
const getBodyConfig = (col, ctx) => {
|
|
633
|
-
const empty = {
|
|
634
|
-
content: undefined,
|
|
635
|
-
type: 'default',
|
|
636
|
-
tagColor: 'primary',
|
|
637
|
-
class: undefined,
|
|
638
|
-
style: undefined,
|
|
639
|
-
align: undefined,
|
|
640
|
-
rowSpan: undefined,
|
|
641
|
-
colSpan: undefined,
|
|
642
|
-
contentClass: undefined,
|
|
643
|
-
contentStyle: undefined,
|
|
644
|
-
tooltip: undefined,
|
|
645
|
-
popover: undefined,
|
|
646
|
-
};
|
|
647
|
-
if (!col) {
|
|
648
|
-
return empty;
|
|
649
|
-
}
|
|
650
|
-
if (!isBodyConfig(col.body)) {
|
|
651
|
-
return { ...empty, content: col.body };
|
|
652
|
-
}
|
|
653
|
-
const { body } = col;
|
|
654
|
-
const rowSpan = typeof body.rowSpan === 'function' && ctx ? body.rowSpan(ctx) : body.rowSpan;
|
|
655
|
-
const colSpan = typeof body.colSpan === 'function' && ctx ? body.colSpan(ctx) : body.colSpan;
|
|
656
|
-
const classValue = typeof body.class === 'function' && ctx ? body.class(ctx) : body.class;
|
|
657
|
-
const styleValue = typeof body.style === 'function' && ctx ? body.style(ctx) : body.style;
|
|
658
|
-
const contentClass = typeof body.contentClass === 'function' && ctx ? body.contentClass(ctx) : body.contentClass;
|
|
659
|
-
const contentStyle = typeof body.contentStyle === 'function' && ctx ? body.contentStyle(ctx) : body.contentStyle;
|
|
660
|
-
const tooltip = typeof body.tooltip === 'function' && ctx ? body.tooltip(ctx) : body.tooltip;
|
|
661
|
-
const popover = typeof body.popover === 'function' && ctx ? body.popover(ctx) : body.popover;
|
|
662
|
-
const tagColor = typeof body.tagColor === 'function' && ctx ? body.tagColor(ctx) : body.tagColor;
|
|
663
|
-
return {
|
|
664
|
-
content: body.content,
|
|
665
|
-
type: body.type || 'default',
|
|
666
|
-
tagColor: tagColor || 'primary',
|
|
667
|
-
class: classValue,
|
|
668
|
-
style: styleValue,
|
|
669
|
-
align: body.align,
|
|
670
|
-
rowSpan: typeof rowSpan === 'number' ? rowSpan : undefined,
|
|
671
|
-
colSpan: typeof colSpan === 'number' ? colSpan : undefined,
|
|
672
|
-
contentClass,
|
|
673
|
-
contentStyle: contentStyle,
|
|
674
|
-
tooltip,
|
|
675
|
-
popover,
|
|
676
|
-
};
|
|
677
|
-
};
|
|
678
|
-
const getFooterConfig = (col, footerRowIndex = 0) => getHeaderOrFooterConfigInternal(col, 'footer', footerRowIndex);
|
|
679
|
-
// ─── Shortcut Accessors ──────────────────────────────────────────────────────
|
|
680
|
-
// These convenience functions extract a single property from the relevant config.
|
|
681
|
-
const getHeaderContent = (col) => getHeaderConfig(col).content;
|
|
682
|
-
const getBodyContent = (col) => {
|
|
683
|
-
if (!col?.body) {
|
|
684
|
-
return undefined;
|
|
685
|
-
}
|
|
686
|
-
return isBodyConfig(col.body) ? col.body.content : col.body;
|
|
687
|
-
};
|
|
688
|
-
const getFooterContent = (col, footerRowIndex = 0) => getFooterConfig(col, footerRowIndex).content;
|
|
689
|
-
const getBodyRowSpan = (col, ctx) => getBodyConfig(col, ctx).rowSpan;
|
|
690
|
-
const getBodyColSpan = (col, ctx) => getBodyConfig(col, ctx).colSpan;
|
|
691
|
-
const getHeaderRowSpan = (col) => getHeaderConfig(col).rowSpan;
|
|
692
|
-
const getHeaderColSpan = (col) => getHeaderConfig(col).colSpan;
|
|
693
|
-
const getFooterRowSpan = (col, footerRowIndex = 0) => getFooterConfig(col, footerRowIndex).rowSpan;
|
|
694
|
-
const getFooterColSpan = (col, footerRowIndex = 0) => getFooterConfig(col, footerRowIndex).colSpan;
|
|
695
|
-
// ─── Icon Syntax Parsing ─────────────────────────────────────────────────────
|
|
696
|
-
/**
|
|
697
|
-
* Parses inline icon syntax: `"Total [icon:lucideTrendingUp|size:16|class:text-green] Revenue"`
|
|
698
|
-
* Returns an array of text and icon segments for rendering by ZTableIconTextComponent.
|
|
699
|
-
*/
|
|
700
|
-
function parseIconString(content) {
|
|
701
|
-
if (!content || typeof content !== 'string') {
|
|
702
|
-
return [{ type: 'text', value: content || '' }];
|
|
703
|
-
}
|
|
704
|
-
const parts = [];
|
|
705
|
-
const iconRegex = /\[icon:([^\]]+)\]/g;
|
|
706
|
-
let lastIndex = 0;
|
|
707
|
-
let match;
|
|
708
|
-
while ((match = iconRegex.exec(content)) !== null) {
|
|
709
|
-
if (match.index > lastIndex) {
|
|
710
|
-
const textPart = content.slice(lastIndex, match.index);
|
|
711
|
-
if (textPart) {
|
|
712
|
-
parts.push({ type: 'text', value: textPart });
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
const iconContent = match[1];
|
|
716
|
-
const attrs = iconContent.split('|');
|
|
717
|
-
const iconName = attrs[0];
|
|
718
|
-
const iconPart = { type: 'icon', value: iconName };
|
|
719
|
-
for (let i = 1; i < attrs.length; i++) {
|
|
720
|
-
const [key, val] = attrs[i].split(':');
|
|
721
|
-
if (key === 'size') {
|
|
722
|
-
iconPart.size = parseInt(val, 10);
|
|
723
|
-
}
|
|
724
|
-
if (key === 'class') {
|
|
725
|
-
iconPart.class = val;
|
|
726
|
-
}
|
|
727
|
-
if (key === 'strokeWidth') {
|
|
728
|
-
iconPart.strokeWidth = parseFloat(val);
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
parts.push(iconPart);
|
|
732
|
-
lastIndex = match.index + match[0].length;
|
|
733
|
-
}
|
|
734
|
-
if (lastIndex < content.length) {
|
|
735
|
-
parts.push({ type: 'text', value: content.slice(lastIndex) });
|
|
736
|
-
}
|
|
737
|
-
return parts.length > 0 ? parts : [{ type: 'text', value: content }];
|
|
738
|
-
}
|
|
739
|
-
/** Removes all `[icon:...]` syntax from a string, returning plain text */
|
|
740
|
-
function stripIconSyntax(content) {
|
|
741
|
-
if (!content || typeof content !== 'string') {
|
|
742
|
-
return content || '';
|
|
743
|
-
}
|
|
744
|
-
return content.replace(/\[icon:[^\]]+\]/g, '').trim();
|
|
745
|
-
}
|
|
746
|
-
/** Returns true if the content string contains at least one `[icon:...]` segment */
|
|
747
|
-
function hasIconSyntax(content) {
|
|
748
|
-
if (!content || typeof content !== 'string') {
|
|
749
|
-
return false;
|
|
750
|
-
}
|
|
751
|
-
return /\[icon:[^\]]+\]/.test(content);
|
|
752
|
-
}
|
|
753
|
-
// ─── Column Lookup ───────────────────────────────────────────────────────────
|
|
754
|
-
/** Recursively search for a column config by ID within a (possibly nested) column array */
|
|
755
|
-
const findColumnConfig = (columnId, columns) => {
|
|
756
|
-
for (const col of columns) {
|
|
757
|
-
if (col.id === columnId) {
|
|
758
|
-
return col;
|
|
759
|
-
}
|
|
760
|
-
if (col.columns) {
|
|
761
|
-
const found = findColumnConfig(columnId, col.columns);
|
|
762
|
-
if (found) {
|
|
763
|
-
return found;
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
return undefined;
|
|
768
|
-
};
|
|
769
|
-
const getZTableColumnType = (column, columnId) => {
|
|
770
|
-
if (column?.type) {
|
|
771
|
-
return column.type;
|
|
772
|
-
}
|
|
773
|
-
if (column && isBodyConfig(column.body) && column.body.actions) {
|
|
774
|
-
return 'actions';
|
|
775
|
-
}
|
|
776
|
-
const id = column?.id ?? columnId;
|
|
777
|
-
if (id === 'select') {
|
|
778
|
-
return 'select';
|
|
779
|
-
}
|
|
780
|
-
if (id === 'expand') {
|
|
781
|
-
return 'expand';
|
|
782
|
-
}
|
|
783
|
-
if (id === 'rowDrag') {
|
|
784
|
-
return 'rowDrag';
|
|
785
|
-
}
|
|
786
|
-
if (id === 'actionRowPin' || id === 'actions') {
|
|
787
|
-
return 'rowPin';
|
|
788
|
-
}
|
|
789
|
-
return 'data';
|
|
790
|
-
};
|
|
791
|
-
const getZTableColumnTypeById = (columnId, columns) => getZTableColumnType(findColumnConfig(columnId, columns), columnId);
|
|
792
|
-
const isZTableColumnType = (column, type) => getZTableColumnType(column) === type;
|
|
793
|
-
const isZTableColumnTypeById = (columnId, columns, type) => getZTableColumnTypeById(columnId, columns) === type;
|
|
794
|
-
// ─── Span Calculation ────────────────────────────────────────────────────────
|
|
795
|
-
/**
|
|
796
|
-
* Walk down a chain of placeholder headers to find the deepest real header.
|
|
797
|
-
* Used to calculate how many rows a header cell should span in multi-level headers.
|
|
798
|
-
* Returns null if the header is already the deepest (no spanning needed).
|
|
799
|
-
*/
|
|
800
|
-
const deepestHeader = (header) => {
|
|
801
|
-
let last = header;
|
|
802
|
-
while (true) {
|
|
803
|
-
// Follow single-child placeholder chains (placeholders with colSpan=1)
|
|
804
|
-
const next = last.isPlaceholder && last.colSpan === 1 && last.subHeaders.length === 1 ? last.subHeaders[0] : null;
|
|
805
|
-
if (!next) {
|
|
806
|
-
return last === header ? null : last;
|
|
807
|
-
}
|
|
808
|
-
last = next;
|
|
318
|
+
const deepestHeader = (header) => {
|
|
319
|
+
let last = header;
|
|
320
|
+
while (true) {
|
|
321
|
+
// Follow single-child placeholder chains (placeholders with colSpan=1)
|
|
322
|
+
const next = last.isPlaceholder && last.colSpan === 1 && last.subHeaders.length === 1 ? last.subHeaders[0] : null;
|
|
323
|
+
if (!next) {
|
|
324
|
+
return last === header ? null : last;
|
|
325
|
+
}
|
|
326
|
+
last = next;
|
|
809
327
|
}
|
|
810
328
|
};
|
|
811
329
|
/** Calculate rowSpan for a TanStack header based on its depth vs deepest sub-header */
|
|
@@ -1435,6 +953,490 @@ function isFixedLeadingColumn(columnId) {
|
|
|
1435
953
|
return columnId === 'expand' || columnId === 'select' || columnId === 'rowDrag';
|
|
1436
954
|
}
|
|
1437
955
|
|
|
956
|
+
class ZTableActionsComponent {
|
|
957
|
+
zConfig = input.required(...(ngDevMode ? [{ debugName: "zConfig" }] : []));
|
|
958
|
+
zRow = input.required(...(ngDevMode ? [{ debugName: "zRow" }] : []));
|
|
959
|
+
zRowId = input.required(...(ngDevMode ? [{ debugName: "zRowId" }] : []));
|
|
960
|
+
zDropdownButtonSize = input(Z_TABLE_DEFAULT_DROPDOWN_BUTTON_SIZE, ...(ngDevMode ? [{ debugName: "zDropdownButtonSize" }] : []));
|
|
961
|
+
zActionClick = output();
|
|
962
|
+
allActions = computed(() => {
|
|
963
|
+
const config = this.zConfig();
|
|
964
|
+
const row = this.zRow();
|
|
965
|
+
const { actions } = config;
|
|
966
|
+
const resolvedActions = typeof actions === 'function' ? actions(row) : actions;
|
|
967
|
+
return resolvedActions.filter(action => {
|
|
968
|
+
if (typeof action.hidden === 'function') {
|
|
969
|
+
return !action.hidden(row);
|
|
970
|
+
}
|
|
971
|
+
return !action.hidden;
|
|
972
|
+
});
|
|
973
|
+
}, ...(ngDevMode ? [{ debugName: "allActions" }] : []));
|
|
974
|
+
shouldShowAsButtons = computed(() => {
|
|
975
|
+
const actions = this.allActions();
|
|
976
|
+
const maxVisible = this.zConfig().maxVisible ?? Z_TABLE_DEFAULT_MAX_VISIBLE_ACTIONS;
|
|
977
|
+
return actions.length <= maxVisible;
|
|
978
|
+
}, ...(ngDevMode ? [{ debugName: "shouldShowAsButtons" }] : []));
|
|
979
|
+
actionStates = computed(() => {
|
|
980
|
+
const row = this.zRow();
|
|
981
|
+
const actions = this.allActions();
|
|
982
|
+
const states = {};
|
|
983
|
+
for (const action of actions) {
|
|
984
|
+
const isHidden = typeof action.hidden === 'function' ? action.hidden(row) : (action.hidden ?? false);
|
|
985
|
+
const isDisabled = typeof action.disabled === 'function' ? action.disabled(row) : (action.disabled ?? false);
|
|
986
|
+
const isLoading = typeof action.loading === 'function' ? action.loading(row) : (action.loading ?? false);
|
|
987
|
+
states[action.key] = {
|
|
988
|
+
visible: !isHidden,
|
|
989
|
+
loading: isLoading,
|
|
990
|
+
disabled: isDisabled || isLoading,
|
|
991
|
+
tooltipState: this._getTooltipState(action.tooltip),
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
return states;
|
|
995
|
+
}, ...(ngDevMode ? [{ debugName: "actionStates" }] : []));
|
|
996
|
+
dropdownItems = computed(() => {
|
|
997
|
+
const row = this.zRow();
|
|
998
|
+
return this.allActions().map(action => {
|
|
999
|
+
const isDisabled = typeof action.disabled === 'function' ? action.disabled(row) : (action.disabled ?? false);
|
|
1000
|
+
const isLoading = typeof action.loading === 'function' ? action.loading(row) : (action.loading ?? false);
|
|
1001
|
+
return {
|
|
1002
|
+
label: getZTableActionDropdownLabel(action),
|
|
1003
|
+
icon: action.icon,
|
|
1004
|
+
iconSize: action?.iconSize || '18',
|
|
1005
|
+
loading: isLoading,
|
|
1006
|
+
disabled: isDisabled || isLoading,
|
|
1007
|
+
class: action.class,
|
|
1008
|
+
divide: action.divide,
|
|
1009
|
+
onClick: () => {
|
|
1010
|
+
if (isDisabled || isLoading) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
this._emitActionClick(action);
|
|
1014
|
+
},
|
|
1015
|
+
};
|
|
1016
|
+
});
|
|
1017
|
+
}, ...(ngDevMode ? [{ debugName: "dropdownItems" }] : []));
|
|
1018
|
+
_getTooltipState(tooltip) {
|
|
1019
|
+
if (!tooltip) {
|
|
1020
|
+
return { content: '', alwaysShow: false };
|
|
1021
|
+
}
|
|
1022
|
+
if (typeof tooltip === 'string') {
|
|
1023
|
+
return { content: tooltip, alwaysShow: true };
|
|
1024
|
+
}
|
|
1025
|
+
return {
|
|
1026
|
+
content: tooltip.content ?? '',
|
|
1027
|
+
alwaysShow: tooltip.alwaysShow ?? true,
|
|
1028
|
+
position: tooltip.position,
|
|
1029
|
+
arrow: tooltip.arrow,
|
|
1030
|
+
offset: tooltip.offset,
|
|
1031
|
+
maxWidth: tooltip.maxWidth,
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
_onActionClick(action, event) {
|
|
1035
|
+
event.stopPropagation();
|
|
1036
|
+
const states = this.actionStates();
|
|
1037
|
+
if (states[action.key]?.disabled) {
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
this._emitActionClick(action);
|
|
1041
|
+
}
|
|
1042
|
+
_onDropdownItemClick(item) {
|
|
1043
|
+
const action = this.allActions().find(candidate => getZTableActionDropdownLabel(candidate) === item.label);
|
|
1044
|
+
if (!action || this.actionStates()[action.key]?.disabled) {
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
this._emitActionClick(action);
|
|
1048
|
+
}
|
|
1049
|
+
_emitActionClick(action) {
|
|
1050
|
+
this.zActionClick.emit({
|
|
1051
|
+
key: action.key,
|
|
1052
|
+
row: this.zRow(),
|
|
1053
|
+
rowId: this.zRowId(),
|
|
1054
|
+
action,
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1058
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", type: ZTableActionsComponent, isStandalone: true, selector: "z-table-actions", inputs: { zConfig: { classPropertyName: "zConfig", publicName: "zConfig", isSignal: true, isRequired: true, transformFunction: null }, zRow: { classPropertyName: "zRow", publicName: "zRow", isSignal: true, isRequired: true, transformFunction: null }, zRowId: { classPropertyName: "zRowId", publicName: "zRowId", isSignal: true, isRequired: true, transformFunction: null }, zDropdownButtonSize: { classPropertyName: "zDropdownButtonSize", publicName: "zDropdownButtonSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zActionClick: "zActionClick" }, ngImport: i0, template: `
|
|
1059
|
+
<div class="z-table-actions flex items-center justify-center gap-1">
|
|
1060
|
+
@if (shouldShowAsButtons()) {
|
|
1061
|
+
@for (action of allActions(); track action.key) {
|
|
1062
|
+
@if (actionStates()[action.key].visible) {
|
|
1063
|
+
<button
|
|
1064
|
+
type="button"
|
|
1065
|
+
z-button
|
|
1066
|
+
z-tooltip
|
|
1067
|
+
[zType]="action.type ?? 'outline'"
|
|
1068
|
+
[zSize]="action.size ?? 'sm'"
|
|
1069
|
+
[zTypeIcon]="action.icon"
|
|
1070
|
+
zSizeIcon="14"
|
|
1071
|
+
[zLabel]="action.label ?? ''"
|
|
1072
|
+
[zLoading]="actionStates()[action.key].loading"
|
|
1073
|
+
[zDisabled]="actionStates()[action.key].disabled"
|
|
1074
|
+
[class]="action.class ?? ''"
|
|
1075
|
+
[zContent]="actionStates()[action.key].tooltipState.content"
|
|
1076
|
+
[zAlwaysShow]="actionStates()[action.key].tooltipState.alwaysShow"
|
|
1077
|
+
[zArrow]="actionStates()[action.key].tooltipState.arrow ?? true"
|
|
1078
|
+
[zOffset]="actionStates()[action.key].tooltipState.offset ?? 8"
|
|
1079
|
+
[zMaxWidth]="actionStates()[action.key].tooltipState.maxWidth ?? '250px'"
|
|
1080
|
+
(click)="_onActionClick(action, $event)"
|
|
1081
|
+
></button>
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
} @else {
|
|
1085
|
+
<z-dropdown-menu
|
|
1086
|
+
[zItems]="dropdownItems()"
|
|
1087
|
+
zPosition="bottom-right"
|
|
1088
|
+
[zButtonSize]="zDropdownButtonSize()"
|
|
1089
|
+
[zMinWidth]="160"
|
|
1090
|
+
(zOnItemClick)="_onDropdownItemClick($event)"
|
|
1091
|
+
>
|
|
1092
|
+
<button
|
|
1093
|
+
type="button"
|
|
1094
|
+
z-button
|
|
1095
|
+
zTypeIcon="lucideEllipsis"
|
|
1096
|
+
[zSize]="zDropdownButtonSize()"
|
|
1097
|
+
zType="outline"
|
|
1098
|
+
[zWave]="false"
|
|
1099
|
+
></button>
|
|
1100
|
+
</z-dropdown-menu>
|
|
1101
|
+
}
|
|
1102
|
+
</div>
|
|
1103
|
+
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "component", type: ZDropdownMenuComponent, selector: "z-dropdown-menu", inputs: ["zItems", "zLabel", "zIcon", "zButtonType", "zPosition", "zButtonSize", "zOffset", "zMinWidth", "zMaxWidth", "zDisabled", "zWave"], outputs: ["zOnItemClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1104
|
+
}
|
|
1105
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableActionsComponent, decorators: [{
|
|
1106
|
+
type: Component,
|
|
1107
|
+
args: [{ selector: 'z-table-actions', imports: [ZButtonComponent, ZTooltipDirective, ZDropdownMenuComponent], standalone: true, template: `
|
|
1108
|
+
<div class="z-table-actions flex items-center justify-center gap-1">
|
|
1109
|
+
@if (shouldShowAsButtons()) {
|
|
1110
|
+
@for (action of allActions(); track action.key) {
|
|
1111
|
+
@if (actionStates()[action.key].visible) {
|
|
1112
|
+
<button
|
|
1113
|
+
type="button"
|
|
1114
|
+
z-button
|
|
1115
|
+
z-tooltip
|
|
1116
|
+
[zType]="action.type ?? 'outline'"
|
|
1117
|
+
[zSize]="action.size ?? 'sm'"
|
|
1118
|
+
[zTypeIcon]="action.icon"
|
|
1119
|
+
zSizeIcon="14"
|
|
1120
|
+
[zLabel]="action.label ?? ''"
|
|
1121
|
+
[zLoading]="actionStates()[action.key].loading"
|
|
1122
|
+
[zDisabled]="actionStates()[action.key].disabled"
|
|
1123
|
+
[class]="action.class ?? ''"
|
|
1124
|
+
[zContent]="actionStates()[action.key].tooltipState.content"
|
|
1125
|
+
[zAlwaysShow]="actionStates()[action.key].tooltipState.alwaysShow"
|
|
1126
|
+
[zArrow]="actionStates()[action.key].tooltipState.arrow ?? true"
|
|
1127
|
+
[zOffset]="actionStates()[action.key].tooltipState.offset ?? 8"
|
|
1128
|
+
[zMaxWidth]="actionStates()[action.key].tooltipState.maxWidth ?? '250px'"
|
|
1129
|
+
(click)="_onActionClick(action, $event)"
|
|
1130
|
+
></button>
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
} @else {
|
|
1134
|
+
<z-dropdown-menu
|
|
1135
|
+
[zItems]="dropdownItems()"
|
|
1136
|
+
zPosition="bottom-right"
|
|
1137
|
+
[zButtonSize]="zDropdownButtonSize()"
|
|
1138
|
+
[zMinWidth]="160"
|
|
1139
|
+
(zOnItemClick)="_onDropdownItemClick($event)"
|
|
1140
|
+
>
|
|
1141
|
+
<button
|
|
1142
|
+
type="button"
|
|
1143
|
+
z-button
|
|
1144
|
+
zTypeIcon="lucideEllipsis"
|
|
1145
|
+
[zSize]="zDropdownButtonSize()"
|
|
1146
|
+
zType="outline"
|
|
1147
|
+
[zWave]="false"
|
|
1148
|
+
></button>
|
|
1149
|
+
</z-dropdown-menu>
|
|
1150
|
+
}
|
|
1151
|
+
</div>
|
|
1152
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
|
|
1153
|
+
}], propDecorators: { zConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zConfig", required: true }] }], zRow: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRow", required: true }] }], zRowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRowId", required: true }] }], zDropdownButtonSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDropdownButtonSize", required: false }] }], zActionClick: [{ type: i0.Output, args: ["zActionClick"] }] } });
|
|
1154
|
+
|
|
1155
|
+
class ZTableContentEditorComponent {
|
|
1156
|
+
zValue = input(...(ngDevMode ? [undefined, { debugName: "zValue" }] : []));
|
|
1157
|
+
zConfig = input.required(...(ngDevMode ? [{ debugName: "zConfig" }] : []));
|
|
1158
|
+
zCommit = output();
|
|
1159
|
+
zCancel = output();
|
|
1160
|
+
draftValue = signal(null, ...(ngDevMode ? [{ debugName: "draftValue" }] : []));
|
|
1161
|
+
controlClass = computed(() => zMergeClasses('z-table-embedded-control', this.zConfig().class), ...(ngDevMode ? [{ debugName: "controlClass" }] : []));
|
|
1162
|
+
inputType = computed(() => this.zConfig().type === 'number' ? 'number' : 'text', ...(ngDevMode ? [{ debugName: "inputType" }] : []));
|
|
1163
|
+
_host = inject(ElementRef);
|
|
1164
|
+
_finished = false;
|
|
1165
|
+
_inputControl = null;
|
|
1166
|
+
_selectControl = null;
|
|
1167
|
+
_calendarControl = null;
|
|
1168
|
+
_activated = false;
|
|
1169
|
+
_ignoreNextCalendarChange = false;
|
|
1170
|
+
constructor() {
|
|
1171
|
+
effect(() => {
|
|
1172
|
+
const value = this.zValue();
|
|
1173
|
+
this.draftValue.set(value ?? null);
|
|
1174
|
+
});
|
|
1175
|
+
afterNextRender(() => this._activateControl());
|
|
1176
|
+
}
|
|
1177
|
+
onInputControl(control) {
|
|
1178
|
+
this._inputControl = control;
|
|
1179
|
+
queueMicrotask(() => this._activateControl());
|
|
1180
|
+
}
|
|
1181
|
+
onSelectControl(control) {
|
|
1182
|
+
this._selectControl = control;
|
|
1183
|
+
queueMicrotask(() => this._activateControl());
|
|
1184
|
+
}
|
|
1185
|
+
onCalendarControl(control) {
|
|
1186
|
+
this._calendarControl = control;
|
|
1187
|
+
queueMicrotask(() => this._activateControl());
|
|
1188
|
+
}
|
|
1189
|
+
onSelectChange(value) {
|
|
1190
|
+
if (this.zConfig().selectMode !== 'single') {
|
|
1191
|
+
this.draftValue.set(value);
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
this._commit(value);
|
|
1195
|
+
}
|
|
1196
|
+
onCalendarChange(value) {
|
|
1197
|
+
if (this._ignoreNextCalendarChange) {
|
|
1198
|
+
this._ignoreNextCalendarChange = false;
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
this._commit(value);
|
|
1202
|
+
}
|
|
1203
|
+
commitDraft() {
|
|
1204
|
+
this._commit(this.draftValue());
|
|
1205
|
+
}
|
|
1206
|
+
onEditorKeydown(event) {
|
|
1207
|
+
if (event.key !== 'Escape') {
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
event.preventDefault();
|
|
1211
|
+
event.stopPropagation();
|
|
1212
|
+
if (this._finished) {
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
this._finished = true;
|
|
1216
|
+
this.zCancel.emit();
|
|
1217
|
+
}
|
|
1218
|
+
_commit(value) {
|
|
1219
|
+
if (this._finished) {
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
this._finished = true;
|
|
1223
|
+
this.zCommit.emit(value);
|
|
1224
|
+
}
|
|
1225
|
+
_activateControl() {
|
|
1226
|
+
if (this._activated) {
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
const { type } = this.zConfig();
|
|
1230
|
+
if (type === 'select') {
|
|
1231
|
+
const trigger = this._host.nativeElement.querySelector('.z-select-trigger');
|
|
1232
|
+
if (!this._selectControl || !trigger) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
this._activated = true;
|
|
1236
|
+
this._selectControl?.focus();
|
|
1237
|
+
trigger.click();
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
if (type === 'date') {
|
|
1241
|
+
if (!this._calendarControl) {
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
this._activated = true;
|
|
1245
|
+
this._ignoreNextCalendarChange = true;
|
|
1246
|
+
this._calendarControl?.open();
|
|
1247
|
+
requestAnimationFrame(() => this._focusCalendarInput());
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
if (!this._inputControl) {
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
this._activated = true;
|
|
1254
|
+
this._inputControl?.focus();
|
|
1255
|
+
}
|
|
1256
|
+
_focusCalendarInput() {
|
|
1257
|
+
const input = this._host.nativeElement.querySelector('.z-calendar-wrapper input');
|
|
1258
|
+
input?.focus();
|
|
1259
|
+
}
|
|
1260
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableContentEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1261
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", type: ZTableContentEditorComponent, isStandalone: true, selector: "z-table-content-editor", inputs: { zValue: { classPropertyName: "zValue", publicName: "zValue", isSignal: true, isRequired: false, transformFunction: null }, zConfig: { classPropertyName: "zConfig", publicName: "zConfig", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { zCommit: "zCommit", zCancel: "zCancel" }, ngImport: i0, template: `
|
|
1262
|
+
@switch (zConfig().type) {
|
|
1263
|
+
@case ('select') {
|
|
1264
|
+
<z-select
|
|
1265
|
+
#embeddedControl
|
|
1266
|
+
[class]="controlClass()"
|
|
1267
|
+
[style]="zConfig().style"
|
|
1268
|
+
[zSize]="zConfig().size"
|
|
1269
|
+
[zMode]="zConfig().selectMode"
|
|
1270
|
+
[zConfig]="zConfig().selectConfig"
|
|
1271
|
+
[zShowSearch]="zConfig().selectShowSearch"
|
|
1272
|
+
[zAllowClear]="zConfig().allowClear"
|
|
1273
|
+
[zWrap]="zConfig().selectWrap"
|
|
1274
|
+
[zLoading]="zConfig().loading"
|
|
1275
|
+
[zLoadingOutline]="true"
|
|
1276
|
+
[zDisabled]="zConfig().disabled"
|
|
1277
|
+
[zReadonly]="zConfig().readonly"
|
|
1278
|
+
[zMaxTagCount]="zConfig().maxTagCount"
|
|
1279
|
+
[zPlaceholder]="zConfig().placeholder"
|
|
1280
|
+
[zOptions]="zConfig().options"
|
|
1281
|
+
[ngModel]="zValue()"
|
|
1282
|
+
[ngModelOptions]="{ standalone: true }"
|
|
1283
|
+
(ngModelChange)="onSelectChange($event)"
|
|
1284
|
+
(zOnBlur)="commitDraft()"
|
|
1285
|
+
(keydown)="onEditorKeydown($event)"
|
|
1286
|
+
(zControl)="onSelectControl($event)"
|
|
1287
|
+
/>
|
|
1288
|
+
}
|
|
1289
|
+
@case ('date') {
|
|
1290
|
+
<z-calendar
|
|
1291
|
+
#embeddedControl
|
|
1292
|
+
[class]="controlClass()"
|
|
1293
|
+
[style]="zConfig().style"
|
|
1294
|
+
[zSize]="zConfig().size"
|
|
1295
|
+
zMode="single"
|
|
1296
|
+
[zFormat]="zConfig().dateFormat"
|
|
1297
|
+
[zValueType]="zConfig().dateValueType"
|
|
1298
|
+
[zMinDate]="zConfig().minDate"
|
|
1299
|
+
[zMaxDate]="zConfig().maxDate"
|
|
1300
|
+
[zAllowClear]="zConfig().allowClear"
|
|
1301
|
+
[zLoading]="zConfig().loading"
|
|
1302
|
+
[zLoadingOutline]="true"
|
|
1303
|
+
[zDisabled]="zConfig().disabled"
|
|
1304
|
+
[zReadonly]="zConfig().readonly"
|
|
1305
|
+
[ngModel]="$any(zValue())"
|
|
1306
|
+
[ngModelOptions]="{ standalone: true }"
|
|
1307
|
+
(zChange)="onCalendarChange($event)"
|
|
1308
|
+
(keydown)="onEditorKeydown($event)"
|
|
1309
|
+
(zControl)="onCalendarControl($event)"
|
|
1310
|
+
/>
|
|
1311
|
+
}
|
|
1312
|
+
@default {
|
|
1313
|
+
<z-input
|
|
1314
|
+
#embeddedControl
|
|
1315
|
+
[class]="controlClass()"
|
|
1316
|
+
[style]="zConfig().style"
|
|
1317
|
+
[zSize]="zConfig().size"
|
|
1318
|
+
[zType]="inputType()"
|
|
1319
|
+
[zAlign]="zConfig().align"
|
|
1320
|
+
[zPlaceholder]="zConfig().placeholder"
|
|
1321
|
+
[zPrefix]="zConfig().prefix"
|
|
1322
|
+
[zSuffix]="zConfig().suffix"
|
|
1323
|
+
[zMin]="zConfig().min"
|
|
1324
|
+
[zMax]="zConfig().max"
|
|
1325
|
+
[zStep]="zConfig().step ?? 1"
|
|
1326
|
+
[zShowArrows]="zConfig().type === 'number'"
|
|
1327
|
+
[zMask]="zConfig().mask"
|
|
1328
|
+
[zDecimalPlaces]="zConfig().decimalPlaces"
|
|
1329
|
+
[zAllowNegative]="zConfig().allowNegative"
|
|
1330
|
+
[zThousandSeparator]="zConfig().thousandSeparator"
|
|
1331
|
+
[zDecimalMarker]="zConfig().decimalMarker"
|
|
1332
|
+
[zAllowClear]="zConfig().allowClear"
|
|
1333
|
+
[zLoading]="zConfig().loading"
|
|
1334
|
+
[zLoadingOutline]="true"
|
|
1335
|
+
[zDisabled]="zConfig().disabled"
|
|
1336
|
+
[zReadonly]="zConfig().readonly"
|
|
1337
|
+
[ngModel]="$any(zValue())"
|
|
1338
|
+
[ngModelOptions]="{ standalone: true }"
|
|
1339
|
+
(ngModelChange)="draftValue.set($event)"
|
|
1340
|
+
(zOnBlur)="commitDraft()"
|
|
1341
|
+
(zOnEnter)="commitDraft()"
|
|
1342
|
+
(zOnKeydown)="onEditorKeydown($event)"
|
|
1343
|
+
(zControl)="onInputControl($event)"
|
|
1344
|
+
/>
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
`, isInline: true, styles: [":host{position:absolute;z-index:2;inset:0;display:block;min-width:0;overflow:hidden;background:var(--background);box-shadow:inset 0 0 0 1px var(--primary)}:host ::ng-deep z-input,:host ::ng-deep z-select,:host ::ng-deep z-calendar,:host ::ng-deep .z-input-wrapper,:host ::ng-deep .z-select-wrapper,:host ::ng-deep .z-calendar-wrapper,:host ::ng-deep .z-input-wrapper>div,:host ::ng-deep .z-select-wrapper>div,:host ::ng-deep .z-calendar-wrapper>div{width:100%;height:100%;min-height:0}:host ::ng-deep .z-input-container,:host ::ng-deep .z-select-trigger,:host ::ng-deep .z-calendar-wrapper>div>div{width:100%;height:100%!important;min-height:0!important;border:0!important;border-radius:0!important;background:transparent!important;box-shadow:none!important;outline:0!important;--tw-ring-shadow: 0 0 #0000 !important}:host ::ng-deep .z-input-container,:host ::ng-deep .z-select-trigger,:host ::ng-deep .z-calendar-wrapper>div>div{gap:0!important;padding:0 12px!important;color:inherit;font:inherit;line-height:inherit}:host ::ng-deep .z-loading-outline-active{box-shadow:0 0 0 3px color-mix(in oklab,var(--ring) 50%,transparent)!important}:host ::ng-deep .z-input-native,:host ::ng-deep .z-select-trigger,:host ::ng-deep .z-calendar-wrapper input{color:inherit;font:inherit;line-height:inherit}:host ::ng-deep .z-calendar-wrapper>div>div>z-icon{display:none}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ZCalendarComponent, selector: "z-calendar", inputs: ["class", "zMode", "zSize", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zLoadingOutline", "zShowTime", "zTimeFormat", "zShowHour", "zShowMinute", "zShowSecond", "zQuickSelect", "zAllowEdit", "zShortTime", "zAllowClear", "zFormat", "zMinDate", "zMaxDate", "zValueType", "zValidators", "zShowOk", "zOkText", "zShowCancel", "zCancelText", "zDisabledDate", "zScrollClose", "zDefaultTime", "zRangeDefaultTime"], outputs: ["zControl", "zChange", "zOnBlur", "zOnFocus", "zEvent"], exportAs: ["zCalendar"] }, { kind: "component", type: ZInputComponent, selector: "z-input", inputs: ["class", "zType", "zSize", "zAlign", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zLoadingOutline", "zPrefix", "zSuffix", "zMin", "zMax", "zStep", "zShowArrows", "zMask", "zDecimalPlaces", "zAllowNegative", "zThousandSeparator", "zDecimalMarker", "zValidators", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zShowPasswordToggle", "zSearch", "zDebounce", "zAutofocus", "zAutoComplete", "zAllowClear", "zAutoSizeContent", "zRows", "zResize", "zMaxLength", "zAutoSuggest", "zColorConfig"], outputs: ["zOnSearch", "zOnChange", "zOnBlur", "zOnFocus", "zOnKeydown", "zOnEnter", "zOnColorCollapse", "zControl", "zEvent"], exportAs: ["zInput"] }, { kind: "component", type: ZSelectComponent, selector: "z-select", inputs: ["class", "zClassSelect", "zMode", "zSize", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zLoadingOutline", "zPrefix", "zAllowClear", "zShowCheck", "zWrap", "zShowSearch", "zPlaceholderSearch", "zDebounce", "zNotFoundText", "zEmptyText", "zEmptyIcon", "zMaxTagCount", "zDropdownMaxHeight", "zOptionHeight", "zVirtualScroll", "zDynamicSize", "zShowAction", "zOptions", "zConfig", "zTranslateLabels", "zKey", "zSearchServer", "zLoadingMore", "zEnableLoadMore", "zScrollDistance", "zMaxVisible", "zScrollClose", "zSticky", "zPosition", "zSelectedTemplate", "zOptionTemplate", "zActionTemplate", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zValidators"], outputs: ["zOnSearch", "zOnLoadMore", "zOnBlur", "zOnFocus", "zControl", "zEvent"], exportAs: ["zSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1348
|
+
}
|
|
1349
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableContentEditorComponent, decorators: [{
|
|
1350
|
+
type: Component,
|
|
1351
|
+
args: [{ selector: 'z-table-content-editor', imports: [FormsModule, ZCalendarComponent, ZInputComponent, ZSelectComponent], standalone: true, template: `
|
|
1352
|
+
@switch (zConfig().type) {
|
|
1353
|
+
@case ('select') {
|
|
1354
|
+
<z-select
|
|
1355
|
+
#embeddedControl
|
|
1356
|
+
[class]="controlClass()"
|
|
1357
|
+
[style]="zConfig().style"
|
|
1358
|
+
[zSize]="zConfig().size"
|
|
1359
|
+
[zMode]="zConfig().selectMode"
|
|
1360
|
+
[zConfig]="zConfig().selectConfig"
|
|
1361
|
+
[zShowSearch]="zConfig().selectShowSearch"
|
|
1362
|
+
[zAllowClear]="zConfig().allowClear"
|
|
1363
|
+
[zWrap]="zConfig().selectWrap"
|
|
1364
|
+
[zLoading]="zConfig().loading"
|
|
1365
|
+
[zLoadingOutline]="true"
|
|
1366
|
+
[zDisabled]="zConfig().disabled"
|
|
1367
|
+
[zReadonly]="zConfig().readonly"
|
|
1368
|
+
[zMaxTagCount]="zConfig().maxTagCount"
|
|
1369
|
+
[zPlaceholder]="zConfig().placeholder"
|
|
1370
|
+
[zOptions]="zConfig().options"
|
|
1371
|
+
[ngModel]="zValue()"
|
|
1372
|
+
[ngModelOptions]="{ standalone: true }"
|
|
1373
|
+
(ngModelChange)="onSelectChange($event)"
|
|
1374
|
+
(zOnBlur)="commitDraft()"
|
|
1375
|
+
(keydown)="onEditorKeydown($event)"
|
|
1376
|
+
(zControl)="onSelectControl($event)"
|
|
1377
|
+
/>
|
|
1378
|
+
}
|
|
1379
|
+
@case ('date') {
|
|
1380
|
+
<z-calendar
|
|
1381
|
+
#embeddedControl
|
|
1382
|
+
[class]="controlClass()"
|
|
1383
|
+
[style]="zConfig().style"
|
|
1384
|
+
[zSize]="zConfig().size"
|
|
1385
|
+
zMode="single"
|
|
1386
|
+
[zFormat]="zConfig().dateFormat"
|
|
1387
|
+
[zValueType]="zConfig().dateValueType"
|
|
1388
|
+
[zMinDate]="zConfig().minDate"
|
|
1389
|
+
[zMaxDate]="zConfig().maxDate"
|
|
1390
|
+
[zAllowClear]="zConfig().allowClear"
|
|
1391
|
+
[zLoading]="zConfig().loading"
|
|
1392
|
+
[zLoadingOutline]="true"
|
|
1393
|
+
[zDisabled]="zConfig().disabled"
|
|
1394
|
+
[zReadonly]="zConfig().readonly"
|
|
1395
|
+
[ngModel]="$any(zValue())"
|
|
1396
|
+
[ngModelOptions]="{ standalone: true }"
|
|
1397
|
+
(zChange)="onCalendarChange($event)"
|
|
1398
|
+
(keydown)="onEditorKeydown($event)"
|
|
1399
|
+
(zControl)="onCalendarControl($event)"
|
|
1400
|
+
/>
|
|
1401
|
+
}
|
|
1402
|
+
@default {
|
|
1403
|
+
<z-input
|
|
1404
|
+
#embeddedControl
|
|
1405
|
+
[class]="controlClass()"
|
|
1406
|
+
[style]="zConfig().style"
|
|
1407
|
+
[zSize]="zConfig().size"
|
|
1408
|
+
[zType]="inputType()"
|
|
1409
|
+
[zAlign]="zConfig().align"
|
|
1410
|
+
[zPlaceholder]="zConfig().placeholder"
|
|
1411
|
+
[zPrefix]="zConfig().prefix"
|
|
1412
|
+
[zSuffix]="zConfig().suffix"
|
|
1413
|
+
[zMin]="zConfig().min"
|
|
1414
|
+
[zMax]="zConfig().max"
|
|
1415
|
+
[zStep]="zConfig().step ?? 1"
|
|
1416
|
+
[zShowArrows]="zConfig().type === 'number'"
|
|
1417
|
+
[zMask]="zConfig().mask"
|
|
1418
|
+
[zDecimalPlaces]="zConfig().decimalPlaces"
|
|
1419
|
+
[zAllowNegative]="zConfig().allowNegative"
|
|
1420
|
+
[zThousandSeparator]="zConfig().thousandSeparator"
|
|
1421
|
+
[zDecimalMarker]="zConfig().decimalMarker"
|
|
1422
|
+
[zAllowClear]="zConfig().allowClear"
|
|
1423
|
+
[zLoading]="zConfig().loading"
|
|
1424
|
+
[zLoadingOutline]="true"
|
|
1425
|
+
[zDisabled]="zConfig().disabled"
|
|
1426
|
+
[zReadonly]="zConfig().readonly"
|
|
1427
|
+
[ngModel]="$any(zValue())"
|
|
1428
|
+
[ngModelOptions]="{ standalone: true }"
|
|
1429
|
+
(ngModelChange)="draftValue.set($event)"
|
|
1430
|
+
(zOnBlur)="commitDraft()"
|
|
1431
|
+
(zOnEnter)="commitDraft()"
|
|
1432
|
+
(zOnKeydown)="onEditorKeydown($event)"
|
|
1433
|
+
(zControl)="onInputControl($event)"
|
|
1434
|
+
/>
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{position:absolute;z-index:2;inset:0;display:block;min-width:0;overflow:hidden;background:var(--background);box-shadow:inset 0 0 0 1px var(--primary)}:host ::ng-deep z-input,:host ::ng-deep z-select,:host ::ng-deep z-calendar,:host ::ng-deep .z-input-wrapper,:host ::ng-deep .z-select-wrapper,:host ::ng-deep .z-calendar-wrapper,:host ::ng-deep .z-input-wrapper>div,:host ::ng-deep .z-select-wrapper>div,:host ::ng-deep .z-calendar-wrapper>div{width:100%;height:100%;min-height:0}:host ::ng-deep .z-input-container,:host ::ng-deep .z-select-trigger,:host ::ng-deep .z-calendar-wrapper>div>div{width:100%;height:100%!important;min-height:0!important;border:0!important;border-radius:0!important;background:transparent!important;box-shadow:none!important;outline:0!important;--tw-ring-shadow: 0 0 #0000 !important}:host ::ng-deep .z-input-container,:host ::ng-deep .z-select-trigger,:host ::ng-deep .z-calendar-wrapper>div>div{gap:0!important;padding:0 12px!important;color:inherit;font:inherit;line-height:inherit}:host ::ng-deep .z-loading-outline-active{box-shadow:0 0 0 3px color-mix(in oklab,var(--ring) 50%,transparent)!important}:host ::ng-deep .z-input-native,:host ::ng-deep .z-select-trigger,:host ::ng-deep .z-calendar-wrapper input{color:inherit;font:inherit;line-height:inherit}:host ::ng-deep .z-calendar-wrapper>div>div>z-icon{display:none}\n"] }]
|
|
1438
|
+
}], ctorParameters: () => [], propDecorators: { zValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "zValue", required: false }] }], zConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zConfig", required: true }] }], zCommit: [{ type: i0.Output, args: ["zCommit"] }], zCancel: [{ type: i0.Output, args: ["zCancel"] }] } });
|
|
1439
|
+
|
|
1438
1440
|
class ZTableEditCellComponent {
|
|
1439
1441
|
_destroyRef = inject(DestroyRef);
|
|
1440
1442
|
zRow = input.required(...(ngDevMode ? [{ debugName: "zRow" }] : []));
|