@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.
@@ -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
- class ZTableActionsComponent {
62
- zConfig = input.required(...(ngDevMode ? [{ debugName: "zConfig" }] : []));
63
- zRow = input.required(...(ngDevMode ? [{ debugName: "zRow" }] : []));
64
- zRowId = input.required(...(ngDevMode ? [{ debugName: "zRowId" }] : []));
65
- zDropdownButtonSize = input(Z_TABLE_DEFAULT_DROPDOWN_BUTTON_SIZE, ...(ngDevMode ? [{ debugName: "zDropdownButtonSize" }] : []));
66
- zActionClick = output();
67
- allActions = computed(() => {
68
- const config = this.zConfig();
69
- const row = this.zRow();
70
- const { actions } = config;
71
- const resolvedActions = typeof actions === 'function' ? actions(row) : actions;
72
- return resolvedActions.filter(action => {
73
- if (typeof action.hidden === 'function') {
74
- return !action.hidden(row);
75
- }
76
- return !action.hidden;
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
- content: tooltip.content ?? '',
132
- alwaysShow: tooltip.alwaysShow ?? true,
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
- _onActionClick(action, event) {
140
- event.stopPropagation();
141
- const states = this.actionStates();
142
- if (states[action.key]?.disabled) {
143
- return;
144
- }
145
- this._emitActionClick(action);
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
- _onDropdownItemClick(item) {
148
- const action = this.allActions().find(a => (a.label ?? a.key) === item.label);
149
- if (!action || this.actionStates()[action.key]?.disabled) {
150
- return;
151
- }
152
- this._emitActionClick(action);
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
- _emitActionClick(action) {
155
- this.zActionClick.emit({
156
- key: action.key,
157
- row: this.zRow(),
158
- rowId: this.zRowId(),
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
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
163
- 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: `
164
- <div class="z-table-actions flex items-center justify-center gap-1">
165
- @if (shouldShowAsButtons()) {
166
- @for (action of allActions(); track action.key) {
167
- @if (actionStates()[action.key].visible) {
168
- <button
169
- type="button"
170
- z-button
171
- z-tooltip
172
- [zType]="action.type ?? 'outline'"
173
- [zSize]="action.size ?? 'sm'"
174
- [zTypeIcon]="action.icon"
175
- zSizeIcon="14"
176
- [zLabel]="action.label ?? ''"
177
- [zLoading]="actionStates()[action.key].loading"
178
- [zDisabled]="actionStates()[action.key].disabled"
179
- [class]="action.class ?? ''"
180
- [zContent]="actionStates()[action.key].tooltipState.content"
181
- [zAlwaysShow]="actionStates()[action.key].tooltipState.alwaysShow"
182
- [zArrow]="actionStates()[action.key].tooltipState.arrow ?? true"
183
- [zOffset]="actionStates()[action.key].tooltipState.offset ?? 8"
184
- [zMaxWidth]="actionStates()[action.key].tooltipState.maxWidth ?? '250px'"
185
- (click)="_onActionClick(action, $event)"
186
- ></button>
187
- }
188
- }
189
- } @else {
190
- <z-dropdown-menu
191
- [zItems]="dropdownItems()"
192
- zPosition="bottom-right"
193
- [zButtonSize]="zDropdownButtonSize()"
194
- [zMinWidth]="160"
195
- (zOnItemClick)="_onDropdownItemClick($event)"
196
- >
197
- <button
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
- onInputControl(control) {
283
- this._inputControl = control;
284
- queueMicrotask(() => this._activateControl());
166
+ if (!isBodyConfig(col.body)) {
167
+ return { ...empty, content: col.body };
285
168
  }
286
- onSelectControl(control) {
287
- this._selectControl = control;
288
- queueMicrotask(() => this._activateControl());
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
- onCalendarControl(control) {
291
- this._calendarControl = control;
292
- queueMicrotask(() => this._activateControl());
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
- onSelectChange(value) {
295
- if (this.zConfig().selectMode !== 'single') {
296
- this.draftValue.set(value);
297
- return;
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
- this._commit(value);
300
- }
301
- onCalendarChange(value) {
302
- if (this._ignoreNextCalendarChange) {
303
- this._ignoreNextCalendarChange = false;
304
- return;
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
- this._commit(value);
249
+ parts.push(iconPart);
250
+ lastIndex = match.index + match[0].length;
307
251
  }
308
- commitDraft() {
309
- this._commit(this.draftValue());
252
+ if (lastIndex < content.length) {
253
+ parts.push({ type: 'text', value: content.slice(lastIndex) });
310
254
  }
311
- onEditorKeydown(event) {
312
- if (event.key !== 'Escape') {
313
- return;
314
- }
315
- event.preventDefault();
316
- event.stopPropagation();
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
- _commit(value) {
324
- if (this._finished) {
325
- return;
326
- }
327
- this._finished = true;
328
- this.zCommit.emit(value);
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
- _activateControl() {
331
- if (this._activated) {
332
- return;
333
- }
334
- const { type } = this.zConfig();
335
- if (type === 'select') {
336
- const trigger = this._host.nativeElement.querySelector('.z-select-trigger');
337
- if (!this._selectControl || !trigger) {
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 (type === 'date') {
346
- if (!this._calendarControl) {
347
- return;
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
- _focusCalendarInput() {
362
- const input = this._host.nativeElement.querySelector('.z-calendar-wrapper input');
363
- input?.focus();
285
+ return undefined;
286
+ };
287
+ const getZTableColumnType = (column, columnId) => {
288
+ if (column?.type) {
289
+ return column.type;
364
290
  }
365
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableContentEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
366
- 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: `
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
- `, 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 });
453
- }
454
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableContentEditorComponent, decorators: [{
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
- `, 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"] }]
543
- }], 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"] }] } });
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
- return typeof visible === 'function' ? visible() : visible;
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
- return col;
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 config.constructor === Object;
307
+ return 'data';
580
308
  };
581
- /** Type guard: is this a full header config object (not just content shorthand)? */
582
- const isHeaderConfig = (config) => isObjectConfig(config);
583
- /** Type guard: is this a full body config object (not just content shorthand)? */
584
- const isBodyConfig = (config) => isObjectConfig(config);
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
- * Internal helper that normalizes header/footer config into a consistent shape.
590
- * Handles both shorthand (just content) and full config objects.
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 getHeaderOrFooterConfigInternal = (col, type, footerRowIndex = 0) => {
593
- const empty = {
594
- content: undefined,
595
- class: undefined,
596
- style: undefined,
597
- align: undefined,
598
- tooltip: undefined,
599
- rowSpan: undefined,
600
- colSpan: undefined,
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" }] : []));