@aquera/ngx-smart-table 0.0.3-alpha → 0.0.6-alpha
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/esm2020/lib/editors/nile-calendar-editor.mjs +2 -5
- package/esm2020/lib/editors/nile-date-picker-editor.mjs +38 -77
- package/esm2020/lib/editors/nile-select-editor.mjs +53 -3
- package/esm2020/lib/models/cell-strategies.interface.mjs +1 -1
- package/esm2020/lib/renderer/components/st-cell/st-cell.component.mjs +10 -4
- package/esm2020/lib/renderer/components/st-column-menu/st-column-menu.component.mjs +2 -2
- package/esm2020/lib/renderer/components/st-table/st-table.component.mjs +18 -10
- package/esm2020/lib/renderer/components/st-table-actions/st-table-actions.component.mjs +15 -17
- package/fesm2015/aquera-ngx-smart-table.mjs +485 -465
- package/fesm2015/aquera-ngx-smart-table.mjs.map +1 -1
- package/fesm2020/aquera-ngx-smart-table.mjs +476 -456
- package/fesm2020/aquera-ngx-smart-table.mjs.map +1 -1
- package/lib/editors/nile-calendar-editor.d.ts +1 -2
- package/lib/editors/nile-date-picker-editor.d.ts +6 -4
- package/lib/editors/nile-select-editor.d.ts +2 -0
- package/lib/models/cell-strategies.interface.d.ts +7 -0
- package/package.json +1 -1
|
@@ -3499,6 +3499,7 @@ class NileInputEditor {
|
|
|
3499
3499
|
class NileSelectEditor {
|
|
3500
3500
|
constructor(options) {
|
|
3501
3501
|
this.options = options;
|
|
3502
|
+
this.acceptsInitialKeypress = false;
|
|
3502
3503
|
this.eventListeners = [];
|
|
3503
3504
|
this.currentOptions = [];
|
|
3504
3505
|
// Handle Observable options
|
|
@@ -3547,6 +3548,11 @@ class NileSelectEditor {
|
|
|
3547
3548
|
var _a, _b;
|
|
3548
3549
|
(_a = this.select) === null || _a === void 0 ? void 0 : _a.focus();
|
|
3549
3550
|
(_b = this.select) === null || _b === void 0 ? void 0 : _b.click();
|
|
3551
|
+
// Find the portal div for multi-select click detection
|
|
3552
|
+
if (this.options.multiple) {
|
|
3553
|
+
// Portal div is appended to document body
|
|
3554
|
+
this.portalDiv = document.querySelector('.nile-select-portal-append');
|
|
3555
|
+
}
|
|
3550
3556
|
}, 0);
|
|
3551
3557
|
}
|
|
3552
3558
|
/**
|
|
@@ -3645,6 +3651,9 @@ class NileSelectEditor {
|
|
|
3645
3651
|
if (this.options.portal !== undefined) {
|
|
3646
3652
|
this.select.portal = this.options.portal;
|
|
3647
3653
|
}
|
|
3654
|
+
else {
|
|
3655
|
+
this.select.portal = true; // Default to portal mode for better positioning
|
|
3656
|
+
}
|
|
3648
3657
|
// Prevent width syncing issues in table cells
|
|
3649
3658
|
this.select.noWidthSync = true;
|
|
3650
3659
|
}
|
|
@@ -3723,7 +3732,11 @@ class NileSelectEditor {
|
|
|
3723
3732
|
(_b = this.select) === null || _b === void 0 ? void 0 : _b.reportValidity();
|
|
3724
3733
|
return;
|
|
3725
3734
|
}
|
|
3726
|
-
|
|
3735
|
+
// Only save immediately for single-select
|
|
3736
|
+
// Multi-select saves on outside click
|
|
3737
|
+
if (!this.options.multiple) {
|
|
3738
|
+
context.onSave(this.parseValue(customEvent.detail.value));
|
|
3739
|
+
}
|
|
3727
3740
|
};
|
|
3728
3741
|
this.select.addEventListener('nile-change', changeHandler);
|
|
3729
3742
|
this.eventListeners.push({ event: 'nile-change', handler: changeHandler });
|
|
@@ -3756,6 +3769,36 @@ class NileSelectEditor {
|
|
|
3756
3769
|
this.select.addEventListener('nile-search', searchHandler);
|
|
3757
3770
|
this.eventListeners.push({ event: 'nile-search', handler: searchHandler });
|
|
3758
3771
|
}
|
|
3772
|
+
// For multi-select: detect clicks outside portal and select
|
|
3773
|
+
if (this.options.multiple) {
|
|
3774
|
+
const documentClickHandler = (e) => {
|
|
3775
|
+
var _a, _b, _c, _d;
|
|
3776
|
+
const mouseEvent = e;
|
|
3777
|
+
const target = mouseEvent.target;
|
|
3778
|
+
// Check if portal div exists (might take a moment to render)
|
|
3779
|
+
if (!this.portalDiv) {
|
|
3780
|
+
this.portalDiv = document.querySelector('.nile-select-portal-append');
|
|
3781
|
+
}
|
|
3782
|
+
// Determine if click is inside the select or portal
|
|
3783
|
+
const clickedInsideSelect = (_a = this.select) === null || _a === void 0 ? void 0 : _a.contains(target);
|
|
3784
|
+
const clickedInsidePortal = (_b = this.portalDiv) === null || _b === void 0 ? void 0 : _b.contains(target);
|
|
3785
|
+
// If clicked outside both select and portal, save and close
|
|
3786
|
+
if (!clickedInsideSelect && !clickedInsidePortal) {
|
|
3787
|
+
if (validateOnSave && !((_c = this.select) === null || _c === void 0 ? void 0 : _c.checkValidity())) {
|
|
3788
|
+
(_d = this.select) === null || _d === void 0 ? void 0 : _d.reportValidity();
|
|
3789
|
+
return;
|
|
3790
|
+
}
|
|
3791
|
+
context.onSave(this.getCurrentValue());
|
|
3792
|
+
}
|
|
3793
|
+
// Otherwise, click is inside - do nothing (dropdown stays open)
|
|
3794
|
+
};
|
|
3795
|
+
// Add to document with capture phase
|
|
3796
|
+
document.addEventListener('click', documentClickHandler, true);
|
|
3797
|
+
this.eventListeners.push({
|
|
3798
|
+
event: 'document-click',
|
|
3799
|
+
handler: documentClickHandler
|
|
3800
|
+
});
|
|
3801
|
+
}
|
|
3759
3802
|
}
|
|
3760
3803
|
/**
|
|
3761
3804
|
* Parse value based on selection mode
|
|
@@ -3784,11 +3827,19 @@ class NileSelectEditor {
|
|
|
3784
3827
|
if (this.select) {
|
|
3785
3828
|
this.eventListeners.forEach(({ event, handler }) => {
|
|
3786
3829
|
var _a;
|
|
3787
|
-
(
|
|
3830
|
+
if (event === 'document-click') {
|
|
3831
|
+
// Remove from document for multi-select click handler
|
|
3832
|
+
document.removeEventListener('click', handler, true);
|
|
3833
|
+
}
|
|
3834
|
+
else {
|
|
3835
|
+
// Remove from select element
|
|
3836
|
+
(_a = this.select) === null || _a === void 0 ? void 0 : _a.removeEventListener(event, handler);
|
|
3837
|
+
}
|
|
3788
3838
|
});
|
|
3789
3839
|
this.eventListeners = [];
|
|
3790
3840
|
this.select.remove();
|
|
3791
3841
|
this.select = undefined;
|
|
3842
|
+
this.portalDiv = undefined; // Clean up portal reference
|
|
3792
3843
|
}
|
|
3793
3844
|
}
|
|
3794
3845
|
focus() {
|
|
@@ -4057,6 +4108,7 @@ class NileAutoCompleteEditor {
|
|
|
4057
4108
|
class NileCalendarEditor {
|
|
4058
4109
|
constructor(options) {
|
|
4059
4110
|
this.options = options;
|
|
4111
|
+
this.acceptsInitialKeypress = false;
|
|
4060
4112
|
this.eventListeners = [];
|
|
4061
4113
|
}
|
|
4062
4114
|
edit(context) {
|
|
@@ -4100,7 +4152,7 @@ class NileCalendarEditor {
|
|
|
4100
4152
|
* Apply all configuration options to the NileCalendar element
|
|
4101
4153
|
*/
|
|
4102
4154
|
applyOptions() {
|
|
4103
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s
|
|
4155
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
4104
4156
|
if (!this.calendar)
|
|
4105
4157
|
return;
|
|
4106
4158
|
// Date format (default: ISO format)
|
|
@@ -4160,10 +4212,6 @@ class NileCalendarEditor {
|
|
|
4160
4212
|
if ((_s = this.options) === null || _s === void 0 ? void 0 : _s.size) {
|
|
4161
4213
|
this.calendar.setAttribute('size', this.options.size);
|
|
4162
4214
|
}
|
|
4163
|
-
// Portal rendering (default: true)
|
|
4164
|
-
if (((_t = this.options) === null || _t === void 0 ? void 0 : _t.portal) !== false) {
|
|
4165
|
-
this.calendar.setAttribute('portal', 'true');
|
|
4166
|
-
}
|
|
4167
4215
|
}
|
|
4168
4216
|
/**
|
|
4169
4217
|
* Set up all event listeners with proper cleanup tracking
|
|
@@ -4268,7 +4316,7 @@ class NileCalendarEditor {
|
|
|
4268
4316
|
|
|
4269
4317
|
/**
|
|
4270
4318
|
* Custom editor using NileDatePicker from @aquera/nile-elements
|
|
4271
|
-
* Supports both single date and range selection with slot-based trigger
|
|
4319
|
+
* Supports both single date and range selection with slot-based trigger div
|
|
4272
4320
|
* Returns string values for both modes:
|
|
4273
4321
|
* - Single mode: 'YYYY-MM-DD'
|
|
4274
4322
|
* - Range mode: 'YYYY-MM-DD - YYYY-MM-DD'
|
|
@@ -4283,10 +4331,11 @@ class NileCalendarEditor {
|
|
|
4283
4331
|
class NileDatePickerEditor {
|
|
4284
4332
|
constructor(options) {
|
|
4285
4333
|
this.options = options;
|
|
4334
|
+
this.acceptsInitialKeypress = false;
|
|
4286
4335
|
this.eventListeners = [];
|
|
4287
4336
|
}
|
|
4288
4337
|
edit(context) {
|
|
4289
|
-
var _a
|
|
4338
|
+
var _a;
|
|
4290
4339
|
if (!context.container) {
|
|
4291
4340
|
console.warn('NileDatePickerEditor requires a container element');
|
|
4292
4341
|
return;
|
|
@@ -4298,52 +4347,55 @@ class NileDatePickerEditor {
|
|
|
4298
4347
|
this.datePicker.style.width = 'inherit';
|
|
4299
4348
|
this.datePicker.style.height = 'inherit';
|
|
4300
4349
|
this.datePicker.style.boxSizing = 'border-box';
|
|
4301
|
-
// Create trigger
|
|
4302
|
-
this.
|
|
4303
|
-
this.
|
|
4350
|
+
// Create trigger div with slot
|
|
4351
|
+
this.triggerDiv = document.createElement('div');
|
|
4352
|
+
this.triggerDiv.setAttribute('slot', 'trigger');
|
|
4353
|
+
this.triggerDiv.setAttribute('contenteditable', 'false');
|
|
4354
|
+
this.triggerDiv.style.width = '100%';
|
|
4355
|
+
this.triggerDiv.style.minHeight = '28px';
|
|
4356
|
+
this.triggerDiv.style.cursor = 'pointer';
|
|
4357
|
+
this.triggerDiv.style.boxSizing = 'border-box';
|
|
4304
4358
|
// Set initial value
|
|
4305
4359
|
this.setInitialValue(context.value);
|
|
4306
|
-
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.label) {
|
|
4307
|
-
this.triggerInput.label = this.options.label;
|
|
4308
|
-
}
|
|
4309
4360
|
// Apply configuration options
|
|
4310
4361
|
this.applyOptions();
|
|
4311
4362
|
// Append trigger to date picker (slot-based)
|
|
4312
|
-
this.datePicker.appendChild(this.
|
|
4363
|
+
this.datePicker.appendChild(this.triggerDiv);
|
|
4313
4364
|
// Set up event listeners
|
|
4314
4365
|
this.setupEventListeners(context);
|
|
4315
4366
|
// Append to container
|
|
4316
4367
|
context.container.innerHTML = '';
|
|
4317
4368
|
context.container.appendChild(this.datePicker);
|
|
4318
4369
|
// Auto focus and open the date picker
|
|
4319
|
-
if (((
|
|
4370
|
+
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.autoFocus) !== false) {
|
|
4320
4371
|
setTimeout(() => {
|
|
4321
4372
|
var _a, _b;
|
|
4322
|
-
(_a = this.
|
|
4373
|
+
(_a = this.triggerDiv) === null || _a === void 0 ? void 0 : _a.focus();
|
|
4323
4374
|
// Trigger a click to open the date picker dropdown
|
|
4324
|
-
(_b = this.
|
|
4375
|
+
(_b = this.triggerDiv) === null || _b === void 0 ? void 0 : _b.click();
|
|
4325
4376
|
}, 0);
|
|
4326
4377
|
}
|
|
4327
4378
|
}
|
|
4328
4379
|
/**
|
|
4329
|
-
* Set initial value in the trigger
|
|
4380
|
+
* Set initial value in the trigger div
|
|
4330
4381
|
*/
|
|
4331
4382
|
setInitialValue(value) {
|
|
4332
|
-
if (!this.
|
|
4383
|
+
if (!this.triggerDiv)
|
|
4333
4384
|
return;
|
|
4334
4385
|
if (!value) {
|
|
4335
|
-
this.
|
|
4386
|
+
this.triggerDiv.textContent = '';
|
|
4336
4387
|
return;
|
|
4337
4388
|
}
|
|
4338
4389
|
// Both single and range modes use string value
|
|
4339
|
-
this.
|
|
4390
|
+
this.triggerDiv.textContent = String(value);
|
|
4340
4391
|
}
|
|
4341
4392
|
/**
|
|
4342
|
-
* Apply
|
|
4393
|
+
* Apply configuration options to the date picker
|
|
4394
|
+
* Note: Trigger is now a simple div, so input-specific options are not applied
|
|
4343
4395
|
*/
|
|
4344
4396
|
applyOptions() {
|
|
4345
|
-
var _a, _b, _c, _d
|
|
4346
|
-
if (!this.datePicker
|
|
4397
|
+
var _a, _b, _c, _d;
|
|
4398
|
+
if (!this.datePicker)
|
|
4347
4399
|
return;
|
|
4348
4400
|
// Configure NileDatePicker
|
|
4349
4401
|
const dateFormat = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.dateFormat) || 'YYYY-MM-DD';
|
|
@@ -4354,49 +4406,21 @@ class NileDatePickerEditor {
|
|
|
4354
4406
|
if ((_c = this.options) === null || _c === void 0 ? void 0 : _c.syncDatePicker) {
|
|
4355
4407
|
this.datePicker.setAttribute('syncDatePicker', String(this.options.syncDatePicker));
|
|
4356
4408
|
}
|
|
4357
|
-
//
|
|
4358
|
-
if ((_d = this.options) === null || _d === void 0 ? void 0 : _d.disabled) {
|
|
4359
|
-
this.
|
|
4360
|
-
|
|
4361
|
-
if ((_e = this.options) === null || _e === void 0 ? void 0 : _e.clearable) {
|
|
4362
|
-
this.triggerInput.clearable = this.options.clearable;
|
|
4363
|
-
}
|
|
4364
|
-
if ((_f = this.options) === null || _f === void 0 ? void 0 : _f.helpText) {
|
|
4365
|
-
this.triggerInput.setAttribute('help-text', this.options.helpText);
|
|
4366
|
-
}
|
|
4367
|
-
// Visual states on trigger
|
|
4368
|
-
if ((_g = this.options) === null || _g === void 0 ? void 0 : _g.warning) {
|
|
4369
|
-
this.triggerInput.setAttribute('warning', String(this.options.warning));
|
|
4370
|
-
}
|
|
4371
|
-
if ((_h = this.options) === null || _h === void 0 ? void 0 : _h.error) {
|
|
4372
|
-
this.triggerInput.setAttribute('error', String(this.options.error));
|
|
4373
|
-
}
|
|
4374
|
-
if ((_j = this.options) === null || _j === void 0 ? void 0 : _j.success) {
|
|
4375
|
-
this.triggerInput.setAttribute('success', String(this.options.success));
|
|
4376
|
-
}
|
|
4377
|
-
if ((_k = this.options) === null || _k === void 0 ? void 0 : _k.errorMessage) {
|
|
4378
|
-
this.triggerInput.setAttribute('error-message', this.options.errorMessage);
|
|
4379
|
-
}
|
|
4380
|
-
// Styling
|
|
4381
|
-
if ((_l = this.options) === null || _l === void 0 ? void 0 : _l.size) {
|
|
4382
|
-
this.triggerInput.setAttribute('size', String(this.options.size));
|
|
4383
|
-
}
|
|
4384
|
-
if ((_m = this.options) === null || _m === void 0 ? void 0 : _m.filled) {
|
|
4385
|
-
this.triggerInput.setAttribute('filled', String(this.options.filled));
|
|
4386
|
-
}
|
|
4387
|
-
if ((_o = this.options) === null || _o === void 0 ? void 0 : _o.pill) {
|
|
4388
|
-
this.triggerInput.setAttribute('pill', String(this.options.pill));
|
|
4409
|
+
// Trigger div styling (disabled state can be indicated with opacity)
|
|
4410
|
+
if (this.triggerDiv && ((_d = this.options) === null || _d === void 0 ? void 0 : _d.disabled)) {
|
|
4411
|
+
this.triggerDiv.style.opacity = '0.5';
|
|
4412
|
+
this.triggerDiv.style.pointerEvents = 'none';
|
|
4389
4413
|
}
|
|
4390
4414
|
}
|
|
4391
4415
|
/**
|
|
4392
4416
|
* Set up all event listeners with proper cleanup tracking
|
|
4393
4417
|
*/
|
|
4394
4418
|
setupEventListeners(context) {
|
|
4395
|
-
var _a
|
|
4396
|
-
if (!this.datePicker || !this.
|
|
4419
|
+
var _a;
|
|
4420
|
+
if (!this.datePicker || !this.triggerDiv)
|
|
4397
4421
|
return;
|
|
4398
4422
|
const validateOnSave = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.validateOnSave) !== false;
|
|
4399
|
-
// Keyboard events on trigger
|
|
4423
|
+
// Keyboard events on trigger div
|
|
4400
4424
|
const keydownHandler = (e) => {
|
|
4401
4425
|
const keyEvent = e;
|
|
4402
4426
|
if (keyEvent.key === 'Enter') {
|
|
@@ -4414,8 +4438,12 @@ class NileDatePickerEditor {
|
|
|
4414
4438
|
keyEvent.stopPropagation();
|
|
4415
4439
|
this.saveValue(context, validateOnSave);
|
|
4416
4440
|
}
|
|
4441
|
+
else {
|
|
4442
|
+
// Prevent all other keypresses from typing into the div
|
|
4443
|
+
keyEvent.preventDefault();
|
|
4444
|
+
}
|
|
4417
4445
|
};
|
|
4418
|
-
this.
|
|
4446
|
+
this.triggerDiv.addEventListener('keydown', keydownHandler);
|
|
4419
4447
|
this.eventListeners.push({ event: 'keydown', handler: keydownHandler });
|
|
4420
4448
|
// nile-change event on date picker
|
|
4421
4449
|
const changeHandler = (e) => {
|
|
@@ -4435,26 +4463,6 @@ class NileDatePickerEditor {
|
|
|
4435
4463
|
};
|
|
4436
4464
|
this.datePicker.addEventListener('nile-change', changeHandler);
|
|
4437
4465
|
this.eventListeners.push({ event: 'nile-change', handler: changeHandler });
|
|
4438
|
-
// nile-blur event on trigger input
|
|
4439
|
-
const blurHandler = (e) => {
|
|
4440
|
-
var _a;
|
|
4441
|
-
const customEvent = e;
|
|
4442
|
-
// For blur, get value from trigger input directly
|
|
4443
|
-
const inputValue = ((_a = this.triggerInput) === null || _a === void 0 ? void 0 : _a.value) || '';
|
|
4444
|
-
if (inputValue) {
|
|
4445
|
-
context.onSave(this.parseValue(inputValue));
|
|
4446
|
-
}
|
|
4447
|
-
};
|
|
4448
|
-
this.triggerInput.addEventListener('nile-blur', blurHandler);
|
|
4449
|
-
this.eventListeners.push({ event: 'nile-blur', handler: blurHandler });
|
|
4450
|
-
// nile-clear event
|
|
4451
|
-
if ((_b = this.options) === null || _b === void 0 ? void 0 : _b.clearable) {
|
|
4452
|
-
const clearHandler = (e) => {
|
|
4453
|
-
context.onSave('');
|
|
4454
|
-
};
|
|
4455
|
-
this.triggerInput.addEventListener('nile-clear', clearHandler);
|
|
4456
|
-
this.eventListeners.push({ event: 'nile-clear', handler: clearHandler });
|
|
4457
|
-
}
|
|
4458
4466
|
}
|
|
4459
4467
|
/**
|
|
4460
4468
|
* Save value with optional validation
|
|
@@ -4475,29 +4483,29 @@ class NileDatePickerEditor {
|
|
|
4475
4483
|
}
|
|
4476
4484
|
getCurrentValue() {
|
|
4477
4485
|
var _a;
|
|
4478
|
-
if (!this.
|
|
4486
|
+
if (!this.triggerDiv) {
|
|
4479
4487
|
return '';
|
|
4480
4488
|
}
|
|
4481
|
-
return this.parseValue((_a = this.
|
|
4489
|
+
return this.parseValue((_a = this.triggerDiv.textContent) !== null && _a !== void 0 ? _a : '');
|
|
4482
4490
|
}
|
|
4483
4491
|
destroy() {
|
|
4484
|
-
if (this.datePicker || this.
|
|
4492
|
+
if (this.datePicker || this.triggerDiv) {
|
|
4485
4493
|
this.eventListeners.forEach(({ event, handler }) => {
|
|
4486
4494
|
var _a, _b;
|
|
4487
4495
|
(_a = this.datePicker) === null || _a === void 0 ? void 0 : _a.removeEventListener(event, handler);
|
|
4488
|
-
(_b = this.
|
|
4496
|
+
(_b = this.triggerDiv) === null || _b === void 0 ? void 0 : _b.removeEventListener(event, handler);
|
|
4489
4497
|
});
|
|
4490
4498
|
this.eventListeners = [];
|
|
4491
4499
|
if (this.datePicker) {
|
|
4492
4500
|
this.datePicker.remove();
|
|
4493
4501
|
this.datePicker = undefined;
|
|
4494
4502
|
}
|
|
4495
|
-
this.
|
|
4503
|
+
this.triggerDiv = undefined;
|
|
4496
4504
|
}
|
|
4497
4505
|
}
|
|
4498
4506
|
focus() {
|
|
4499
4507
|
var _a;
|
|
4500
|
-
(_a = this.
|
|
4508
|
+
(_a = this.triggerDiv) === null || _a === void 0 ? void 0 : _a.focus();
|
|
4501
4509
|
}
|
|
4502
4510
|
}
|
|
4503
4511
|
|
|
@@ -4856,12 +4864,18 @@ class StCellComponent {
|
|
|
4856
4864
|
startEditWithKey(key) {
|
|
4857
4865
|
const canStart = this.cell.startEdit();
|
|
4858
4866
|
if (canStart) {
|
|
4859
|
-
// Replace current value with the key
|
|
4860
|
-
this.cell.setValue(key, false);
|
|
4861
4867
|
const column = this.cell.getColumnConfig();
|
|
4868
|
+
const editor = column.editor;
|
|
4869
|
+
// Only set initial keypress value if editor accepts it
|
|
4870
|
+
// Default to true for backward compatibility with existing editors
|
|
4871
|
+
const acceptsKeypress = (editor === null || editor === void 0 ? void 0 : editor.acceptsInitialKeypress) !== false;
|
|
4872
|
+
if (acceptsKeypress) {
|
|
4873
|
+
// Replace current value with the key
|
|
4874
|
+
this.cell.setValue(key, false);
|
|
4875
|
+
}
|
|
4862
4876
|
const editEvent = {
|
|
4863
4877
|
cell: this.cell,
|
|
4864
|
-
value: key,
|
|
4878
|
+
value: acceptsKeypress ? key : this.cell.getValue(),
|
|
4865
4879
|
rowData: this.cell.getRowData(),
|
|
4866
4880
|
columnKey: column.key,
|
|
4867
4881
|
rowIndex: this.cell.getRowIndex(),
|
|
@@ -6800,10 +6814,10 @@ class StColumnMenuDropdownComponent {
|
|
|
6800
6814
|
}
|
|
6801
6815
|
}
|
|
6802
6816
|
StColumnMenuDropdownComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StColumnMenuDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6803
|
-
StColumnMenuDropdownComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StColumnMenuDropdownComponent, selector: "st-column-menu-dropdown", inputs: { isOpen: "isOpen", position: "position", context: "context" }, outputs: { actionClicked: "actionClicked", closed: "closed" }, host: { listeners: { "click": "onBackdropClick($event)" } }, viewQueries: [{ propertyName: "filterPopup", first: true, predicate: ["filterPopup"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Dropdown container with backdrop -->\n<div class=\"dropdown-container\" *ngIf=\"isOpen && context\">\n <!-- Backdrop -->\n <div class=\"dropdown-backdrop\" (click)=\"closed.emit()\"></div>\n \n <!-- Dropdown menu -->\n <div class=\"column-menu-dropdown\" [ngStyle]=\"dropdownStyle\">\n <!-- Main menu with actions -->\n <nile-menu *ngIf=\"!isFilterOpen\">\n <!-- Dynamically render all visible actions -->\n <ng-container *ngFor=\"let action of visibleActions; let i = index; let last = last\">\n <nile-menu-item \n (click)=\"onActionClick(action)\"\n [class.disabled]=\"isActionDisabled(action)\"\n [class.active]=\"isActionActive(action)\">\n <span class=\"checkmark\" *ngIf=\"isActionActive(action)\">\u2713</span>\n <nile-icon slot=\"prefix\" *ngIf=\"action.icon && !isActionActive(action)\" [name]=\"action.icon\"></nile-icon>\n <span class=\"action-label\">{{ action.label }}</span>\n </nile-menu-item>\n \n <!-- Add divider after action groups -->\n <nile-divider *ngIf=\"shouldShowDividerAfter(action, i, last)\"></nile-divider>\n </ng-container>\n \n <!-- Fallback if no actions -->\n <nile-menu-item *ngIf=\"visibleActions.length === 0\">\n No actions available\n </nile-menu-item>\n </nile-menu>\n \n <!-- Filter popup (conditionally rendered) -->\n <st-column-filter\n #filterPopup\n *ngIf=\"isFilterOpen && context\"\n [column]=\"context.column\"\n [tableState]=\"context.tableState\"\n [columnIndex]=\"context.columnIndex\"\n [isFirstColumn]=\"context.isFirstColumn\"\n [isLastColumn]=\"context.isLastColumn\"\n [isOpen]=\"isFilterOpen\"\n (filterApplied)=\"onFilterApplied($event)\"\n (filterCleared)=\"onFilterCleared()\"\n (closed)=\"onFilterClosed()\">\n </st-column-filter>\n </div>\n</div>\n", styles: [".dropdown-container{position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9998}.dropdown-backdrop{position:absolute;top:0;left:0;width:100%;height:100%;
|
|
6817
|
+
StColumnMenuDropdownComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StColumnMenuDropdownComponent, selector: "st-column-menu-dropdown", inputs: { isOpen: "isOpen", position: "position", context: "context" }, outputs: { actionClicked: "actionClicked", closed: "closed" }, host: { listeners: { "click": "onBackdropClick($event)" } }, viewQueries: [{ propertyName: "filterPopup", first: true, predicate: ["filterPopup"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Dropdown container with backdrop -->\n<div class=\"dropdown-container\" *ngIf=\"isOpen && context\">\n <!-- Backdrop -->\n <div class=\"dropdown-backdrop\" (click)=\"closed.emit()\"></div>\n \n <!-- Dropdown menu -->\n <div class=\"column-menu-dropdown\" [ngStyle]=\"dropdownStyle\">\n <!-- Main menu with actions -->\n <nile-menu *ngIf=\"!isFilterOpen\">\n <!-- Dynamically render all visible actions -->\n <ng-container *ngFor=\"let action of visibleActions; let i = index; let last = last\">\n <nile-menu-item \n (click)=\"onActionClick(action)\"\n [class.disabled]=\"isActionDisabled(action)\"\n [class.active]=\"isActionActive(action)\">\n <span class=\"checkmark\" *ngIf=\"isActionActive(action)\">\u2713</span>\n <nile-icon slot=\"prefix\" *ngIf=\"action.icon && !isActionActive(action)\" [name]=\"action.icon\"></nile-icon>\n <span class=\"action-label\">{{ action.label }}</span>\n </nile-menu-item>\n \n <!-- Add divider after action groups -->\n <nile-divider *ngIf=\"shouldShowDividerAfter(action, i, last)\"></nile-divider>\n </ng-container>\n \n <!-- Fallback if no actions -->\n <nile-menu-item *ngIf=\"visibleActions.length === 0\">\n No actions available\n </nile-menu-item>\n </nile-menu>\n \n <!-- Filter popup (conditionally rendered) -->\n <st-column-filter\n #filterPopup\n *ngIf=\"isFilterOpen && context\"\n [column]=\"context.column\"\n [tableState]=\"context.tableState\"\n [columnIndex]=\"context.columnIndex\"\n [isFirstColumn]=\"context.isFirstColumn\"\n [isLastColumn]=\"context.isLastColumn\"\n [isOpen]=\"isFilterOpen\"\n (filterApplied)=\"onFilterApplied($event)\"\n (filterCleared)=\"onFilterCleared()\"\n (closed)=\"onFilterClosed()\">\n </st-column-filter>\n </div>\n</div>\n", styles: [".dropdown-container{position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9998}.dropdown-backdrop{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:auto;z-index:9998}.column-menu-dropdown{min-width:200px;max-width:300px;background-color:#fff;border-radius:8px;box-shadow:0 10px 25px #00000026;overflow:hidden;pointer-events:auto;z-index:9999}nile-menu nile-divider::part(divider){margin:0}nile-menu nile-menu-item::part(base){height:2.5rem;min-height:auto}nile-menu nile-menu-item .checkmark{margin-right:8px;color:#4299e1;font-weight:700}\n"], components: [{ type: StColumnFilterComponent, selector: "st-column-filter", inputs: ["column", "tableState", "columnIndex", "isFirstColumn", "isLastColumn", "isOpen", "filterContext"], outputs: ["closed", "filterApplied", "filterCleared"] }], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
6804
6818
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StColumnMenuDropdownComponent, decorators: [{
|
|
6805
6819
|
type: Component,
|
|
6806
|
-
args: [{ selector: 'st-column-menu-dropdown', template: "<!-- Dropdown container with backdrop -->\n<div class=\"dropdown-container\" *ngIf=\"isOpen && context\">\n <!-- Backdrop -->\n <div class=\"dropdown-backdrop\" (click)=\"closed.emit()\"></div>\n \n <!-- Dropdown menu -->\n <div class=\"column-menu-dropdown\" [ngStyle]=\"dropdownStyle\">\n <!-- Main menu with actions -->\n <nile-menu *ngIf=\"!isFilterOpen\">\n <!-- Dynamically render all visible actions -->\n <ng-container *ngFor=\"let action of visibleActions; let i = index; let last = last\">\n <nile-menu-item \n (click)=\"onActionClick(action)\"\n [class.disabled]=\"isActionDisabled(action)\"\n [class.active]=\"isActionActive(action)\">\n <span class=\"checkmark\" *ngIf=\"isActionActive(action)\">\u2713</span>\n <nile-icon slot=\"prefix\" *ngIf=\"action.icon && !isActionActive(action)\" [name]=\"action.icon\"></nile-icon>\n <span class=\"action-label\">{{ action.label }}</span>\n </nile-menu-item>\n \n <!-- Add divider after action groups -->\n <nile-divider *ngIf=\"shouldShowDividerAfter(action, i, last)\"></nile-divider>\n </ng-container>\n \n <!-- Fallback if no actions -->\n <nile-menu-item *ngIf=\"visibleActions.length === 0\">\n No actions available\n </nile-menu-item>\n </nile-menu>\n \n <!-- Filter popup (conditionally rendered) -->\n <st-column-filter\n #filterPopup\n *ngIf=\"isFilterOpen && context\"\n [column]=\"context.column\"\n [tableState]=\"context.tableState\"\n [columnIndex]=\"context.columnIndex\"\n [isFirstColumn]=\"context.isFirstColumn\"\n [isLastColumn]=\"context.isLastColumn\"\n [isOpen]=\"isFilterOpen\"\n (filterApplied)=\"onFilterApplied($event)\"\n (filterCleared)=\"onFilterCleared()\"\n (closed)=\"onFilterClosed()\">\n </st-column-filter>\n </div>\n</div>\n", styles: [".dropdown-container{position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9998}.dropdown-backdrop{position:absolute;top:0;left:0;width:100%;height:100%;
|
|
6820
|
+
args: [{ selector: 'st-column-menu-dropdown', template: "<!-- Dropdown container with backdrop -->\n<div class=\"dropdown-container\" *ngIf=\"isOpen && context\">\n <!-- Backdrop -->\n <div class=\"dropdown-backdrop\" (click)=\"closed.emit()\"></div>\n \n <!-- Dropdown menu -->\n <div class=\"column-menu-dropdown\" [ngStyle]=\"dropdownStyle\">\n <!-- Main menu with actions -->\n <nile-menu *ngIf=\"!isFilterOpen\">\n <!-- Dynamically render all visible actions -->\n <ng-container *ngFor=\"let action of visibleActions; let i = index; let last = last\">\n <nile-menu-item \n (click)=\"onActionClick(action)\"\n [class.disabled]=\"isActionDisabled(action)\"\n [class.active]=\"isActionActive(action)\">\n <span class=\"checkmark\" *ngIf=\"isActionActive(action)\">\u2713</span>\n <nile-icon slot=\"prefix\" *ngIf=\"action.icon && !isActionActive(action)\" [name]=\"action.icon\"></nile-icon>\n <span class=\"action-label\">{{ action.label }}</span>\n </nile-menu-item>\n \n <!-- Add divider after action groups -->\n <nile-divider *ngIf=\"shouldShowDividerAfter(action, i, last)\"></nile-divider>\n </ng-container>\n \n <!-- Fallback if no actions -->\n <nile-menu-item *ngIf=\"visibleActions.length === 0\">\n No actions available\n </nile-menu-item>\n </nile-menu>\n \n <!-- Filter popup (conditionally rendered) -->\n <st-column-filter\n #filterPopup\n *ngIf=\"isFilterOpen && context\"\n [column]=\"context.column\"\n [tableState]=\"context.tableState\"\n [columnIndex]=\"context.columnIndex\"\n [isFirstColumn]=\"context.isFirstColumn\"\n [isLastColumn]=\"context.isLastColumn\"\n [isOpen]=\"isFilterOpen\"\n (filterApplied)=\"onFilterApplied($event)\"\n (filterCleared)=\"onFilterCleared()\"\n (closed)=\"onFilterClosed()\">\n </st-column-filter>\n </div>\n</div>\n", styles: [".dropdown-container{position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9998}.dropdown-backdrop{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:auto;z-index:9998}.column-menu-dropdown{min-width:200px;max-width:300px;background-color:#fff;border-radius:8px;box-shadow:0 10px 25px #00000026;overflow:hidden;pointer-events:auto;z-index:9999}nile-menu nile-divider::part(divider){margin:0}nile-menu nile-menu-item::part(base){height:2.5rem;min-height:auto}nile-menu nile-menu-item .checkmark{margin-right:8px;color:#4299e1;font-weight:700}\n"] }]
|
|
6807
6821
|
}], propDecorators: { isOpen: [{
|
|
6808
6822
|
type: Input
|
|
6809
6823
|
}], position: [{
|
|
@@ -6986,370 +7000,70 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
6986
7000
|
}] } });
|
|
6987
7001
|
|
|
6988
7002
|
/**
|
|
6989
|
-
*
|
|
6990
|
-
*
|
|
7003
|
+
* st-header Component
|
|
7004
|
+
* Encapsulates column-specific logic including sorting and filtering
|
|
6991
7005
|
*/
|
|
6992
|
-
class
|
|
6993
|
-
constructor(
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
this.
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
this.
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
this.updateForm();
|
|
7031
|
-
}
|
|
7006
|
+
class StHeaderComponent {
|
|
7007
|
+
constructor() {
|
|
7008
|
+
/**
|
|
7009
|
+
* Column index in the visible columns array
|
|
7010
|
+
*/
|
|
7011
|
+
this.columnIndex = 0;
|
|
7012
|
+
/**
|
|
7013
|
+
* Whether this is the first column
|
|
7014
|
+
*/
|
|
7015
|
+
this.isFirstColumn = false;
|
|
7016
|
+
/**
|
|
7017
|
+
* Whether this is the last column
|
|
7018
|
+
*/
|
|
7019
|
+
this.isLastColumn = false;
|
|
7020
|
+
/**
|
|
7021
|
+
* Whether sorting is enabled globally
|
|
7022
|
+
*/
|
|
7023
|
+
this.enableSorting = true;
|
|
7024
|
+
/**
|
|
7025
|
+
* Whether filtering is enabled globally
|
|
7026
|
+
*/
|
|
7027
|
+
this.enableFiltering = true;
|
|
7028
|
+
/**
|
|
7029
|
+
* Emits column sort event when sort is toggled
|
|
7030
|
+
*/
|
|
7031
|
+
this.sortToggle = new EventEmitter();
|
|
7032
|
+
/**
|
|
7033
|
+
* Emits filter changes (future feature)
|
|
7034
|
+
*/
|
|
7035
|
+
this.filterChange = new EventEmitter();
|
|
7036
|
+
/**
|
|
7037
|
+
* Emits when column is moved left or right
|
|
7038
|
+
*/
|
|
7039
|
+
this.columnMoved = new EventEmitter();
|
|
7040
|
+
/**
|
|
7041
|
+
* Emits when column menu button is clicked
|
|
7042
|
+
*/
|
|
7043
|
+
this.menuClick = new EventEmitter();
|
|
7032
7044
|
}
|
|
7033
7045
|
/**
|
|
7034
|
-
*
|
|
7046
|
+
* Cleanup on destroy
|
|
7035
7047
|
*/
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
this.form = this.fb.group({
|
|
7039
|
-
// Basic properties
|
|
7040
|
-
key: [this.column.key, [Validators.required, Validators.pattern(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/)]],
|
|
7041
|
-
header: [this.column.header || ''],
|
|
7042
|
-
dataType: [this.column.dataType || CellDataType.STRING],
|
|
7043
|
-
// Feature flags
|
|
7044
|
-
editable: [this.column.editable !== false],
|
|
7045
|
-
sortable: [this.column.sortable !== false],
|
|
7046
|
-
filterable: [this.column.filterable !== false],
|
|
7047
|
-
resizable: [this.column.resizable !== false],
|
|
7048
|
-
hideable: [this.column.hideable !== false],
|
|
7049
|
-
movable: [this.column.movable !== false],
|
|
7050
|
-
pinnable: [this.column.pinnable !== false],
|
|
7051
|
-
enableMenu: [this.column.enableMenu !== false],
|
|
7052
|
-
// Layout
|
|
7053
|
-
width: [this.column.width || ''],
|
|
7054
|
-
minWidth: [this.column.minWidth || ''],
|
|
7055
|
-
maxWidth: [this.column.maxWidth || ''],
|
|
7056
|
-
sticky: [this.column.sticky || false],
|
|
7057
|
-
alignment: [this.column.alignment || CellAlignment.LEFT],
|
|
7058
|
-
verticalAlignment: [this.column.verticalAlignment || CellVerticalAlignment.MIDDLE],
|
|
7059
|
-
// Edit mode
|
|
7060
|
-
editMode: [this.column.editMode || EditMode.CLICK],
|
|
7061
|
-
// Display
|
|
7062
|
-
visible: [this.column.visible !== false],
|
|
7063
|
-
truncate: [this.column.truncate || false]
|
|
7064
|
-
});
|
|
7065
|
-
// Subscribe to hideable changes to enforce visible=true when hideable=false
|
|
7066
|
-
(_a = this.form.get('hideable')) === null || _a === void 0 ? void 0 : _a.valueChanges.subscribe(hideable => {
|
|
7067
|
-
var _a;
|
|
7068
|
-
if (!hideable) {
|
|
7069
|
-
(_a = this.form.get('visible')) === null || _a === void 0 ? void 0 : _a.setValue(true, { emitEvent: false });
|
|
7070
|
-
}
|
|
7071
|
-
});
|
|
7072
|
-
// Update form when column changes
|
|
7073
|
-
this.updateForm();
|
|
7048
|
+
ngOnDestroy() {
|
|
7049
|
+
// No cleanup needed - resize is now handled by directive
|
|
7074
7050
|
}
|
|
7075
7051
|
/**
|
|
7076
|
-
*
|
|
7052
|
+
* Handle column menu button click
|
|
7077
7053
|
*/
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
this.
|
|
7082
|
-
key: this.column.key,
|
|
7083
|
-
header: this.column.header || '',
|
|
7084
|
-
dataType: this.column.dataType || CellDataType.STRING,
|
|
7085
|
-
editable: this.column.editable !== false,
|
|
7086
|
-
sortable: this.column.sortable !== false,
|
|
7087
|
-
filterable: this.column.filterable !== false,
|
|
7088
|
-
resizable: this.column.resizable !== false,
|
|
7089
|
-
hideable: this.column.hideable !== false,
|
|
7090
|
-
movable: this.column.movable !== false,
|
|
7091
|
-
pinnable: this.column.pinnable !== false,
|
|
7092
|
-
enableMenu: this.column.enableMenu !== false,
|
|
7093
|
-
width: this.column.width || '',
|
|
7094
|
-
minWidth: this.column.minWidth || '',
|
|
7095
|
-
maxWidth: this.column.maxWidth || '',
|
|
7096
|
-
sticky: this.column.sticky || false,
|
|
7097
|
-
alignment: this.column.alignment || CellAlignment.LEFT,
|
|
7098
|
-
verticalAlignment: this.column.verticalAlignment || CellVerticalAlignment.MIDDLE,
|
|
7099
|
-
editMode: this.column.editMode || EditMode.CLICK,
|
|
7100
|
-
visible: this.column.visible !== false,
|
|
7101
|
-
truncate: this.column.truncate || false
|
|
7102
|
-
}, { emitEvent: false });
|
|
7054
|
+
onMenuClick(event) {
|
|
7055
|
+
event.preventDefault();
|
|
7056
|
+
event.stopPropagation();
|
|
7057
|
+
this.menuClick.emit(event);
|
|
7103
7058
|
}
|
|
7104
7059
|
/**
|
|
7105
|
-
*
|
|
7060
|
+
* Check if column menu should be shown
|
|
7106
7061
|
*/
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
const formValue = this.form.value;
|
|
7110
|
-
const updates = {
|
|
7111
|
-
key: formValue.key,
|
|
7112
|
-
header: formValue.header || undefined,
|
|
7113
|
-
dataType: formValue.dataType,
|
|
7114
|
-
editable: formValue.editable,
|
|
7115
|
-
sortable: formValue.sortable,
|
|
7116
|
-
filterable: formValue.filterable,
|
|
7117
|
-
resizable: formValue.resizable,
|
|
7118
|
-
hideable: formValue.hideable,
|
|
7119
|
-
movable: formValue.movable,
|
|
7120
|
-
pinnable: formValue.pinnable,
|
|
7121
|
-
enableMenu: formValue.enableMenu,
|
|
7122
|
-
width: formValue.width || undefined,
|
|
7123
|
-
minWidth: formValue.minWidth || undefined,
|
|
7124
|
-
maxWidth: formValue.maxWidth || undefined,
|
|
7125
|
-
sticky: formValue.sticky || undefined,
|
|
7126
|
-
alignment: formValue.alignment,
|
|
7127
|
-
verticalAlignment: formValue.verticalAlignment,
|
|
7128
|
-
editMode: formValue.editMode,
|
|
7129
|
-
visible: formValue.visible,
|
|
7130
|
-
truncate: formValue.truncate
|
|
7131
|
-
};
|
|
7132
|
-
// Convert empty strings to undefined
|
|
7133
|
-
Object.keys(updates).forEach(key => {
|
|
7134
|
-
const value = updates[key];
|
|
7135
|
-
if (value === '' || value === null) {
|
|
7136
|
-
updates[key] = undefined;
|
|
7137
|
-
}
|
|
7138
|
-
});
|
|
7139
|
-
this.columnUpdated.emit(updates);
|
|
7140
|
-
}
|
|
7141
|
-
else {
|
|
7142
|
-
// Mark all fields as touched to show validation errors
|
|
7143
|
-
Object.keys(this.form.controls).forEach(key => {
|
|
7144
|
-
var _a;
|
|
7145
|
-
(_a = this.form.get(key)) === null || _a === void 0 ? void 0 : _a.markAsTouched();
|
|
7146
|
-
});
|
|
7147
|
-
}
|
|
7062
|
+
isMenuEnabled() {
|
|
7063
|
+
return this.column.enableMenu !== false;
|
|
7148
7064
|
}
|
|
7149
7065
|
/**
|
|
7150
|
-
*
|
|
7151
|
-
*/
|
|
7152
|
-
onCancel() {
|
|
7153
|
-
this.cancel.emit();
|
|
7154
|
-
}
|
|
7155
|
-
/**
|
|
7156
|
-
* Get form control error message
|
|
7157
|
-
*/
|
|
7158
|
-
getErrorMessage(controlName) {
|
|
7159
|
-
const control = this.form.get(controlName);
|
|
7160
|
-
if (control === null || control === void 0 ? void 0 : control.hasError('required')) {
|
|
7161
|
-
return 'This field is required';
|
|
7162
|
-
}
|
|
7163
|
-
if (control === null || control === void 0 ? void 0 : control.hasError('pattern')) {
|
|
7164
|
-
return 'Invalid format';
|
|
7165
|
-
}
|
|
7166
|
-
return '';
|
|
7167
|
-
}
|
|
7168
|
-
/**
|
|
7169
|
-
* Check if form control has error
|
|
7170
|
-
*/
|
|
7171
|
-
hasError(controlName) {
|
|
7172
|
-
const control = this.form.get(controlName);
|
|
7173
|
-
return !!(control && control.invalid && (control.dirty || control.touched));
|
|
7174
|
-
}
|
|
7175
|
-
}
|
|
7176
|
-
ColumnEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ColumnEditorComponent, deps: [{ token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
7177
|
-
ColumnEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ColumnEditorComponent, selector: "st-column-editor", inputs: { column: "column", columnIndex: "columnIndex" }, outputs: { columnUpdated: "columnUpdated", cancel: "cancel" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"column-editor\">\n <div class=\"editor-header\">\n <h3>Column Editor</h3>\n <div class=\"editor-actions\">\n <button class=\"btn btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"btn btn-primary\" (click)=\"onSave()\">Save</button>\n </div>\n </div>\n\n <form [formGroup]=\"form\" class=\"editor-form\">\n <!-- Basic Properties -->\n <div class=\"form-section\">\n <h4>Basic Properties</h4>\n <div class=\"form-group\">\n <label for=\"key\">Key *</label>\n <input\n id=\"key\"\n type=\"text\"\n formControlName=\"key\"\n class=\"form-control\"\n [class.error]=\"hasError('key')\"\n placeholder=\"columnKey\">\n <span class=\"error-message\" *ngIf=\"hasError('key')\">\n {{ getErrorMessage('key') }}\n </span>\n </div>\n\n <div class=\"form-group\">\n <label for=\"header\">Header</label>\n <input\n id=\"header\"\n type=\"text\"\n formControlName=\"header\"\n class=\"form-control\"\n placeholder=\"Column Header\">\n </div>\n\n <div class=\"form-group\">\n <label for=\"dataType\">Data Type</label>\n <select id=\"dataType\" formControlName=\"dataType\" class=\"form-control\">\n <option *ngFor=\"let type of dataTypes\" [value]=\"type.value\">\n {{ type.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Features -->\n <div class=\"form-section\">\n <h4>Features</h4>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"editable\">\n <span>Editable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"sortable\">\n <span>Sortable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"filterable\">\n <span>Filterable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"resizable\">\n <span>Resizable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"hideable\">\n <span>Hideable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"movable\">\n <span>Movable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"pinnable\">\n <span>Pinnable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"enableMenu\">\n <span>Enable Menu</span>\n </label>\n </div>\n </div>\n\n <!-- Layout -->\n <div class=\"form-section\">\n <h4>Layout</h4>\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"width\">Width</label>\n <input\n id=\"width\"\n type=\"text\"\n formControlName=\"width\"\n class=\"form-control\"\n placeholder=\"150 or 'auto'\">\n </div>\n <div class=\"form-group\">\n <label for=\"minWidth\">Min Width</label>\n <input\n id=\"minWidth\"\n type=\"number\"\n formControlName=\"minWidth\"\n class=\"form-control\"\n placeholder=\"50\">\n </div>\n <div class=\"form-group\">\n <label for=\"maxWidth\">Max Width</label>\n <input\n id=\"maxWidth\"\n type=\"number\"\n formControlName=\"maxWidth\"\n class=\"form-control\"\n placeholder=\"500\">\n </div>\n </div>\n\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"sticky\">Sticky</label>\n <select id=\"sticky\" formControlName=\"sticky\" class=\"form-control\">\n <option *ngFor=\"let option of stickyOptions\" [value]=\"option.value\">\n {{ option.label }}\n </option>\n </select>\n </div>\n <div class=\"form-group\">\n <label for=\"alignment\">Alignment</label>\n <select id=\"alignment\" formControlName=\"alignment\" class=\"form-control\">\n <option *ngFor=\"let align of alignments\" [value]=\"align.value\">\n {{ align.label }}\n </option>\n </select>\n </div>\n <div class=\"form-group\">\n <label for=\"verticalAlignment\">Vertical Alignment</label>\n <select id=\"verticalAlignment\" formControlName=\"verticalAlignment\" class=\"form-control\">\n <option *ngFor=\"let align of verticalAlignments\" [value]=\"align.value\">\n {{ align.label }}\n </option>\n </select>\n </div>\n </div>\n </div>\n\n <!-- Edit Mode -->\n <div class=\"form-section\">\n <h4>Edit Mode</h4>\n <div class=\"form-group\">\n <label for=\"editMode\">Edit Trigger</label>\n <select id=\"editMode\" formControlName=\"editMode\" class=\"form-control\">\n <option *ngFor=\"let mode of editModes\" [value]=\"mode.value\">\n {{ mode.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Display -->\n <div class=\"form-section\">\n <h4>Display</h4>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-label\" [class.disabled]=\"!form.get('hideable')?.value\">\n <input type=\"checkbox\" \n formControlName=\"visible\"\n [disabled]=\"!form.get('hideable')?.value\"\n [title]=\"!form.get('hideable')?.value ? 'Column visibility cannot be changed when hideable is disabled' : ''\">\n <span>Visible</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"truncate\">\n <span>Truncate Text</span>\n </label>\n </div>\n </div>\n </form>\n</div>\n\n", styles: [".column-editor{display:flex;flex-direction:column;height:100%}.editor-header{display:flex;justify-content:space-between;align-items:center;padding:1rem;border-bottom:1px solid #e0e0e0;background-color:#f8f8f8}.editor-header h3{margin:0;font-size:1.125rem;font-weight:600;color:#333}.editor-actions{display:flex;gap:.5rem}.btn{padding:.5rem 1rem;border:1px solid #d0d0d0;border-radius:4px;cursor:pointer;font-size:.875rem;transition:all .2s}.btn.btn-primary{background-color:#2196f3;color:#fff;border-color:#2196f3}.btn.btn-primary:hover{background-color:#1976d2;border-color:#1976d2}.btn.btn-secondary{background-color:#fff;color:#333}.btn.btn-secondary:hover{background-color:#f5f5f5}.editor-form{flex:1;overflow-y:auto;padding:1rem}.form-section{margin-bottom:2rem}.form-section h4{margin:0 0 1rem;font-size:.875rem;font-weight:600;color:#666;text-transform:uppercase;letter-spacing:.5px}.form-group{margin-bottom:1rem}.form-group label{display:block;margin-bottom:.5rem;font-size:.875rem;font-weight:500;color:#333}.form-control{width:100%;padding:.5rem;border:1px solid #d0d0d0;border-radius:4px;font-size:.875rem;transition:border-color .2s}.form-control:focus{outline:none;border-color:#2196f3}.form-control.error{border-color:#f44336}.form-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));grid-gap:1rem;gap:1rem}.checkbox-group{display:flex;row-gap:1rem;flex-wrap:wrap;gap:.75rem}.checkbox-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem;color:#333}.checkbox-label input[type=checkbox]{width:18px;height:18px;cursor:pointer}.checkbox-label input[type=checkbox]:disabled{cursor:not-allowed;opacity:.5}.checkbox-label.disabled{opacity:.6;cursor:not-allowed}.checkbox-label.disabled span{color:#999}.error-message{display:block;margin-top:.25rem;font-size:.75rem;color:#f44336}\n"], directives: [{ type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }] });
|
|
7178
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ColumnEditorComponent, decorators: [{
|
|
7179
|
-
type: Component,
|
|
7180
|
-
args: [{ selector: 'st-column-editor', template: "<div class=\"column-editor\">\n <div class=\"editor-header\">\n <h3>Column Editor</h3>\n <div class=\"editor-actions\">\n <button class=\"btn btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"btn btn-primary\" (click)=\"onSave()\">Save</button>\n </div>\n </div>\n\n <form [formGroup]=\"form\" class=\"editor-form\">\n <!-- Basic Properties -->\n <div class=\"form-section\">\n <h4>Basic Properties</h4>\n <div class=\"form-group\">\n <label for=\"key\">Key *</label>\n <input\n id=\"key\"\n type=\"text\"\n formControlName=\"key\"\n class=\"form-control\"\n [class.error]=\"hasError('key')\"\n placeholder=\"columnKey\">\n <span class=\"error-message\" *ngIf=\"hasError('key')\">\n {{ getErrorMessage('key') }}\n </span>\n </div>\n\n <div class=\"form-group\">\n <label for=\"header\">Header</label>\n <input\n id=\"header\"\n type=\"text\"\n formControlName=\"header\"\n class=\"form-control\"\n placeholder=\"Column Header\">\n </div>\n\n <div class=\"form-group\">\n <label for=\"dataType\">Data Type</label>\n <select id=\"dataType\" formControlName=\"dataType\" class=\"form-control\">\n <option *ngFor=\"let type of dataTypes\" [value]=\"type.value\">\n {{ type.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Features -->\n <div class=\"form-section\">\n <h4>Features</h4>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"editable\">\n <span>Editable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"sortable\">\n <span>Sortable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"filterable\">\n <span>Filterable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"resizable\">\n <span>Resizable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"hideable\">\n <span>Hideable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"movable\">\n <span>Movable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"pinnable\">\n <span>Pinnable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"enableMenu\">\n <span>Enable Menu</span>\n </label>\n </div>\n </div>\n\n <!-- Layout -->\n <div class=\"form-section\">\n <h4>Layout</h4>\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"width\">Width</label>\n <input\n id=\"width\"\n type=\"text\"\n formControlName=\"width\"\n class=\"form-control\"\n placeholder=\"150 or 'auto'\">\n </div>\n <div class=\"form-group\">\n <label for=\"minWidth\">Min Width</label>\n <input\n id=\"minWidth\"\n type=\"number\"\n formControlName=\"minWidth\"\n class=\"form-control\"\n placeholder=\"50\">\n </div>\n <div class=\"form-group\">\n <label for=\"maxWidth\">Max Width</label>\n <input\n id=\"maxWidth\"\n type=\"number\"\n formControlName=\"maxWidth\"\n class=\"form-control\"\n placeholder=\"500\">\n </div>\n </div>\n\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"sticky\">Sticky</label>\n <select id=\"sticky\" formControlName=\"sticky\" class=\"form-control\">\n <option *ngFor=\"let option of stickyOptions\" [value]=\"option.value\">\n {{ option.label }}\n </option>\n </select>\n </div>\n <div class=\"form-group\">\n <label for=\"alignment\">Alignment</label>\n <select id=\"alignment\" formControlName=\"alignment\" class=\"form-control\">\n <option *ngFor=\"let align of alignments\" [value]=\"align.value\">\n {{ align.label }}\n </option>\n </select>\n </div>\n <div class=\"form-group\">\n <label for=\"verticalAlignment\">Vertical Alignment</label>\n <select id=\"verticalAlignment\" formControlName=\"verticalAlignment\" class=\"form-control\">\n <option *ngFor=\"let align of verticalAlignments\" [value]=\"align.value\">\n {{ align.label }}\n </option>\n </select>\n </div>\n </div>\n </div>\n\n <!-- Edit Mode -->\n <div class=\"form-section\">\n <h4>Edit Mode</h4>\n <div class=\"form-group\">\n <label for=\"editMode\">Edit Trigger</label>\n <select id=\"editMode\" formControlName=\"editMode\" class=\"form-control\">\n <option *ngFor=\"let mode of editModes\" [value]=\"mode.value\">\n {{ mode.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Display -->\n <div class=\"form-section\">\n <h4>Display</h4>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-label\" [class.disabled]=\"!form.get('hideable')?.value\">\n <input type=\"checkbox\" \n formControlName=\"visible\"\n [disabled]=\"!form.get('hideable')?.value\"\n [title]=\"!form.get('hideable')?.value ? 'Column visibility cannot be changed when hideable is disabled' : ''\">\n <span>Visible</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"truncate\">\n <span>Truncate Text</span>\n </label>\n </div>\n </div>\n </form>\n</div>\n\n", styles: [".column-editor{display:flex;flex-direction:column;height:100%}.editor-header{display:flex;justify-content:space-between;align-items:center;padding:1rem;border-bottom:1px solid #e0e0e0;background-color:#f8f8f8}.editor-header h3{margin:0;font-size:1.125rem;font-weight:600;color:#333}.editor-actions{display:flex;gap:.5rem}.btn{padding:.5rem 1rem;border:1px solid #d0d0d0;border-radius:4px;cursor:pointer;font-size:.875rem;transition:all .2s}.btn.btn-primary{background-color:#2196f3;color:#fff;border-color:#2196f3}.btn.btn-primary:hover{background-color:#1976d2;border-color:#1976d2}.btn.btn-secondary{background-color:#fff;color:#333}.btn.btn-secondary:hover{background-color:#f5f5f5}.editor-form{flex:1;overflow-y:auto;padding:1rem}.form-section{margin-bottom:2rem}.form-section h4{margin:0 0 1rem;font-size:.875rem;font-weight:600;color:#666;text-transform:uppercase;letter-spacing:.5px}.form-group{margin-bottom:1rem}.form-group label{display:block;margin-bottom:.5rem;font-size:.875rem;font-weight:500;color:#333}.form-control{width:100%;padding:.5rem;border:1px solid #d0d0d0;border-radius:4px;font-size:.875rem;transition:border-color .2s}.form-control:focus{outline:none;border-color:#2196f3}.form-control.error{border-color:#f44336}.form-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));grid-gap:1rem;gap:1rem}.checkbox-group{display:flex;row-gap:1rem;flex-wrap:wrap;gap:.75rem}.checkbox-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem;color:#333}.checkbox-label input[type=checkbox]{width:18px;height:18px;cursor:pointer}.checkbox-label input[type=checkbox]:disabled{cursor:not-allowed;opacity:.5}.checkbox-label.disabled{opacity:.6;cursor:not-allowed}.checkbox-label.disabled span{color:#999}.error-message{display:block;margin-top:.25rem;font-size:.75rem;color:#f44336}\n"] }]
|
|
7181
|
-
}], ctorParameters: function () { return [{ type: i1$1.FormBuilder }]; }, propDecorators: { column: [{
|
|
7182
|
-
type: Input
|
|
7183
|
-
}], columnIndex: [{
|
|
7184
|
-
type: Input
|
|
7185
|
-
}], columnUpdated: [{
|
|
7186
|
-
type: Output
|
|
7187
|
-
}], cancel: [{
|
|
7188
|
-
type: Output
|
|
7189
|
-
}] } });
|
|
7190
|
-
|
|
7191
|
-
class StColumnEditorModalComponent {
|
|
7192
|
-
constructor() {
|
|
7193
|
-
this.columnCreated = new EventEmitter();
|
|
7194
|
-
this.cancelled = new EventEmitter();
|
|
7195
|
-
this.columnIndex = -1;
|
|
7196
|
-
}
|
|
7197
|
-
ngOnInit() {
|
|
7198
|
-
// Create a default column that will be edited
|
|
7199
|
-
this.newColumn = this.createDefaultColumn();
|
|
7200
|
-
}
|
|
7201
|
-
ngOnDestroy() {
|
|
7202
|
-
// Cleanup if needed
|
|
7203
|
-
}
|
|
7204
|
-
/**
|
|
7205
|
-
* Create a default column configuration
|
|
7206
|
-
*/
|
|
7207
|
-
createDefaultColumn() {
|
|
7208
|
-
return ColumnConfigFactory.text('newColumn', {
|
|
7209
|
-
header: 'New Column',
|
|
7210
|
-
editable: true,
|
|
7211
|
-
sortable: true,
|
|
7212
|
-
filterable: true,
|
|
7213
|
-
resizable: true,
|
|
7214
|
-
hideable: true,
|
|
7215
|
-
visible: true
|
|
7216
|
-
});
|
|
7217
|
-
}
|
|
7218
|
-
/**
|
|
7219
|
-
* Trigger save from external button
|
|
7220
|
-
*/
|
|
7221
|
-
onSave() {
|
|
7222
|
-
// Call the column editor's save method
|
|
7223
|
-
if (this.columnEditor) {
|
|
7224
|
-
this.columnEditor.onSave();
|
|
7225
|
-
}
|
|
7226
|
-
}
|
|
7227
|
-
/**
|
|
7228
|
-
* Handle column updates from the editor
|
|
7229
|
-
*/
|
|
7230
|
-
onColumnUpdated(updates) {
|
|
7231
|
-
// Merge updates into the new column
|
|
7232
|
-
this.newColumn = Object.assign(Object.assign({}, this.newColumn), updates);
|
|
7233
|
-
// Use ColumnConfigFactory to create proper column based on data type
|
|
7234
|
-
let finalColumn;
|
|
7235
|
-
const key = updates.key || this.newColumn.key;
|
|
7236
|
-
const dataType = updates.dataType || this.newColumn.dataType;
|
|
7237
|
-
switch (dataType) {
|
|
7238
|
-
case CellDataType.NUMBER:
|
|
7239
|
-
finalColumn = ColumnConfigFactory.number(key, this.newColumn);
|
|
7240
|
-
break;
|
|
7241
|
-
case CellDataType.DATE:
|
|
7242
|
-
finalColumn = ColumnConfigFactory.date(key, this.newColumn);
|
|
7243
|
-
break;
|
|
7244
|
-
case CellDataType.BOOLEAN:
|
|
7245
|
-
finalColumn = ColumnConfigFactory.boolean(key, this.newColumn);
|
|
7246
|
-
break;
|
|
7247
|
-
default:
|
|
7248
|
-
finalColumn = ColumnConfigFactory.text(key, this.newColumn);
|
|
7249
|
-
}
|
|
7250
|
-
// Emit the created column
|
|
7251
|
-
this.columnCreated.emit(finalColumn);
|
|
7252
|
-
}
|
|
7253
|
-
/**
|
|
7254
|
-
* Handle cancel from the editor
|
|
7255
|
-
*/
|
|
7256
|
-
onCancel() {
|
|
7257
|
-
this.cancelled.emit();
|
|
7258
|
-
}
|
|
7259
|
-
/**
|
|
7260
|
-
* Handle backdrop click to close modal
|
|
7261
|
-
*/
|
|
7262
|
-
onBackdropClick(event) {
|
|
7263
|
-
if (event.target === event.currentTarget) {
|
|
7264
|
-
this.cancelled.emit();
|
|
7265
|
-
}
|
|
7266
|
-
}
|
|
7267
|
-
/**
|
|
7268
|
-
* Prevent event propagation from modal content
|
|
7269
|
-
*/
|
|
7270
|
-
onModalContentClick(event) {
|
|
7271
|
-
event.stopPropagation();
|
|
7272
|
-
}
|
|
7273
|
-
}
|
|
7274
|
-
StColumnEditorModalComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StColumnEditorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7275
|
-
StColumnEditorModalComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StColumnEditorModalComponent, selector: "st-column-editor-modal", outputs: { columnCreated: "columnCreated", cancelled: "cancelled" }, viewQueries: [{ propertyName: "columnEditor", first: true, predicate: ColumnEditorComponent, descendants: true }], ngImport: i0, template: "<div class=\"modal-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"modal-content\" (click)=\"onModalContentClick($event)\">\n <div class=\"modal-header\">\n <h2>Add New Column</h2>\n <button class=\"close-button\" (click)=\"onCancel()\" type=\"button\" aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n <div class=\"modal-body\">\n <!-- Now using the shared st-column-editor component from SharedTableComponentsModule -->\n <st-column-editor\n [column]=\"newColumn\"\n [columnIndex]=\"columnIndex\"\n (columnUpdated)=\"onColumnUpdated($event)\"\n (cancel)=\"onCancel()\">\n </st-column-editor>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"onSave()\">Add Column</button>\n </div>\n </div>\n</div>\n", styles: [".modal-backdrop{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:2000;animation:fadeIn .2s ease-in-out}.modal-content{background:white;border-radius:8px;box-shadow:0 11px 15px -7px #0003,0 24px 38px 3px #00000024,0 9px 46px 8px #0000001f;max-width:600px;max-height:90vh;width:90%;display:flex;flex-direction:column;animation:slideUp .3s cubic-bezier(.4,0,.2,1)}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;border-bottom:1px solid #e0e0e0;flex-shrink:0}.modal-header h2{margin:0;font-size:20px;font-weight:500;color:#212121}.close-button{background:none;border:none;cursor:pointer;padding:8px;display:flex;align-items:center;justify-content:center;border-radius:50%;color:#757575;transition:all .2s ease}.close-button:hover{background-color:#0000000a;color:#212121}.close-button:active{background-color:#00000014}.close-button:focus{outline:none;box-shadow:0 0 0 2px #1976d24d}.close-button svg{width:24px;height:24px}.modal-body{padding:0;overflow-y:auto;flex:1;min-height:0}.modal-body ::ng-deep st-column-editor{display:block}.modal-body ::ng-deep st-column-editor .column-editor{padding:0;border:none;box-shadow:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-header{display:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-actions{display:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-form{padding:24px}.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #e0e0e0;flex-shrink:0;background-color:#f5f5f5}.modal-footer .btn{padding:10px 20px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.modal-footer .btn:focus{outline:none;box-shadow:0 0 0 2px #0000001a}.modal-footer .btn.btn-secondary{background-color:#fff;color:#424242;border:1px solid #d0d0d0}.modal-footer .btn.btn-secondary:hover{background-color:#f5f5f5}.modal-footer .btn.btn-secondary:active{background-color:#eee}.modal-footer .btn.btn-primary{background-color:#1976d2;color:#fff}.modal-footer .btn.btn-primary:hover{background-color:#1565c0}.modal-footer .btn.btn-primary:active{background-color:#0d47a1}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(50px)}to{opacity:1;transform:translateY(0)}}\n"], components: [{ type: ColumnEditorComponent, selector: "st-column-editor", inputs: ["column", "columnIndex"], outputs: ["columnUpdated", "cancel"] }] });
|
|
7276
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StColumnEditorModalComponent, decorators: [{
|
|
7277
|
-
type: Component,
|
|
7278
|
-
args: [{ selector: 'st-column-editor-modal', template: "<div class=\"modal-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"modal-content\" (click)=\"onModalContentClick($event)\">\n <div class=\"modal-header\">\n <h2>Add New Column</h2>\n <button class=\"close-button\" (click)=\"onCancel()\" type=\"button\" aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n <div class=\"modal-body\">\n <!-- Now using the shared st-column-editor component from SharedTableComponentsModule -->\n <st-column-editor\n [column]=\"newColumn\"\n [columnIndex]=\"columnIndex\"\n (columnUpdated)=\"onColumnUpdated($event)\"\n (cancel)=\"onCancel()\">\n </st-column-editor>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"onSave()\">Add Column</button>\n </div>\n </div>\n</div>\n", styles: [".modal-backdrop{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:2000;animation:fadeIn .2s ease-in-out}.modal-content{background:white;border-radius:8px;box-shadow:0 11px 15px -7px #0003,0 24px 38px 3px #00000024,0 9px 46px 8px #0000001f;max-width:600px;max-height:90vh;width:90%;display:flex;flex-direction:column;animation:slideUp .3s cubic-bezier(.4,0,.2,1)}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;border-bottom:1px solid #e0e0e0;flex-shrink:0}.modal-header h2{margin:0;font-size:20px;font-weight:500;color:#212121}.close-button{background:none;border:none;cursor:pointer;padding:8px;display:flex;align-items:center;justify-content:center;border-radius:50%;color:#757575;transition:all .2s ease}.close-button:hover{background-color:#0000000a;color:#212121}.close-button:active{background-color:#00000014}.close-button:focus{outline:none;box-shadow:0 0 0 2px #1976d24d}.close-button svg{width:24px;height:24px}.modal-body{padding:0;overflow-y:auto;flex:1;min-height:0}.modal-body ::ng-deep st-column-editor{display:block}.modal-body ::ng-deep st-column-editor .column-editor{padding:0;border:none;box-shadow:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-header{display:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-actions{display:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-form{padding:24px}.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #e0e0e0;flex-shrink:0;background-color:#f5f5f5}.modal-footer .btn{padding:10px 20px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.modal-footer .btn:focus{outline:none;box-shadow:0 0 0 2px #0000001a}.modal-footer .btn.btn-secondary{background-color:#fff;color:#424242;border:1px solid #d0d0d0}.modal-footer .btn.btn-secondary:hover{background-color:#f5f5f5}.modal-footer .btn.btn-secondary:active{background-color:#eee}.modal-footer .btn.btn-primary{background-color:#1976d2;color:#fff}.modal-footer .btn.btn-primary:hover{background-color:#1565c0}.modal-footer .btn.btn-primary:active{background-color:#0d47a1}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(50px)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
7279
|
-
}], propDecorators: { columnCreated: [{
|
|
7280
|
-
type: Output
|
|
7281
|
-
}], cancelled: [{
|
|
7282
|
-
type: Output
|
|
7283
|
-
}], columnEditor: [{
|
|
7284
|
-
type: ViewChild,
|
|
7285
|
-
args: [ColumnEditorComponent]
|
|
7286
|
-
}] } });
|
|
7287
|
-
|
|
7288
|
-
/**
|
|
7289
|
-
* st-header Component
|
|
7290
|
-
* Encapsulates column-specific logic including sorting and filtering
|
|
7291
|
-
*/
|
|
7292
|
-
class StHeaderComponent {
|
|
7293
|
-
constructor() {
|
|
7294
|
-
/**
|
|
7295
|
-
* Column index in the visible columns array
|
|
7296
|
-
*/
|
|
7297
|
-
this.columnIndex = 0;
|
|
7298
|
-
/**
|
|
7299
|
-
* Whether this is the first column
|
|
7300
|
-
*/
|
|
7301
|
-
this.isFirstColumn = false;
|
|
7302
|
-
/**
|
|
7303
|
-
* Whether this is the last column
|
|
7304
|
-
*/
|
|
7305
|
-
this.isLastColumn = false;
|
|
7306
|
-
/**
|
|
7307
|
-
* Whether sorting is enabled globally
|
|
7308
|
-
*/
|
|
7309
|
-
this.enableSorting = true;
|
|
7310
|
-
/**
|
|
7311
|
-
* Whether filtering is enabled globally
|
|
7312
|
-
*/
|
|
7313
|
-
this.enableFiltering = true;
|
|
7314
|
-
/**
|
|
7315
|
-
* Emits column sort event when sort is toggled
|
|
7316
|
-
*/
|
|
7317
|
-
this.sortToggle = new EventEmitter();
|
|
7318
|
-
/**
|
|
7319
|
-
* Emits filter changes (future feature)
|
|
7320
|
-
*/
|
|
7321
|
-
this.filterChange = new EventEmitter();
|
|
7322
|
-
/**
|
|
7323
|
-
* Emits when column is moved left or right
|
|
7324
|
-
*/
|
|
7325
|
-
this.columnMoved = new EventEmitter();
|
|
7326
|
-
/**
|
|
7327
|
-
* Emits when column menu button is clicked
|
|
7328
|
-
*/
|
|
7329
|
-
this.menuClick = new EventEmitter();
|
|
7330
|
-
}
|
|
7331
|
-
/**
|
|
7332
|
-
* Cleanup on destroy
|
|
7333
|
-
*/
|
|
7334
|
-
ngOnDestroy() {
|
|
7335
|
-
// No cleanup needed - resize is now handled by directive
|
|
7336
|
-
}
|
|
7337
|
-
/**
|
|
7338
|
-
* Handle column menu button click
|
|
7339
|
-
*/
|
|
7340
|
-
onMenuClick(event) {
|
|
7341
|
-
event.preventDefault();
|
|
7342
|
-
event.stopPropagation();
|
|
7343
|
-
this.menuClick.emit(event);
|
|
7344
|
-
}
|
|
7345
|
-
/**
|
|
7346
|
-
* Check if column menu should be shown
|
|
7347
|
-
*/
|
|
7348
|
-
isMenuEnabled() {
|
|
7349
|
-
return this.column.enableMenu !== false;
|
|
7350
|
-
}
|
|
7351
|
-
/**
|
|
7352
|
-
* Check if column is sortable
|
|
7066
|
+
* Check if column is sortable
|
|
7353
7067
|
*/
|
|
7354
7068
|
isSortable() {
|
|
7355
7069
|
return this.column.sortable !== false && this.enableSorting;
|
|
@@ -7512,25 +7226,22 @@ class StTableActionsComponent {
|
|
|
7512
7226
|
updateDropdownPosition(event) {
|
|
7513
7227
|
const button = event.currentTarget;
|
|
7514
7228
|
const rect = button.getBoundingClientRect();
|
|
7515
|
-
const
|
|
7516
|
-
|
|
7517
|
-
const dropdownWidth = 280;
|
|
7518
|
-
const dropdownHeight = 400;
|
|
7519
|
-
let x = rect.left;
|
|
7229
|
+
const dropdownWidth = 220;
|
|
7230
|
+
let x = rect.right;
|
|
7520
7231
|
let y = rect.bottom + 5;
|
|
7521
|
-
// Adjust horizontal position if dropdown would overflow
|
|
7522
|
-
if (x + dropdownWidth > viewportWidth) {
|
|
7523
|
-
|
|
7524
|
-
}
|
|
7525
|
-
// Adjust vertical position if dropdown would overflow
|
|
7526
|
-
if (y + dropdownHeight > viewportHeight) {
|
|
7527
|
-
|
|
7528
|
-
}
|
|
7232
|
+
// // Adjust horizontal position if dropdown would overflow
|
|
7233
|
+
// if (x + dropdownWidth > viewportWidth) {
|
|
7234
|
+
// x = Math.max(10, viewportWidth - dropdownWidth - 10);
|
|
7235
|
+
// }
|
|
7236
|
+
// // Adjust vertical position if dropdown would overflow
|
|
7237
|
+
// if (y + dropdownHeight > viewportHeight) {
|
|
7238
|
+
// y = rect.top - dropdownHeight - 5;
|
|
7239
|
+
// }
|
|
7529
7240
|
this.dropdownStyle = {
|
|
7530
|
-
position: '
|
|
7531
|
-
left: `${x}px`,
|
|
7241
|
+
position: 'absolute',
|
|
7242
|
+
left: `${x - dropdownWidth}px`,
|
|
7532
7243
|
top: `${y}px`,
|
|
7533
|
-
'z-index':
|
|
7244
|
+
'z-index': TableZIndex.TABLE_ACTIONS_DROPDOWN
|
|
7534
7245
|
};
|
|
7535
7246
|
}
|
|
7536
7247
|
/**
|
|
@@ -7900,7 +7611,7 @@ class StTableComponent {
|
|
|
7900
7611
|
}
|
|
7901
7612
|
}
|
|
7902
7613
|
ngOnChanges(changes) {
|
|
7903
|
-
var _a;
|
|
7614
|
+
var _a, _b;
|
|
7904
7615
|
// Validate configuration when tableConfig changes
|
|
7905
7616
|
if (changes['tableConfig'] && !changes['tableConfig'].firstChange && this.tableConfig) {
|
|
7906
7617
|
this.mergedConfig = mergeTableConfig(this.tableConfig);
|
|
@@ -7935,8 +7646,17 @@ class StTableComponent {
|
|
|
7935
7646
|
// Update visible columns and cell grid
|
|
7936
7647
|
this.updateVisibleData();
|
|
7937
7648
|
}
|
|
7649
|
+
// Handle tableState input changes (when external state is provided, e.g., in workbook)
|
|
7650
|
+
if (changes['tableState'] && !changes['tableState'].firstChange && this.tableState) {
|
|
7651
|
+
// Unsubscribe from old tableState's focus observable to prevent memory leaks
|
|
7652
|
+
(_a = this.focusSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
7653
|
+
// Reinitialize keyboard navigation with new tableState
|
|
7654
|
+
if (this.isKeyboardNavigationEnabled()) {
|
|
7655
|
+
this.initializeKeyboardNavigation();
|
|
7656
|
+
}
|
|
7657
|
+
}
|
|
7938
7658
|
// Recalculate virtual scroll when data changes
|
|
7939
|
-
if ((changes['data'] || changes['cellGrid']) && !((
|
|
7659
|
+
if ((changes['data'] || changes['cellGrid']) && !((_b = changes['data']) === null || _b === void 0 ? void 0 : _b.firstChange)) {
|
|
7940
7660
|
if (this.isVirtualScrollEnabled()) {
|
|
7941
7661
|
const currentState = this.virtualScrollState$.value;
|
|
7942
7662
|
if (currentState) {
|
|
@@ -8976,10 +8696,10 @@ class StTableComponent {
|
|
|
8976
8696
|
}
|
|
8977
8697
|
}
|
|
8978
8698
|
StTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StTableComponent, deps: [{ token: JsonSchemaValidatorService }, { token: ValidationLoggerService }, { token: VirtualScrollService }], target: i0.ɵɵFactoryTarget.Component });
|
|
8979
|
-
StTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StTableComponent, selector: "st-table", inputs: { tableConfig: "tableConfig", data: "data", data$: "data$", tableState: "tableState", enableSorting: "enableSorting", enableFiltering: "enableFiltering", validateConfig: "validateConfig" }, outputs: { stateChange: "stateChange", dataChange: "dataChange", cellEdit: "cellEdit", cellSave: "cellSave", cellCancel: "cellCancel", cellChange: "cellChange", columnResized: "columnResized", columnMoved: "columnMoved", configValidationErrors: "configValidationErrors", columnAdded: "columnAdded", rowAction: "rowAction", validationStateChange: "validationStateChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "scrollViewport", first: true, predicate: ["scrollViewport"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<!-- Top pagination controls -->\n<st-pagination \n *ngIf=\"showTopPagination() && !(mergedConfig.tableSkeleton?.enabled | async)\" \n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n position=\"top\">\n</st-pagination>\n\n<div class=\"st-table\" *ngIf=\"!(mergedConfig.tableSkeleton?.enabled | async)\" \n [ngClass]=\"{\n 'virtual-scroll-enabled': isVirtualScrollEnabled(),\n 'keyboard-navigation-enabled': isKeyboardNavigationEnabled()\n }\"\n [ngStyle]=\"{\n 'max-height.px': !isVirtualScrollEnabled() ? mergedConfig.display?.maxHeight : null\n }\"\n stKeyboardNavigation\n [tableState]=\"getActiveTableState()\" \n [attr.tabindex]=\"isKeyboardNavigationEnabled() ? 0 : -1\"\n (focus)=\"onTableContainerFocus($event)\"\n [attr.title]=\"isKeyboardNavigationEnabled() ? 'Click a cell or press Tab to start keyboard navigation' : null\">\n <!-- Unified Table Actions Menu -->\n\n <!-- Virtual scroll viewport wrapper -->\n <div class=\"st-scroll-viewport\" #scrollViewport *ngIf=\"isVirtualScrollEnabled()\"\n [ngStyle]=\"{ 'height.px': getVirtualScrollViewportHeight() }\">\n\n <!-- Spacer to create scrollable area -->\n <div class=\"st-scroll-spacer\" [ngStyle]=\"{ 'height.px': virtualScrollTotalHeight$ | async }\">\n </div>\n\n <!-- Table positioner with transform (instead of tbody) -->\n <div class=\"st-table-positioner\" [ngStyle]=\"{ transform: 'translateY(' + (virtualScrollOffsetY$ | async) + 'px)' }\">\n <!-- Table with only visible rows -->\n <ng-container *ngTemplateOutlet=\"tableTemplate; context: { \n mode: 'virtual',\n theadStyle: { top: (virtualScrollOffsetYNeg$ | async) + 'px' }\n }\"></ng-container>\n </div>\n </div>\n \n <!-- Standard table (when virtual scroll disabled) -->\n <ng-container *ngIf=\"!isVirtualScrollEnabled()\">\n <ng-container *ngTemplateOutlet=\"tableTemplate; context: { \n mode: 'standard',\n theadStyle: null\n }\"></ng-container>\n </ng-container>\n\n <!-- Shared Column Menu Dropdown -->\n <st-column-menu-dropdown \n [isOpen]=\"columnMenuState.isOpen\"\n [position]=\"columnMenuState.position\"\n [context]=\"columnMenuState.context\"\n (actionClicked)=\"onColumnActionClicked($event)\"\n (closed)=\"closeColumnMenu()\">\n </st-column-menu-dropdown>\n</div>\n\n<ng-container *ngIf=\"(mergedConfig.tableSkeleton?.enabled | async)\">\n <ng-container *ngTemplateOutlet=\"skeletonLoader\"></ng-container>\n</ng-container>\n\n<!-- Shared Row Actions Dropdown -->\n<st-row-actions-dropdown [isOpen]=\"dropdownState.isOpen\" [position]=\"dropdownState.position\"\n [context]=\"dropdownState.context\" (actionClicked)=\"onRowActionClicked($event)\" (closed)=\"closeRowActionsDropdown()\">\n</st-row-actions-dropdown>\n\n\n<!-- Bottom pagination controls -->\n<st-pagination \n *ngIf=\"showBottomPagination() && !(mergedConfig.tableSkeleton?.enabled | async)\" \n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n position=\"bottom\">\n</st-pagination>\n\n<!-- Add Column Modal -->\n<st-column-editor-modal *ngIf=\"showColumnModal\" (columnCreated)=\"onColumnCreated($event)\"\n (cancelled)=\"onModalCancelled()\">\n</st-column-editor-modal>\n\n <!-- ========================================== -->\n <!-- REUSABLE TABLE TEMPLATE -->\n <!-- ========================================== -->\n <ng-template #tableTemplate let-mode=\"mode\" let-theadStyle=\"theadStyle\">\n <table class=\"st-table-element\">\n <!-- TABLE HEADER -->\n <thead [ngClass]=\"{ 'sticky': mergedConfig.display?.stickyHeader }\" [ngStyle]=\"theadStyle\">\n <tr>\n <!-- Row Number Header -->\n <th *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-header header-cell sticky-left\"\n [ngStyle]=\"{\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_HEADER_CELL,\n 'width.px': 30\n }\">\n #\n </th>\n <!-- Column Headers -->\n <th \n *ngFor=\"let column of visibleColumns; let colIndex = index; let isFirst = first; let isLast = last\"\n [ngClass]=\"{\n 'header-cell': mode === 'standard',\n 'sticky-left': column.sticky === 'left',\n 'sticky-right': column.sticky === 'right',\n 'sticky-right-first': column.sticky === 'right' && isFirstStickyRight(column.key),\n 'resizable': column.resizable !== false\n }\"\n [ngStyle]=\"{\n position: column.sticky ? 'sticky' : null,\n 'left.px': column.sticky === 'left' ? (column.stickyOffset || 0) : null,\n 'right.px': column.sticky === 'right' ? (column.stickyOffset || 0) : null,\n 'z-index': column.sticky ? ZIndex.STICKY_HEADER_CELL : null,\n 'width.px': column.width\n }\">\n \n <st-header \n [column]=\"column\"\n [columnIndex]=\"colIndex\"\n [isFirstColumn]=\"isFirst\"\n [isLastColumn]=\"isLast\"\n [tableState]=\"getActiveTableState()\"\n [enableSorting]=\"mergedConfig.sorting?.enabled ?? enableSorting\"\n [enableFiltering]=\"mergedConfig.filtering?.enabled ?? enableFiltering\"\n (columnMoved)=\"onColumnMoved($event)\"\n (menuClick)=\"openColumnMenu($event, column, colIndex, isFirst, isLast)\">\n </st-header>\n\n <div \n class=\"resize-handle\" \n stColumnResize\n [column]=\"column\"\n (columnResized)=\"onColumnResized($event)\"\n *ngIf=\"column.resizable !== false\">\n </div>\n </th>\n \n <!-- Settings Column Header -->\n <th \n class=\"settings-column sticky-right\"\n [ngClass]=\"{ 'header-cell': mode === 'standard' }\"\n [ngStyle]=\"{ 'z-index': ZIndex.STICKY_HEADER_CELL }\">\n <div [ngClass]=\"{ 'flex-center': mode === 'virtual', 'header-content': mode === 'standard' }\">\n <st-table-actions \n [tableState]=\"getActiveTableState()\"\n [allowAddColumn]=\"mergedConfig.features?.columnManagement?.allowAdd || false\"\n (addColumnClicked)=\"onAddColumnClick()\">\n </st-table-actions>\n </div>\n </th>\n </tr>\n </thead>\n\n <!-- TABLE BODY -->\n <tbody>\n <!-- Virtual Scroll Rows -->\n <ng-container *ngIf=\"mode === 'virtual'\">\n <tr *ngFor=\"let row of visibleRows$ | async; let relativeIndex = index; trackBy: trackByRowIndex\"\n [attr.data-row-index]=\"getAbsoluteRowIndex(relativeIndex)\">\n <!-- Row Number Cell -->\n <td *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-cell\" \n [ngClass]=\"{ 'sticky-left': 'left' }\"\n [ngStyle]=\"{\n 'width.px': 30,\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_BODY_CELL,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\">\n {{getAbsoluteRowIndex(relativeIndex) + 1}}\n </td>\n <ng-container *ngTemplateOutlet=\"bodyCellTemplate; context: { \n row: row,\n rowIndex: getAbsoluteRowIndex(relativeIndex),\n mode: 'virtual',\n relativeIndex: relativeIndex\n }\"></ng-container>\n </tr>\n </ng-container>\n\n <!-- Standard Rows -->\n <ng-container *ngIf=\"mode === 'standard'\">\n <tr *ngFor=\"let row of visibleCellGrid; let rowIndex = index\" [attr.data-row-index]=\"rowIndex\">\n <!-- Row Number Cell -->\n <td *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-cell\" \n [ngClass]=\"{ 'sticky-left': 'left' }\"\n [ngStyle]=\"{\n 'width.px': 30,\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_BODY_CELL,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\">\n {{rowIndex + 1}}\n </td>\n <ng-container *ngTemplateOutlet=\"bodyCellTemplate; context: { \n row: row,\n rowIndex: rowIndex,\n mode: 'standard'\n }\"></ng-container>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </ng-template>\n\n <!-- ========================================== -->\n <!-- REUSABLE BODY CELL TEMPLATE -->\n <!-- ========================================== -->\n <ng-template #bodyCellTemplate let-row=\"row\" let-rowIndex=\"rowIndex\" let-mode=\"mode\" let-relativeIndex=\"relativeIndex\">\n <!-- Data Cells -->\n <td \n *ngFor=\"let cell of row; let colIndex = index\"\n [ngClass]=\"{\n 'sticky-left': visibleColumns[colIndex]?.sticky === 'left',\n 'sticky-right': visibleColumns[colIndex]?.sticky === 'right',\n 'sticky-right-first': visibleColumns[colIndex]?.sticky === 'right' && visibleColumns[colIndex]?.key && isFirstStickyRight(visibleColumns[colIndex].key),\n 'align-center': visibleColumns[colIndex]?.alignment === 'center',\n 'align-right': visibleColumns[colIndex]?.alignment === 'right',\n 'cell-focused': cell.isFocused()\n }\"\n [ngStyle]=\"{\n position: visibleColumns[colIndex]?.sticky ? 'sticky' : null,\n 'left.px': visibleColumns[colIndex]?.sticky === 'left' ? (visibleColumns[colIndex]?.stickyOffset || 0) : null,\n 'right.px': visibleColumns[colIndex]?.sticky === 'right' ? (visibleColumns[colIndex]?.stickyOffset || 0) : null,\n 'z-index': visibleColumns[colIndex]?.sticky ? ZIndex.STICKY_BODY_CELL : null,\n 'width.px': visibleColumns[colIndex]?.width,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\"\n (click)=\"isKeyboardNavigationEnabled() ? onCellClick(rowIndex, colIndex) : null\">\n \n <!-- Virtual Scroll Cell -->\n <st-cell \n *ngIf=\"mode === 'virtual'\"\n [cell]=\"cell\" \n [attr.tabindex]=\"cell.isFocused() ? 0 : -1\" \n [editMode]=\"getEditModeForCells()\"\n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n [columnIndex]=\"colIndex\"\n (cellEdit)=\"onCellEdit($event)\" \n (cellSave)=\"onCellSave($event)\"\n (cellSaveAndNavigate)=\"onCellSaveAndNavigate($event)\" \n (cellCancel)=\"onCellCancel($event)\"\n (cellChange)=\"cellChange.emit($event)\">\n </st-cell>\n\n <!-- Standard Cell -->\n <st-cell \n *ngIf=\"mode === 'standard'\"\n [cell]=\"cell\" \n [attr.tabindex]=\"cell.isFocused() ? 0 : -1\"\n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n [columnIndex]=\"colIndex\"\n (cellSave)=\"onCellSave($event)\"\n (cellChange)=\"cellChange.emit($event)\">\n </st-cell>\n </td>\n \n <!-- Row Actions Cell -->\n <td class=\"settings-column\"\n [ngClass]=\"{\n 'has-actions': hasRowActions()\n }\"\n [ngStyle]=\"{\n position: hasRowActions() ? 'sticky' : null,\n 'right.px': hasRowActions() ? 0 : null,\n 'z-index': hasRowActions() ? ZIndex.STICKY_BODY_CELL : null\n }\">\n <button \n *ngIf=\"hasRowActions()\"\n class=\"settings-trigger\"\n (click)=\"openRowActionsDropdown($event, getRowData(rowIndex), rowIndex)\"\n type=\"button\" \n aria-label=\"Row actions\">\n \u22EF\n </button>\n </td>\n </ng-template>\n\n<ng-template #skeletonLoader>\n <div class=\"list-row\" *ngIf=\"(mergedConfig.tableSkeleton?.enabled | async)\">\n <div *ngFor=\"let i of skeletonColumns\" class=\"list-content\">\n <nile-skeleton-loader variant=\"text\" width=\"90%\" height=\"18\" *ngFor=\"let j of skeletonRows\"></nile-skeleton-loader>\n </div>\n </div>\n</ng-template>", styles: [".st-table{width:100%;overflow:auto;position:relative;height:100%;max-height:30rem;border-radius:4px;border:1px solid #E6E9EB}.st-table st-table-actions{position:sticky;right:0}.st-table.keyboard-navigation-enabled{cursor:pointer}.st-table.keyboard-navigation-enabled:focus{outline:none;box-shadow:0 0 0 2px #3b82f64d}.st-table.keyboard-navigation-enabled td.cell-focused{outline:2px solid #4299e1;outline-offset:-1px;position:relative;box-shadow:0 0 0 3px #3182ce1a}.st-table.keyboard-navigation-enabled td.cell-focused:focus{outline:2px solid #4299e1;outline-offset:-1px;box-shadow:0 0 0 3px #3182ce1a}.st-table.keyboard-navigation-enabled td.cell-focused:has(.st-cell.editing){box-shadow:0 0 0 4px #2563eb26}.st-table.virtual-scroll-enabled{overflow-x:visible;margin:0;border:1px solid #E6E9EB;border-collapse:collapse}.st-table.virtual-scroll-enabled .st-scroll-viewport{position:relative;overflow-y:auto;overflow-x:auto;scroll-behavior:smooth}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-scroll-spacer{position:absolute;top:0;left:0;width:1px;pointer-events:none;z-index:-1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-positioner{position:absolute;top:0;left:0;right:0;will-change:transform}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element{position:relative;width:100%;border-collapse:collapse;border-spacing:0;background-color:#fff;table-layout:fixed}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead{background-color:#fff;border-bottom:1px solid #E6E9EB}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead.sticky{position:sticky;top:0;z-index:3;background-color:#fff;will-change:top;backface-visibility:hidden}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead.sticky:after{content:\"\";position:absolute;bottom:-2px;left:0;right:0;height:2px;background:linear-gradient(to bottom,rgba(0,0,0,.1),transparent)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th{padding:0;vertical-align:middle;position:relative;border:none;background-color:#fff;will-change:top;border-right:1px solid #E6E9EB}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left{position:sticky;left:0;background-color:#fff;border-right:1px solid #E6E9EB!important}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-right{position:sticky;right:0;background-color:#fff}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.settings-column{width:2rem;text-align:center;font-weight:600;font-size:12px}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle{position:absolute;top:0;right:0;bottom:0;width:8px;cursor:col-resize;z-index:4;pointer-events:auto}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:after{content:\"\";position:absolute;top:50%;right:3px;transform:translateY(-50%);width:2px;height:20px;background-color:#cbd5e0;opacity:0;transition:opacity .2s}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:hover:after,.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:active:after{opacity:1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.row-number-header{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)):after{content:\"\";position:absolute;right:-6px;top:0;bottom:-1px;width:5px;border-left:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-right-first:not(.settings-column):before{content:\"\";position:absolute;left:-6px;top:0;bottom:-1px;width:5px;border-right:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.08) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody{will-change:transform;position:relative;z-index:1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr{border-bottom:1px solid #E6E9EB;transition:background-color .15s;height:2rem;box-sizing:border-box}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr:last-child{border-bottom:none}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td{padding:0;vertical-align:middle;box-sizing:border-box;height:2rem;border:1px solid #E6E9EB;border-left:none;background-color:#fff}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.align-center{text-align:center}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.align-right{text-align:right}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left{position:sticky;z-index:2;border-right:1px solid #E6E9EB!important}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-right{position:sticky;z-index:2}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column{width:2rem;text-align:center}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column .settings-trigger{background:none;border:none;font-size:1rem;line-height:1;cursor:pointer;border-radius:4px;transition:all .15s ease}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column .settings-trigger:focus{outline:2px solid #4299e1;outline-offset:2px}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.row-number-cell{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)):after{content:\"\";position:absolute;right:-6px;top:0;bottom:-1px;width:5px;border-left:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-right-first:before{content:\"\";position:absolute;left:-6px;top:0;bottom:-1px;width:5px;border-right:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.08) 100%)}.st-table:not(.virtual-scroll-enabled) .st-table-element{width:100%;height:100%;overflow:auto;border-collapse:collapse;table-layout:fixed}.st-table:not(.virtual-scroll-enabled) .st-table-element thead{background-color:#fff;border-bottom:1px solid #E6E9EB}.st-table:not(.virtual-scroll-enabled) .st-table-element thead.sticky{position:sticky;top:0;z-index:3;background-color:#fff;will-change:top;backface-visibility:hidden}.st-table:not(.virtual-scroll-enabled) .st-table-element thead.sticky:after{content:\"\";position:absolute;bottom:-2px;left:0;right:0;height:2px;background:linear-gradient(to bottom,rgba(0,0,0,.1),transparent)}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th{padding:0;vertical-align:middle;position:relative;background-color:#fff;border-right:1px solid #E6E9EB}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-left{position:sticky;left:0;border-right:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-right{position:sticky;right:0;border-left:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-right-first:not(.settings-column){box-shadow:-2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.settings-column{width:2rem;text-align:center;font-weight:600;font-size:12px;border-right:none;position:sticky;right:0}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle{position:absolute;top:0;right:0;bottom:0;width:8px;cursor:col-resize;z-index:4;pointer-events:auto}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:after{content:\"\";position:absolute;top:50%;right:3px;transform:translateY(-50%);width:2px;height:20px;background-color:#cbd5e0;opacity:0;transition:opacity .2s}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:hover:after,.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:active:after{opacity:1}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.row-number-header{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody{will-change:transform;position:relative;z-index:1}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr{height:2rem;box-sizing:border-box}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr:last-child{border-bottom:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td{padding:0;vertical-align:middle;height:2rem;background-color:#fff;border:1px solid #E6E9EB;border-left:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.row-number-cell{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.align-center{text-align:center}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.align-right{text-align:right}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-left{position:sticky;z-index:2;border-right:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-right{position:sticky;z-index:2;border-left:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-right-first:not(.settings-column){box-shadow:-2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.settings-column{position:sticky;right:0;width:2rem;text-align:center;border-right:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.settings-column .settings-trigger{background:none;border:none;font-size:1rem;line-height:1;cursor:pointer;border-radius:4px;transition:all .15s ease}.st-table:not(.virtual-scroll-enabled) .st-table-element .header-content{display:flex;height:2rem;align-items:center}.st-table:not(.virtual-scroll-enabled) .st-table-element .header-content .table-header-text{flex-grow:1;padding-left:4px}.st-table:not(.virtual-scroll-enabled) .st-table-element .settings-column>.header-content{display:flex;align-items:center;justify-content:center}.flex-center{display:flex;align-items:center;justify-content:center}.list-row{padding:1rem}.list-row .list-content{display:flex;justify-content:space-evenly;gap:4px;margin-bottom:1rem}\n"], components: [{ type: StPaginationComponent, selector: "st-pagination", inputs: ["tableState", "tableConfig", "position"] }, { type: StColumnMenuDropdownComponent, selector: "st-column-menu-dropdown", inputs: ["isOpen", "position", "context"], outputs: ["actionClicked", "closed"] }, { type: StRowActionsDropdownComponent, selector: "st-row-actions-dropdown", inputs: ["isOpen", "position", "context"], outputs: ["actionClicked", "closed"] }, { type: StColumnEditorModalComponent, selector: "st-column-editor-modal", outputs: ["columnCreated", "cancelled"] }, { type: StHeaderComponent, selector: "st-header", inputs: ["column", "columnIndex", "isFirstColumn", "isLastColumn", "tableState", "enableSorting", "enableFiltering"], outputs: ["sortToggle", "filterChange", "columnMoved", "menuClick"] }, { type: StTableActionsComponent, selector: "st-table-actions", inputs: ["tableState", "allowAddColumn"], outputs: ["addColumnClicked"] }, { type: StCellComponent, selector: "st-cell", inputs: ["cell", "editMode", "tableState", "tableConfig", "columnIndex"], outputs: ["cellChange", "cellEdit", "cellSave", "cellCancel", "cellSaveAndNavigate"] }], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: StKeyboardNavigationDirective, selector: "[stKeyboardNavigation]", inputs: ["tableState"] }, { type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: StColumnResizeDirective, selector: "[stColumnResize]", inputs: ["column"], outputs: ["columnResized"] }], pipes: { "async": i1.AsyncPipe } });
|
|
8699
|
+
StTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StTableComponent, selector: "st-table", inputs: { tableConfig: "tableConfig", data: "data", data$: "data$", tableState: "tableState", enableSorting: "enableSorting", enableFiltering: "enableFiltering", validateConfig: "validateConfig" }, outputs: { stateChange: "stateChange", dataChange: "dataChange", cellEdit: "cellEdit", cellSave: "cellSave", cellCancel: "cellCancel", cellChange: "cellChange", columnResized: "columnResized", columnMoved: "columnMoved", configValidationErrors: "configValidationErrors", columnAdded: "columnAdded", rowAction: "rowAction", validationStateChange: "validationStateChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "scrollViewport", first: true, predicate: ["scrollViewport"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<!-- Top pagination controls -->\n<st-pagination \n *ngIf=\"showTopPagination() && !(mergedConfig.tableSkeleton?.enabled | async)\" \n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n position=\"top\">\n</st-pagination>\n\n<div class=\"st-table\" *ngIf=\"!(mergedConfig.tableSkeleton?.enabled | async)\" \n [ngClass]=\"{\n 'virtual-scroll-enabled': isVirtualScrollEnabled(),\n 'keyboard-navigation-enabled': isKeyboardNavigationEnabled()\n }\"\n [ngStyle]=\"{\n 'max-height.px': !isVirtualScrollEnabled() ? mergedConfig.display?.maxHeight : null\n }\"\n stKeyboardNavigation\n [tableState]=\"getActiveTableState()\" \n [attr.tabindex]=\"isKeyboardNavigationEnabled() ? 0 : -1\"\n (focus)=\"onTableContainerFocus($event)\"\n [attr.title]=\"isKeyboardNavigationEnabled() ? 'Click a cell or press Tab to start keyboard navigation' : null\">\n <!-- Unified Table Actions Menu -->\n\n <!-- Virtual scroll viewport wrapper -->\n <div class=\"st-scroll-viewport\" #scrollViewport *ngIf=\"isVirtualScrollEnabled()\"\n [ngStyle]=\"{ 'height.px': getVirtualScrollViewportHeight() }\">\n\n <!-- Spacer to create scrollable area -->\n <div class=\"st-scroll-spacer\" [ngStyle]=\"{ 'height.px': virtualScrollTotalHeight$ | async }\">\n </div>\n\n <!-- Table positioner with transform (instead of tbody) -->\n <div class=\"st-table-positioner\" [ngStyle]=\"{ transform: 'translateY(' + (virtualScrollOffsetY$ | async) + 'px)' }\">\n <!-- Table with only visible rows -->\n <ng-container *ngTemplateOutlet=\"tableTemplate; context: { \n mode: 'virtual',\n theadStyle: { top: (virtualScrollOffsetYNeg$ | async) + 'px' }\n }\"></ng-container>\n </div>\n </div>\n \n <!-- Standard table (when virtual scroll disabled) -->\n <ng-container *ngIf=\"!isVirtualScrollEnabled()\">\n <ng-container *ngTemplateOutlet=\"tableTemplate; context: { \n mode: 'standard',\n theadStyle: null\n }\"></ng-container>\n </ng-container>\n\n <!-- Shared Column Menu Dropdown -->\n <st-column-menu-dropdown \n [isOpen]=\"columnMenuState.isOpen\"\n [position]=\"columnMenuState.position\"\n [context]=\"columnMenuState.context\"\n (actionClicked)=\"onColumnActionClicked($event)\"\n (closed)=\"closeColumnMenu()\">\n </st-column-menu-dropdown>\n</div>\n\n<ng-container *ngIf=\"(mergedConfig.tableSkeleton?.enabled | async)\">\n <ng-container *ngTemplateOutlet=\"skeletonLoader\"></ng-container>\n</ng-container>\n\n<!-- Shared Row Actions Dropdown -->\n<st-row-actions-dropdown [isOpen]=\"dropdownState.isOpen\" [position]=\"dropdownState.position\"\n [context]=\"dropdownState.context\" (actionClicked)=\"onRowActionClicked($event)\" (closed)=\"closeRowActionsDropdown()\">\n</st-row-actions-dropdown>\n\n\n<!-- Bottom pagination controls -->\n<st-pagination \n *ngIf=\"showBottomPagination() && !(mergedConfig.tableSkeleton?.enabled | async)\" \n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n position=\"bottom\">\n</st-pagination>\n\n\n <!-- ========================================== -->\n <!-- REUSABLE TABLE TEMPLATE -->\n <!-- ========================================== -->\n <ng-template #tableTemplate let-mode=\"mode\" let-theadStyle=\"theadStyle\">\n <table class=\"st-table-element\">\n <!-- TABLE HEADER -->\n <thead [ngClass]=\"{ 'sticky': mergedConfig.display?.stickyHeader }\" [ngStyle]=\"theadStyle\">\n <tr>\n <!-- Row Number Header -->\n <th *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-header header-cell sticky-left\"\n [ngStyle]=\"{\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_HEADER_CELL,\n 'width.px': 30\n }\">\n #\n </th>\n <!-- Column Headers -->\n <th \n *ngFor=\"let column of visibleColumns; let colIndex = index; let isFirst = first; let isLast = last\"\n [ngClass]=\"{\n 'header-cell': mode === 'standard',\n 'sticky-left': column.sticky === 'left',\n 'sticky-right': column.sticky === 'right',\n 'sticky-right-first': column.sticky === 'right' && isFirstStickyRight(column.key),\n 'resizable': column.resizable !== false\n }\"\n [ngStyle]=\"{\n position: column.sticky ? 'sticky' : null,\n 'left.px': column.sticky === 'left' ? (column.stickyOffset || 0) : null,\n 'right.px': column.sticky === 'right' ? (column.stickyOffset || 0) : null,\n 'z-index': column.sticky ? ZIndex.STICKY_HEADER_CELL : null,\n 'width.px': column.width\n }\">\n \n <st-header \n [column]=\"column\"\n [columnIndex]=\"colIndex\"\n [isFirstColumn]=\"isFirst\"\n [isLastColumn]=\"isLast\"\n [tableState]=\"getActiveTableState()\"\n [enableSorting]=\"mergedConfig.sorting?.enabled ?? enableSorting\"\n [enableFiltering]=\"mergedConfig.filtering?.enabled ?? enableFiltering\"\n (columnMoved)=\"onColumnMoved($event)\"\n (menuClick)=\"openColumnMenu($event, column, colIndex, isFirst, isLast)\">\n </st-header>\n\n <div \n class=\"resize-handle\" \n stColumnResize\n [column]=\"column\"\n (columnResized)=\"onColumnResized($event)\"\n *ngIf=\"column.resizable !== false\">\n </div>\n </th>\n \n <!-- Settings Column Header -->\n <th \n class=\"settings-column sticky-right\"\n [ngClass]=\"{ 'header-cell': mode === 'standard' }\"\n [ngStyle]=\"{ 'z-index': ZIndex.STICKY_HEADER_CELL }\">\n <div [ngClass]=\"{ 'flex-center': mode === 'virtual', 'header-content': mode === 'standard' }\">\n <st-table-actions \n [tableState]=\"getActiveTableState()\"\n [allowAddColumn]=\"mergedConfig.features?.columnManagement?.allowAdd || false\"\n (addColumnClicked)=\"onAddColumnClick()\">\n </st-table-actions>\n </div>\n </th>\n </tr>\n </thead>\n\n <!-- TABLE BODY -->\n <tbody>\n <!-- Virtual Scroll Rows -->\n <ng-container *ngIf=\"mode === 'virtual'\">\n <tr *ngFor=\"let row of visibleRows$ | async; let relativeIndex = index; trackBy: trackByRowIndex\"\n [attr.data-row-index]=\"getAbsoluteRowIndex(relativeIndex)\">\n <!-- Row Number Cell -->\n <td *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-cell\" \n [ngClass]=\"{ 'sticky-left': 'left' }\"\n [ngStyle]=\"{\n 'width.px': 30,\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_BODY_CELL,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\">\n {{getAbsoluteRowIndex(relativeIndex) + 1}}\n </td>\n <ng-container *ngTemplateOutlet=\"bodyCellTemplate; context: { \n row: row,\n rowIndex: getAbsoluteRowIndex(relativeIndex),\n mode: 'virtual',\n relativeIndex: relativeIndex\n }\"></ng-container>\n </tr>\n </ng-container>\n\n <!-- Standard Rows -->\n <ng-container *ngIf=\"mode === 'standard'\">\n <tr *ngFor=\"let row of visibleCellGrid; let rowIndex = index\" [attr.data-row-index]=\"rowIndex\">\n <!-- Row Number Cell -->\n <td *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-cell\" \n [ngClass]=\"{ 'sticky-left': 'left' }\"\n [ngStyle]=\"{\n 'width.px': 30,\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_BODY_CELL,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\">\n {{rowIndex + 1}}\n </td>\n <ng-container *ngTemplateOutlet=\"bodyCellTemplate; context: { \n row: row,\n rowIndex: rowIndex,\n mode: 'standard'\n }\"></ng-container>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </ng-template>\n\n <!-- ========================================== -->\n <!-- REUSABLE BODY CELL TEMPLATE -->\n <!-- ========================================== -->\n <ng-template #bodyCellTemplate let-row=\"row\" let-rowIndex=\"rowIndex\" let-mode=\"mode\" let-relativeIndex=\"relativeIndex\">\n <!-- Data Cells -->\n <td \n *ngFor=\"let cell of row; let colIndex = index\"\n [ngClass]=\"{\n 'sticky-left': visibleColumns[colIndex]?.sticky === 'left',\n 'sticky-right': visibleColumns[colIndex]?.sticky === 'right',\n 'sticky-right-first': visibleColumns[colIndex]?.sticky === 'right' && visibleColumns[colIndex]?.key && isFirstStickyRight(visibleColumns[colIndex].key),\n 'align-center': visibleColumns[colIndex]?.alignment === 'center',\n 'align-right': visibleColumns[colIndex]?.alignment === 'right',\n 'cell-focused': cell.isFocused()\n }\"\n [ngStyle]=\"{\n position: visibleColumns[colIndex]?.sticky ? 'sticky' : null,\n 'left.px': visibleColumns[colIndex]?.sticky === 'left' ? (visibleColumns[colIndex]?.stickyOffset || 0) : null,\n 'right.px': visibleColumns[colIndex]?.sticky === 'right' ? (visibleColumns[colIndex]?.stickyOffset || 0) : null,\n 'z-index': visibleColumns[colIndex]?.sticky ? ZIndex.STICKY_BODY_CELL : null,\n 'width.px': visibleColumns[colIndex]?.width,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\"\n (click)=\"isKeyboardNavigationEnabled() ? onCellClick(rowIndex, colIndex) : null\">\n \n <!-- Virtual Scroll Cell -->\n <st-cell \n *ngIf=\"mode === 'virtual'\"\n [cell]=\"cell\" \n [attr.tabindex]=\"cell.isFocused() ? 0 : -1\" \n [editMode]=\"getEditModeForCells()\"\n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n [columnIndex]=\"colIndex\"\n (cellEdit)=\"onCellEdit($event)\" \n (cellSave)=\"onCellSave($event)\"\n (cellSaveAndNavigate)=\"onCellSaveAndNavigate($event)\" \n (cellCancel)=\"onCellCancel($event)\"\n (cellChange)=\"cellChange.emit($event)\">\n </st-cell>\n\n <!-- Standard Cell -->\n <st-cell \n *ngIf=\"mode === 'standard'\"\n [cell]=\"cell\" \n [attr.tabindex]=\"cell.isFocused() ? 0 : -1\"\n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n [columnIndex]=\"colIndex\"\n (cellSave)=\"onCellSave($event)\"\n (cellChange)=\"cellChange.emit($event)\">\n </st-cell>\n </td>\n \n <!-- Row Actions Cell -->\n <td class=\"settings-column\"\n [ngClass]=\"{\n 'has-actions': hasRowActions()\n }\"\n [ngStyle]=\"{\n position: hasRowActions() ? 'sticky' : null,\n 'right.px': hasRowActions() ? 0 : null,\n 'z-index': hasRowActions() ? ZIndex.STICKY_BODY_CELL : null\n }\">\n <button \n *ngIf=\"hasRowActions()\"\n class=\"settings-trigger\"\n (click)=\"openRowActionsDropdown($event, getRowData(rowIndex), rowIndex)\"\n type=\"button\" \n aria-label=\"Row actions\">\n \u22EF\n </button>\n </td>\n </ng-template>\n\n<ng-template #skeletonLoader>\n <div class=\"list-row\" *ngIf=\"(mergedConfig.tableSkeleton?.enabled | async)\">\n <div *ngFor=\"let i of skeletonColumns\" class=\"list-content\">\n <nile-skeleton-loader variant=\"text\" width=\"90%\" height=\"18\" *ngFor=\"let j of skeletonRows\"></nile-skeleton-loader>\n </div>\n </div>\n</ng-template>", styles: [".st-table{width:100%;overflow:auto;position:relative;height:100%;max-height:30rem;border-radius:4px;border:1px solid #E6E9EB}.st-table st-table-actions{position:sticky;right:0}.st-table.keyboard-navigation-enabled{cursor:pointer}.st-table.keyboard-navigation-enabled:focus{outline:none;box-shadow:0 0 0 2px #3b82f64d}.st-table.keyboard-navigation-enabled td.cell-focused{outline:2px solid #4299e1;outline-offset:-1px;position:relative;box-shadow:0 0 0 3px #3182ce1a}.st-table.keyboard-navigation-enabled td.cell-focused:focus{outline:2px solid #4299e1;outline-offset:-1px;box-shadow:0 0 0 3px #3182ce1a}.st-table.keyboard-navigation-enabled td.cell-focused:has(.st-cell.editing){box-shadow:0 0 0 4px #2563eb26}.st-table.virtual-scroll-enabled{overflow-x:visible;margin:0;border:1px solid #E6E9EB;border-collapse:collapse}.st-table.virtual-scroll-enabled .st-scroll-viewport{position:relative;overflow-y:auto;overflow-x:auto;scroll-behavior:smooth}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-scroll-spacer{position:absolute;top:0;left:0;width:1px;pointer-events:none;z-index:-1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-positioner{position:absolute;top:0;left:0;right:0;will-change:transform}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element{position:relative;width:100%;border-collapse:collapse;border-spacing:0;background-color:#fff;table-layout:fixed}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead{background-color:#fff;border-bottom:1px solid #E6E9EB}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead.sticky{position:sticky;top:0;z-index:3;background-color:#fff;will-change:top;backface-visibility:hidden}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead.sticky:after{content:\"\";position:absolute;bottom:-2px;left:0;right:0;height:2px;background:linear-gradient(to bottom,rgba(0,0,0,.1),transparent)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th{padding:0;vertical-align:middle;position:relative;border:none;background-color:#fff;will-change:top;border-right:1px solid #E6E9EB}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left{position:sticky;left:0;background-color:#fff;border-right:1px solid #E6E9EB!important}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-right{position:sticky;right:0;background-color:#fff}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.settings-column{width:2rem;text-align:center;font-weight:600;font-size:12px}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle{position:absolute;top:0;right:0;bottom:0;width:8px;cursor:col-resize;z-index:4;pointer-events:auto}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:after{content:\"\";position:absolute;top:50%;right:3px;transform:translateY(-50%);width:2px;height:20px;background-color:#cbd5e0;opacity:0;transition:opacity .2s}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:hover:after,.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:active:after{opacity:1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.row-number-header{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)):after{content:\"\";position:absolute;right:-6px;top:0;bottom:-1px;width:5px;border-left:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-right-first:not(.settings-column):before{content:\"\";position:absolute;left:-6px;top:0;bottom:-1px;width:5px;border-right:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.08) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody{will-change:transform;position:relative;z-index:1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr{border-bottom:1px solid #E6E9EB;transition:background-color .15s;height:2rem;box-sizing:border-box}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr:last-child{border-bottom:none}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td{padding:0;vertical-align:middle;box-sizing:border-box;height:2rem;border:1px solid #E6E9EB;border-left:none;background-color:#fff}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.align-center{text-align:center}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.align-right{text-align:right}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left{position:sticky;z-index:2;border-right:1px solid #E6E9EB!important}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-right{position:sticky;z-index:2}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column{width:2rem;text-align:center}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column .settings-trigger{background:none;border:none;font-size:1rem;line-height:1;cursor:pointer;border-radius:4px;transition:all .15s ease}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column .settings-trigger:focus{outline:2px solid #4299e1;outline-offset:2px}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.row-number-cell{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)):after{content:\"\";position:absolute;right:-6px;top:0;bottom:-1px;width:5px;border-left:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-right-first:before{content:\"\";position:absolute;left:-6px;top:0;bottom:-1px;width:5px;border-right:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.08) 100%)}.st-table:not(.virtual-scroll-enabled) .st-table-element{width:100%;height:100%;overflow:auto;border-collapse:collapse;table-layout:fixed}.st-table:not(.virtual-scroll-enabled) .st-table-element thead{background-color:#fff;border-bottom:1px solid #E6E9EB}.st-table:not(.virtual-scroll-enabled) .st-table-element thead.sticky{position:sticky;top:0;z-index:3;background-color:#fff;will-change:top;backface-visibility:hidden}.st-table:not(.virtual-scroll-enabled) .st-table-element thead.sticky:after{content:\"\";position:absolute;bottom:-2px;left:0;right:0;height:2px;background:linear-gradient(to bottom,rgba(0,0,0,.1),transparent)}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th{padding:0;vertical-align:middle;position:relative;background-color:#fff;border-right:1px solid #E6E9EB}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-left{position:sticky;left:0;border-right:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-right{position:sticky;right:0;border-left:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-right-first:not(.settings-column){box-shadow:-2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.settings-column{width:2rem;text-align:center;font-weight:600;font-size:12px;border-right:none;position:sticky;right:0}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle{position:absolute;top:0;right:0;bottom:0;width:8px;cursor:col-resize;z-index:4;pointer-events:auto}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:after{content:\"\";position:absolute;top:50%;right:3px;transform:translateY(-50%);width:2px;height:20px;background-color:#cbd5e0;opacity:0;transition:opacity .2s}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:hover:after,.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:active:after{opacity:1}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.row-number-header{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody{will-change:transform;position:relative;z-index:1}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr{height:2rem;box-sizing:border-box}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr:last-child{border-bottom:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td{padding:0;vertical-align:middle;height:2rem;background-color:#fff;border:1px solid #E6E9EB;border-left:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.row-number-cell{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.align-center{text-align:center}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.align-right{text-align:right}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-left{position:sticky;z-index:2;border-right:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-right{position:sticky;z-index:2;border-left:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-right-first:not(.settings-column){box-shadow:-2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.settings-column{position:sticky;right:0;width:2rem;text-align:center;border-right:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.settings-column .settings-trigger{background:none;border:none;font-size:1rem;line-height:1;cursor:pointer;border-radius:4px;transition:all .15s ease}.st-table:not(.virtual-scroll-enabled) .st-table-element .header-content{display:flex;height:2rem;align-items:center}.st-table:not(.virtual-scroll-enabled) .st-table-element .header-content .table-header-text{flex-grow:1;padding-left:4px}.st-table:not(.virtual-scroll-enabled) .st-table-element .settings-column>.header-content{display:flex;align-items:center;justify-content:center}.flex-center{display:flex;align-items:center;justify-content:center}.list-row{padding:1rem}.list-row .list-content{display:flex;justify-content:space-evenly;gap:4px;margin-bottom:1rem}\n"], components: [{ type: StPaginationComponent, selector: "st-pagination", inputs: ["tableState", "tableConfig", "position"] }, { type: StColumnMenuDropdownComponent, selector: "st-column-menu-dropdown", inputs: ["isOpen", "position", "context"], outputs: ["actionClicked", "closed"] }, { type: StRowActionsDropdownComponent, selector: "st-row-actions-dropdown", inputs: ["isOpen", "position", "context"], outputs: ["actionClicked", "closed"] }, { type: StHeaderComponent, selector: "st-header", inputs: ["column", "columnIndex", "isFirstColumn", "isLastColumn", "tableState", "enableSorting", "enableFiltering"], outputs: ["sortToggle", "filterChange", "columnMoved", "menuClick"] }, { type: StTableActionsComponent, selector: "st-table-actions", inputs: ["tableState", "allowAddColumn"], outputs: ["addColumnClicked"] }, { type: StCellComponent, selector: "st-cell", inputs: ["cell", "editMode", "tableState", "tableConfig", "columnIndex"], outputs: ["cellChange", "cellEdit", "cellSave", "cellCancel", "cellSaveAndNavigate"] }], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: StKeyboardNavigationDirective, selector: "[stKeyboardNavigation]", inputs: ["tableState"] }, { type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: StColumnResizeDirective, selector: "[stColumnResize]", inputs: ["column"], outputs: ["columnResized"] }], pipes: { "async": i1.AsyncPipe } });
|
|
8980
8700
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StTableComponent, decorators: [{
|
|
8981
8701
|
type: Component,
|
|
8982
|
-
args: [{ selector: 'st-table', template: "<!-- Top pagination controls -->\n<st-pagination \n *ngIf=\"showTopPagination() && !(mergedConfig.tableSkeleton?.enabled | async)\" \n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n position=\"top\">\n</st-pagination>\n\n<div class=\"st-table\" *ngIf=\"!(mergedConfig.tableSkeleton?.enabled | async)\" \n [ngClass]=\"{\n 'virtual-scroll-enabled': isVirtualScrollEnabled(),\n 'keyboard-navigation-enabled': isKeyboardNavigationEnabled()\n }\"\n [ngStyle]=\"{\n 'max-height.px': !isVirtualScrollEnabled() ? mergedConfig.display?.maxHeight : null\n }\"\n stKeyboardNavigation\n [tableState]=\"getActiveTableState()\" \n [attr.tabindex]=\"isKeyboardNavigationEnabled() ? 0 : -1\"\n (focus)=\"onTableContainerFocus($event)\"\n [attr.title]=\"isKeyboardNavigationEnabled() ? 'Click a cell or press Tab to start keyboard navigation' : null\">\n <!-- Unified Table Actions Menu -->\n\n <!-- Virtual scroll viewport wrapper -->\n <div class=\"st-scroll-viewport\" #scrollViewport *ngIf=\"isVirtualScrollEnabled()\"\n [ngStyle]=\"{ 'height.px': getVirtualScrollViewportHeight() }\">\n\n <!-- Spacer to create scrollable area -->\n <div class=\"st-scroll-spacer\" [ngStyle]=\"{ 'height.px': virtualScrollTotalHeight$ | async }\">\n </div>\n\n <!-- Table positioner with transform (instead of tbody) -->\n <div class=\"st-table-positioner\" [ngStyle]=\"{ transform: 'translateY(' + (virtualScrollOffsetY$ | async) + 'px)' }\">\n <!-- Table with only visible rows -->\n <ng-container *ngTemplateOutlet=\"tableTemplate; context: { \n mode: 'virtual',\n theadStyle: { top: (virtualScrollOffsetYNeg$ | async) + 'px' }\n }\"></ng-container>\n </div>\n </div>\n \n <!-- Standard table (when virtual scroll disabled) -->\n <ng-container *ngIf=\"!isVirtualScrollEnabled()\">\n <ng-container *ngTemplateOutlet=\"tableTemplate; context: { \n mode: 'standard',\n theadStyle: null\n }\"></ng-container>\n </ng-container>\n\n <!-- Shared Column Menu Dropdown -->\n <st-column-menu-dropdown \n [isOpen]=\"columnMenuState.isOpen\"\n [position]=\"columnMenuState.position\"\n [context]=\"columnMenuState.context\"\n (actionClicked)=\"onColumnActionClicked($event)\"\n (closed)=\"closeColumnMenu()\">\n </st-column-menu-dropdown>\n</div>\n\n<ng-container *ngIf=\"(mergedConfig.tableSkeleton?.enabled | async)\">\n <ng-container *ngTemplateOutlet=\"skeletonLoader\"></ng-container>\n</ng-container>\n\n<!-- Shared Row Actions Dropdown -->\n<st-row-actions-dropdown [isOpen]=\"dropdownState.isOpen\" [position]=\"dropdownState.position\"\n [context]=\"dropdownState.context\" (actionClicked)=\"onRowActionClicked($event)\" (closed)=\"closeRowActionsDropdown()\">\n</st-row-actions-dropdown>\n\n\n<!-- Bottom pagination controls -->\n<st-pagination \n *ngIf=\"showBottomPagination() && !(mergedConfig.tableSkeleton?.enabled | async)\" \n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n position=\"bottom\">\n</st-pagination>\n\n<!-- Add Column Modal -->\n<st-column-editor-modal *ngIf=\"showColumnModal\" (columnCreated)=\"onColumnCreated($event)\"\n (cancelled)=\"onModalCancelled()\">\n</st-column-editor-modal>\n\n <!-- ========================================== -->\n <!-- REUSABLE TABLE TEMPLATE -->\n <!-- ========================================== -->\n <ng-template #tableTemplate let-mode=\"mode\" let-theadStyle=\"theadStyle\">\n <table class=\"st-table-element\">\n <!-- TABLE HEADER -->\n <thead [ngClass]=\"{ 'sticky': mergedConfig.display?.stickyHeader }\" [ngStyle]=\"theadStyle\">\n <tr>\n <!-- Row Number Header -->\n <th *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-header header-cell sticky-left\"\n [ngStyle]=\"{\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_HEADER_CELL,\n 'width.px': 30\n }\">\n #\n </th>\n <!-- Column Headers -->\n <th \n *ngFor=\"let column of visibleColumns; let colIndex = index; let isFirst = first; let isLast = last\"\n [ngClass]=\"{\n 'header-cell': mode === 'standard',\n 'sticky-left': column.sticky === 'left',\n 'sticky-right': column.sticky === 'right',\n 'sticky-right-first': column.sticky === 'right' && isFirstStickyRight(column.key),\n 'resizable': column.resizable !== false\n }\"\n [ngStyle]=\"{\n position: column.sticky ? 'sticky' : null,\n 'left.px': column.sticky === 'left' ? (column.stickyOffset || 0) : null,\n 'right.px': column.sticky === 'right' ? (column.stickyOffset || 0) : null,\n 'z-index': column.sticky ? ZIndex.STICKY_HEADER_CELL : null,\n 'width.px': column.width\n }\">\n \n <st-header \n [column]=\"column\"\n [columnIndex]=\"colIndex\"\n [isFirstColumn]=\"isFirst\"\n [isLastColumn]=\"isLast\"\n [tableState]=\"getActiveTableState()\"\n [enableSorting]=\"mergedConfig.sorting?.enabled ?? enableSorting\"\n [enableFiltering]=\"mergedConfig.filtering?.enabled ?? enableFiltering\"\n (columnMoved)=\"onColumnMoved($event)\"\n (menuClick)=\"openColumnMenu($event, column, colIndex, isFirst, isLast)\">\n </st-header>\n\n <div \n class=\"resize-handle\" \n stColumnResize\n [column]=\"column\"\n (columnResized)=\"onColumnResized($event)\"\n *ngIf=\"column.resizable !== false\">\n </div>\n </th>\n \n <!-- Settings Column Header -->\n <th \n class=\"settings-column sticky-right\"\n [ngClass]=\"{ 'header-cell': mode === 'standard' }\"\n [ngStyle]=\"{ 'z-index': ZIndex.STICKY_HEADER_CELL }\">\n <div [ngClass]=\"{ 'flex-center': mode === 'virtual', 'header-content': mode === 'standard' }\">\n <st-table-actions \n [tableState]=\"getActiveTableState()\"\n [allowAddColumn]=\"mergedConfig.features?.columnManagement?.allowAdd || false\"\n (addColumnClicked)=\"onAddColumnClick()\">\n </st-table-actions>\n </div>\n </th>\n </tr>\n </thead>\n\n <!-- TABLE BODY -->\n <tbody>\n <!-- Virtual Scroll Rows -->\n <ng-container *ngIf=\"mode === 'virtual'\">\n <tr *ngFor=\"let row of visibleRows$ | async; let relativeIndex = index; trackBy: trackByRowIndex\"\n [attr.data-row-index]=\"getAbsoluteRowIndex(relativeIndex)\">\n <!-- Row Number Cell -->\n <td *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-cell\" \n [ngClass]=\"{ 'sticky-left': 'left' }\"\n [ngStyle]=\"{\n 'width.px': 30,\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_BODY_CELL,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\">\n {{getAbsoluteRowIndex(relativeIndex) + 1}}\n </td>\n <ng-container *ngTemplateOutlet=\"bodyCellTemplate; context: { \n row: row,\n rowIndex: getAbsoluteRowIndex(relativeIndex),\n mode: 'virtual',\n relativeIndex: relativeIndex\n }\"></ng-container>\n </tr>\n </ng-container>\n\n <!-- Standard Rows -->\n <ng-container *ngIf=\"mode === 'standard'\">\n <tr *ngFor=\"let row of visibleCellGrid; let rowIndex = index\" [attr.data-row-index]=\"rowIndex\">\n <!-- Row Number Cell -->\n <td *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-cell\" \n [ngClass]=\"{ 'sticky-left': 'left' }\"\n [ngStyle]=\"{\n 'width.px': 30,\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_BODY_CELL,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\">\n {{rowIndex + 1}}\n </td>\n <ng-container *ngTemplateOutlet=\"bodyCellTemplate; context: { \n row: row,\n rowIndex: rowIndex,\n mode: 'standard'\n }\"></ng-container>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </ng-template>\n\n <!-- ========================================== -->\n <!-- REUSABLE BODY CELL TEMPLATE -->\n <!-- ========================================== -->\n <ng-template #bodyCellTemplate let-row=\"row\" let-rowIndex=\"rowIndex\" let-mode=\"mode\" let-relativeIndex=\"relativeIndex\">\n <!-- Data Cells -->\n <td \n *ngFor=\"let cell of row; let colIndex = index\"\n [ngClass]=\"{\n 'sticky-left': visibleColumns[colIndex]?.sticky === 'left',\n 'sticky-right': visibleColumns[colIndex]?.sticky === 'right',\n 'sticky-right-first': visibleColumns[colIndex]?.sticky === 'right' && visibleColumns[colIndex]?.key && isFirstStickyRight(visibleColumns[colIndex].key),\n 'align-center': visibleColumns[colIndex]?.alignment === 'center',\n 'align-right': visibleColumns[colIndex]?.alignment === 'right',\n 'cell-focused': cell.isFocused()\n }\"\n [ngStyle]=\"{\n position: visibleColumns[colIndex]?.sticky ? 'sticky' : null,\n 'left.px': visibleColumns[colIndex]?.sticky === 'left' ? (visibleColumns[colIndex]?.stickyOffset || 0) : null,\n 'right.px': visibleColumns[colIndex]?.sticky === 'right' ? (visibleColumns[colIndex]?.stickyOffset || 0) : null,\n 'z-index': visibleColumns[colIndex]?.sticky ? ZIndex.STICKY_BODY_CELL : null,\n 'width.px': visibleColumns[colIndex]?.width,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\"\n (click)=\"isKeyboardNavigationEnabled() ? onCellClick(rowIndex, colIndex) : null\">\n \n <!-- Virtual Scroll Cell -->\n <st-cell \n *ngIf=\"mode === 'virtual'\"\n [cell]=\"cell\" \n [attr.tabindex]=\"cell.isFocused() ? 0 : -1\" \n [editMode]=\"getEditModeForCells()\"\n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n [columnIndex]=\"colIndex\"\n (cellEdit)=\"onCellEdit($event)\" \n (cellSave)=\"onCellSave($event)\"\n (cellSaveAndNavigate)=\"onCellSaveAndNavigate($event)\" \n (cellCancel)=\"onCellCancel($event)\"\n (cellChange)=\"cellChange.emit($event)\">\n </st-cell>\n\n <!-- Standard Cell -->\n <st-cell \n *ngIf=\"mode === 'standard'\"\n [cell]=\"cell\" \n [attr.tabindex]=\"cell.isFocused() ? 0 : -1\"\n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n [columnIndex]=\"colIndex\"\n (cellSave)=\"onCellSave($event)\"\n (cellChange)=\"cellChange.emit($event)\">\n </st-cell>\n </td>\n \n <!-- Row Actions Cell -->\n <td class=\"settings-column\"\n [ngClass]=\"{\n 'has-actions': hasRowActions()\n }\"\n [ngStyle]=\"{\n position: hasRowActions() ? 'sticky' : null,\n 'right.px': hasRowActions() ? 0 : null,\n 'z-index': hasRowActions() ? ZIndex.STICKY_BODY_CELL : null\n }\">\n <button \n *ngIf=\"hasRowActions()\"\n class=\"settings-trigger\"\n (click)=\"openRowActionsDropdown($event, getRowData(rowIndex), rowIndex)\"\n type=\"button\" \n aria-label=\"Row actions\">\n \u22EF\n </button>\n </td>\n </ng-template>\n\n<ng-template #skeletonLoader>\n <div class=\"list-row\" *ngIf=\"(mergedConfig.tableSkeleton?.enabled | async)\">\n <div *ngFor=\"let i of skeletonColumns\" class=\"list-content\">\n <nile-skeleton-loader variant=\"text\" width=\"90%\" height=\"18\" *ngFor=\"let j of skeletonRows\"></nile-skeleton-loader>\n </div>\n </div>\n</ng-template>", styles: [".st-table{width:100%;overflow:auto;position:relative;height:100%;max-height:30rem;border-radius:4px;border:1px solid #E6E9EB}.st-table st-table-actions{position:sticky;right:0}.st-table.keyboard-navigation-enabled{cursor:pointer}.st-table.keyboard-navigation-enabled:focus{outline:none;box-shadow:0 0 0 2px #3b82f64d}.st-table.keyboard-navigation-enabled td.cell-focused{outline:2px solid #4299e1;outline-offset:-1px;position:relative;box-shadow:0 0 0 3px #3182ce1a}.st-table.keyboard-navigation-enabled td.cell-focused:focus{outline:2px solid #4299e1;outline-offset:-1px;box-shadow:0 0 0 3px #3182ce1a}.st-table.keyboard-navigation-enabled td.cell-focused:has(.st-cell.editing){box-shadow:0 0 0 4px #2563eb26}.st-table.virtual-scroll-enabled{overflow-x:visible;margin:0;border:1px solid #E6E9EB;border-collapse:collapse}.st-table.virtual-scroll-enabled .st-scroll-viewport{position:relative;overflow-y:auto;overflow-x:auto;scroll-behavior:smooth}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-scroll-spacer{position:absolute;top:0;left:0;width:1px;pointer-events:none;z-index:-1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-positioner{position:absolute;top:0;left:0;right:0;will-change:transform}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element{position:relative;width:100%;border-collapse:collapse;border-spacing:0;background-color:#fff;table-layout:fixed}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead{background-color:#fff;border-bottom:1px solid #E6E9EB}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead.sticky{position:sticky;top:0;z-index:3;background-color:#fff;will-change:top;backface-visibility:hidden}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead.sticky:after{content:\"\";position:absolute;bottom:-2px;left:0;right:0;height:2px;background:linear-gradient(to bottom,rgba(0,0,0,.1),transparent)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th{padding:0;vertical-align:middle;position:relative;border:none;background-color:#fff;will-change:top;border-right:1px solid #E6E9EB}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left{position:sticky;left:0;background-color:#fff;border-right:1px solid #E6E9EB!important}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-right{position:sticky;right:0;background-color:#fff}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.settings-column{width:2rem;text-align:center;font-weight:600;font-size:12px}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle{position:absolute;top:0;right:0;bottom:0;width:8px;cursor:col-resize;z-index:4;pointer-events:auto}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:after{content:\"\";position:absolute;top:50%;right:3px;transform:translateY(-50%);width:2px;height:20px;background-color:#cbd5e0;opacity:0;transition:opacity .2s}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:hover:after,.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:active:after{opacity:1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.row-number-header{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)):after{content:\"\";position:absolute;right:-6px;top:0;bottom:-1px;width:5px;border-left:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-right-first:not(.settings-column):before{content:\"\";position:absolute;left:-6px;top:0;bottom:-1px;width:5px;border-right:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.08) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody{will-change:transform;position:relative;z-index:1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr{border-bottom:1px solid #E6E9EB;transition:background-color .15s;height:2rem;box-sizing:border-box}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr:last-child{border-bottom:none}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td{padding:0;vertical-align:middle;box-sizing:border-box;height:2rem;border:1px solid #E6E9EB;border-left:none;background-color:#fff}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.align-center{text-align:center}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.align-right{text-align:right}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left{position:sticky;z-index:2;border-right:1px solid #E6E9EB!important}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-right{position:sticky;z-index:2}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column{width:2rem;text-align:center}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column .settings-trigger{background:none;border:none;font-size:1rem;line-height:1;cursor:pointer;border-radius:4px;transition:all .15s ease}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column .settings-trigger:focus{outline:2px solid #4299e1;outline-offset:2px}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.row-number-cell{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)):after{content:\"\";position:absolute;right:-6px;top:0;bottom:-1px;width:5px;border-left:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-right-first:before{content:\"\";position:absolute;left:-6px;top:0;bottom:-1px;width:5px;border-right:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.08) 100%)}.st-table:not(.virtual-scroll-enabled) .st-table-element{width:100%;height:100%;overflow:auto;border-collapse:collapse;table-layout:fixed}.st-table:not(.virtual-scroll-enabled) .st-table-element thead{background-color:#fff;border-bottom:1px solid #E6E9EB}.st-table:not(.virtual-scroll-enabled) .st-table-element thead.sticky{position:sticky;top:0;z-index:3;background-color:#fff;will-change:top;backface-visibility:hidden}.st-table:not(.virtual-scroll-enabled) .st-table-element thead.sticky:after{content:\"\";position:absolute;bottom:-2px;left:0;right:0;height:2px;background:linear-gradient(to bottom,rgba(0,0,0,.1),transparent)}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th{padding:0;vertical-align:middle;position:relative;background-color:#fff;border-right:1px solid #E6E9EB}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-left{position:sticky;left:0;border-right:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-right{position:sticky;right:0;border-left:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-right-first:not(.settings-column){box-shadow:-2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.settings-column{width:2rem;text-align:center;font-weight:600;font-size:12px;border-right:none;position:sticky;right:0}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle{position:absolute;top:0;right:0;bottom:0;width:8px;cursor:col-resize;z-index:4;pointer-events:auto}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:after{content:\"\";position:absolute;top:50%;right:3px;transform:translateY(-50%);width:2px;height:20px;background-color:#cbd5e0;opacity:0;transition:opacity .2s}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:hover:after,.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:active:after{opacity:1}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.row-number-header{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody{will-change:transform;position:relative;z-index:1}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr{height:2rem;box-sizing:border-box}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr:last-child{border-bottom:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td{padding:0;vertical-align:middle;height:2rem;background-color:#fff;border:1px solid #E6E9EB;border-left:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.row-number-cell{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.align-center{text-align:center}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.align-right{text-align:right}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-left{position:sticky;z-index:2;border-right:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-right{position:sticky;z-index:2;border-left:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-right-first:not(.settings-column){box-shadow:-2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.settings-column{position:sticky;right:0;width:2rem;text-align:center;border-right:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.settings-column .settings-trigger{background:none;border:none;font-size:1rem;line-height:1;cursor:pointer;border-radius:4px;transition:all .15s ease}.st-table:not(.virtual-scroll-enabled) .st-table-element .header-content{display:flex;height:2rem;align-items:center}.st-table:not(.virtual-scroll-enabled) .st-table-element .header-content .table-header-text{flex-grow:1;padding-left:4px}.st-table:not(.virtual-scroll-enabled) .st-table-element .settings-column>.header-content{display:flex;align-items:center;justify-content:center}.flex-center{display:flex;align-items:center;justify-content:center}.list-row{padding:1rem}.list-row .list-content{display:flex;justify-content:space-evenly;gap:4px;margin-bottom:1rem}\n"] }]
|
|
8702
|
+
args: [{ selector: 'st-table', template: "<!-- Top pagination controls -->\n<st-pagination \n *ngIf=\"showTopPagination() && !(mergedConfig.tableSkeleton?.enabled | async)\" \n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n position=\"top\">\n</st-pagination>\n\n<div class=\"st-table\" *ngIf=\"!(mergedConfig.tableSkeleton?.enabled | async)\" \n [ngClass]=\"{\n 'virtual-scroll-enabled': isVirtualScrollEnabled(),\n 'keyboard-navigation-enabled': isKeyboardNavigationEnabled()\n }\"\n [ngStyle]=\"{\n 'max-height.px': !isVirtualScrollEnabled() ? mergedConfig.display?.maxHeight : null\n }\"\n stKeyboardNavigation\n [tableState]=\"getActiveTableState()\" \n [attr.tabindex]=\"isKeyboardNavigationEnabled() ? 0 : -1\"\n (focus)=\"onTableContainerFocus($event)\"\n [attr.title]=\"isKeyboardNavigationEnabled() ? 'Click a cell or press Tab to start keyboard navigation' : null\">\n <!-- Unified Table Actions Menu -->\n\n <!-- Virtual scroll viewport wrapper -->\n <div class=\"st-scroll-viewport\" #scrollViewport *ngIf=\"isVirtualScrollEnabled()\"\n [ngStyle]=\"{ 'height.px': getVirtualScrollViewportHeight() }\">\n\n <!-- Spacer to create scrollable area -->\n <div class=\"st-scroll-spacer\" [ngStyle]=\"{ 'height.px': virtualScrollTotalHeight$ | async }\">\n </div>\n\n <!-- Table positioner with transform (instead of tbody) -->\n <div class=\"st-table-positioner\" [ngStyle]=\"{ transform: 'translateY(' + (virtualScrollOffsetY$ | async) + 'px)' }\">\n <!-- Table with only visible rows -->\n <ng-container *ngTemplateOutlet=\"tableTemplate; context: { \n mode: 'virtual',\n theadStyle: { top: (virtualScrollOffsetYNeg$ | async) + 'px' }\n }\"></ng-container>\n </div>\n </div>\n \n <!-- Standard table (when virtual scroll disabled) -->\n <ng-container *ngIf=\"!isVirtualScrollEnabled()\">\n <ng-container *ngTemplateOutlet=\"tableTemplate; context: { \n mode: 'standard',\n theadStyle: null\n }\"></ng-container>\n </ng-container>\n\n <!-- Shared Column Menu Dropdown -->\n <st-column-menu-dropdown \n [isOpen]=\"columnMenuState.isOpen\"\n [position]=\"columnMenuState.position\"\n [context]=\"columnMenuState.context\"\n (actionClicked)=\"onColumnActionClicked($event)\"\n (closed)=\"closeColumnMenu()\">\n </st-column-menu-dropdown>\n</div>\n\n<ng-container *ngIf=\"(mergedConfig.tableSkeleton?.enabled | async)\">\n <ng-container *ngTemplateOutlet=\"skeletonLoader\"></ng-container>\n</ng-container>\n\n<!-- Shared Row Actions Dropdown -->\n<st-row-actions-dropdown [isOpen]=\"dropdownState.isOpen\" [position]=\"dropdownState.position\"\n [context]=\"dropdownState.context\" (actionClicked)=\"onRowActionClicked($event)\" (closed)=\"closeRowActionsDropdown()\">\n</st-row-actions-dropdown>\n\n\n<!-- Bottom pagination controls -->\n<st-pagination \n *ngIf=\"showBottomPagination() && !(mergedConfig.tableSkeleton?.enabled | async)\" \n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n position=\"bottom\">\n</st-pagination>\n\n\n <!-- ========================================== -->\n <!-- REUSABLE TABLE TEMPLATE -->\n <!-- ========================================== -->\n <ng-template #tableTemplate let-mode=\"mode\" let-theadStyle=\"theadStyle\">\n <table class=\"st-table-element\">\n <!-- TABLE HEADER -->\n <thead [ngClass]=\"{ 'sticky': mergedConfig.display?.stickyHeader }\" [ngStyle]=\"theadStyle\">\n <tr>\n <!-- Row Number Header -->\n <th *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-header header-cell sticky-left\"\n [ngStyle]=\"{\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_HEADER_CELL,\n 'width.px': 30\n }\">\n #\n </th>\n <!-- Column Headers -->\n <th \n *ngFor=\"let column of visibleColumns; let colIndex = index; let isFirst = first; let isLast = last\"\n [ngClass]=\"{\n 'header-cell': mode === 'standard',\n 'sticky-left': column.sticky === 'left',\n 'sticky-right': column.sticky === 'right',\n 'sticky-right-first': column.sticky === 'right' && isFirstStickyRight(column.key),\n 'resizable': column.resizable !== false\n }\"\n [ngStyle]=\"{\n position: column.sticky ? 'sticky' : null,\n 'left.px': column.sticky === 'left' ? (column.stickyOffset || 0) : null,\n 'right.px': column.sticky === 'right' ? (column.stickyOffset || 0) : null,\n 'z-index': column.sticky ? ZIndex.STICKY_HEADER_CELL : null,\n 'width.px': column.width\n }\">\n \n <st-header \n [column]=\"column\"\n [columnIndex]=\"colIndex\"\n [isFirstColumn]=\"isFirst\"\n [isLastColumn]=\"isLast\"\n [tableState]=\"getActiveTableState()\"\n [enableSorting]=\"mergedConfig.sorting?.enabled ?? enableSorting\"\n [enableFiltering]=\"mergedConfig.filtering?.enabled ?? enableFiltering\"\n (columnMoved)=\"onColumnMoved($event)\"\n (menuClick)=\"openColumnMenu($event, column, colIndex, isFirst, isLast)\">\n </st-header>\n\n <div \n class=\"resize-handle\" \n stColumnResize\n [column]=\"column\"\n (columnResized)=\"onColumnResized($event)\"\n *ngIf=\"column.resizable !== false\">\n </div>\n </th>\n \n <!-- Settings Column Header -->\n <th \n class=\"settings-column sticky-right\"\n [ngClass]=\"{ 'header-cell': mode === 'standard' }\"\n [ngStyle]=\"{ 'z-index': ZIndex.STICKY_HEADER_CELL }\">\n <div [ngClass]=\"{ 'flex-center': mode === 'virtual', 'header-content': mode === 'standard' }\">\n <st-table-actions \n [tableState]=\"getActiveTableState()\"\n [allowAddColumn]=\"mergedConfig.features?.columnManagement?.allowAdd || false\"\n (addColumnClicked)=\"onAddColumnClick()\">\n </st-table-actions>\n </div>\n </th>\n </tr>\n </thead>\n\n <!-- TABLE BODY -->\n <tbody>\n <!-- Virtual Scroll Rows -->\n <ng-container *ngIf=\"mode === 'virtual'\">\n <tr *ngFor=\"let row of visibleRows$ | async; let relativeIndex = index; trackBy: trackByRowIndex\"\n [attr.data-row-index]=\"getAbsoluteRowIndex(relativeIndex)\">\n <!-- Row Number Cell -->\n <td *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-cell\" \n [ngClass]=\"{ 'sticky-left': 'left' }\"\n [ngStyle]=\"{\n 'width.px': 30,\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_BODY_CELL,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\">\n {{getAbsoluteRowIndex(relativeIndex) + 1}}\n </td>\n <ng-container *ngTemplateOutlet=\"bodyCellTemplate; context: { \n row: row,\n rowIndex: getAbsoluteRowIndex(relativeIndex),\n mode: 'virtual',\n relativeIndex: relativeIndex\n }\"></ng-container>\n </tr>\n </ng-container>\n\n <!-- Standard Rows -->\n <ng-container *ngIf=\"mode === 'standard'\">\n <tr *ngFor=\"let row of visibleCellGrid; let rowIndex = index\" [attr.data-row-index]=\"rowIndex\">\n <!-- Row Number Cell -->\n <td *ngIf=\"mergedConfig.showRowNumber\" class=\"row-number-cell\" \n [ngClass]=\"{ 'sticky-left': 'left' }\"\n [ngStyle]=\"{\n 'width.px': 30,\n position: 'sticky',\n 'left.px': 0,\n 'z-index': ZIndex.STICKY_BODY_CELL,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\">\n {{rowIndex + 1}}\n </td>\n <ng-container *ngTemplateOutlet=\"bodyCellTemplate; context: { \n row: row,\n rowIndex: rowIndex,\n mode: 'standard'\n }\"></ng-container>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </ng-template>\n\n <!-- ========================================== -->\n <!-- REUSABLE BODY CELL TEMPLATE -->\n <!-- ========================================== -->\n <ng-template #bodyCellTemplate let-row=\"row\" let-rowIndex=\"rowIndex\" let-mode=\"mode\" let-relativeIndex=\"relativeIndex\">\n <!-- Data Cells -->\n <td \n *ngFor=\"let cell of row; let colIndex = index\"\n [ngClass]=\"{\n 'sticky-left': visibleColumns[colIndex]?.sticky === 'left',\n 'sticky-right': visibleColumns[colIndex]?.sticky === 'right',\n 'sticky-right-first': visibleColumns[colIndex]?.sticky === 'right' && visibleColumns[colIndex]?.key && isFirstStickyRight(visibleColumns[colIndex].key),\n 'align-center': visibleColumns[colIndex]?.alignment === 'center',\n 'align-right': visibleColumns[colIndex]?.alignment === 'right',\n 'cell-focused': cell.isFocused()\n }\"\n [ngStyle]=\"{\n position: visibleColumns[colIndex]?.sticky ? 'sticky' : null,\n 'left.px': visibleColumns[colIndex]?.sticky === 'left' ? (visibleColumns[colIndex]?.stickyOffset || 0) : null,\n 'right.px': visibleColumns[colIndex]?.sticky === 'right' ? (visibleColumns[colIndex]?.stickyOffset || 0) : null,\n 'z-index': visibleColumns[colIndex]?.sticky ? ZIndex.STICKY_BODY_CELL : null,\n 'width.px': visibleColumns[colIndex]?.width,\n 'height.px': mode === 'virtual' ? getVirtualScrollItemSize() : null\n }\"\n (click)=\"isKeyboardNavigationEnabled() ? onCellClick(rowIndex, colIndex) : null\">\n \n <!-- Virtual Scroll Cell -->\n <st-cell \n *ngIf=\"mode === 'virtual'\"\n [cell]=\"cell\" \n [attr.tabindex]=\"cell.isFocused() ? 0 : -1\" \n [editMode]=\"getEditModeForCells()\"\n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n [columnIndex]=\"colIndex\"\n (cellEdit)=\"onCellEdit($event)\" \n (cellSave)=\"onCellSave($event)\"\n (cellSaveAndNavigate)=\"onCellSaveAndNavigate($event)\" \n (cellCancel)=\"onCellCancel($event)\"\n (cellChange)=\"cellChange.emit($event)\">\n </st-cell>\n\n <!-- Standard Cell -->\n <st-cell \n *ngIf=\"mode === 'standard'\"\n [cell]=\"cell\" \n [attr.tabindex]=\"cell.isFocused() ? 0 : -1\"\n [tableState]=\"getActiveTableState()\"\n [tableConfig]=\"mergedConfig\"\n [columnIndex]=\"colIndex\"\n (cellSave)=\"onCellSave($event)\"\n (cellChange)=\"cellChange.emit($event)\">\n </st-cell>\n </td>\n \n <!-- Row Actions Cell -->\n <td class=\"settings-column\"\n [ngClass]=\"{\n 'has-actions': hasRowActions()\n }\"\n [ngStyle]=\"{\n position: hasRowActions() ? 'sticky' : null,\n 'right.px': hasRowActions() ? 0 : null,\n 'z-index': hasRowActions() ? ZIndex.STICKY_BODY_CELL : null\n }\">\n <button \n *ngIf=\"hasRowActions()\"\n class=\"settings-trigger\"\n (click)=\"openRowActionsDropdown($event, getRowData(rowIndex), rowIndex)\"\n type=\"button\" \n aria-label=\"Row actions\">\n \u22EF\n </button>\n </td>\n </ng-template>\n\n<ng-template #skeletonLoader>\n <div class=\"list-row\" *ngIf=\"(mergedConfig.tableSkeleton?.enabled | async)\">\n <div *ngFor=\"let i of skeletonColumns\" class=\"list-content\">\n <nile-skeleton-loader variant=\"text\" width=\"90%\" height=\"18\" *ngFor=\"let j of skeletonRows\"></nile-skeleton-loader>\n </div>\n </div>\n</ng-template>", styles: [".st-table{width:100%;overflow:auto;position:relative;height:100%;max-height:30rem;border-radius:4px;border:1px solid #E6E9EB}.st-table st-table-actions{position:sticky;right:0}.st-table.keyboard-navigation-enabled{cursor:pointer}.st-table.keyboard-navigation-enabled:focus{outline:none;box-shadow:0 0 0 2px #3b82f64d}.st-table.keyboard-navigation-enabled td.cell-focused{outline:2px solid #4299e1;outline-offset:-1px;position:relative;box-shadow:0 0 0 3px #3182ce1a}.st-table.keyboard-navigation-enabled td.cell-focused:focus{outline:2px solid #4299e1;outline-offset:-1px;box-shadow:0 0 0 3px #3182ce1a}.st-table.keyboard-navigation-enabled td.cell-focused:has(.st-cell.editing){box-shadow:0 0 0 4px #2563eb26}.st-table.virtual-scroll-enabled{overflow-x:visible;margin:0;border:1px solid #E6E9EB;border-collapse:collapse}.st-table.virtual-scroll-enabled .st-scroll-viewport{position:relative;overflow-y:auto;overflow-x:auto;scroll-behavior:smooth}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-scroll-spacer{position:absolute;top:0;left:0;width:1px;pointer-events:none;z-index:-1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-positioner{position:absolute;top:0;left:0;right:0;will-change:transform}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element{position:relative;width:100%;border-collapse:collapse;border-spacing:0;background-color:#fff;table-layout:fixed}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead{background-color:#fff;border-bottom:1px solid #E6E9EB}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead.sticky{position:sticky;top:0;z-index:3;background-color:#fff;will-change:top;backface-visibility:hidden}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead.sticky:after{content:\"\";position:absolute;bottom:-2px;left:0;right:0;height:2px;background:linear-gradient(to bottom,rgba(0,0,0,.1),transparent)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th{padding:0;vertical-align:middle;position:relative;border:none;background-color:#fff;will-change:top;border-right:1px solid #E6E9EB}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left{position:sticky;left:0;background-color:#fff;border-right:1px solid #E6E9EB!important}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-right{position:sticky;right:0;background-color:#fff}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.settings-column{width:2rem;text-align:center;font-weight:600;font-size:12px}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle{position:absolute;top:0;right:0;bottom:0;width:8px;cursor:col-resize;z-index:4;pointer-events:auto}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:after{content:\"\";position:absolute;top:50%;right:3px;transform:translateY(-50%);width:2px;height:20px;background-color:#cbd5e0;opacity:0;transition:opacity .2s}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:hover:after,.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.resizable .resize-handle:active:after{opacity:1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.row-number-header{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)):after{content:\"\";position:absolute;right:-6px;top:0;bottom:-1px;width:5px;border-left:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element thead tr th.sticky-right-first:not(.settings-column):before{content:\"\";position:absolute;left:-6px;top:0;bottom:-1px;width:5px;border-right:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.08) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody{will-change:transform;position:relative;z-index:1}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr{border-bottom:1px solid #E6E9EB;transition:background-color .15s;height:2rem;box-sizing:border-box}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr:last-child{border-bottom:none}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td{padding:0;vertical-align:middle;box-sizing:border-box;height:2rem;border:1px solid #E6E9EB;border-left:none;background-color:#fff}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.align-center{text-align:center}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.align-right{text-align:right}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left{position:sticky;z-index:2;border-right:1px solid #E6E9EB!important}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-right{position:sticky;z-index:2}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column{width:2rem;text-align:center}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column .settings-trigger{background:none;border:none;font-size:1rem;line-height:1;cursor:pointer;border-radius:4px;transition:all .15s ease}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.settings-column .settings-trigger:focus{outline:2px solid #4299e1;outline-offset:2px}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.row-number-cell{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)):after{content:\"\";position:absolute;right:-6px;top:0;bottom:-1px;width:5px;border-left:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 100%)}.st-table.virtual-scroll-enabled .st-scroll-viewport .st-table-element tbody tr td.sticky-right-first:before{content:\"\";position:absolute;left:-6px;top:0;bottom:-1px;width:5px;border-right:1px solid var(--borderColor);background:linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.08) 100%)}.st-table:not(.virtual-scroll-enabled) .st-table-element{width:100%;height:100%;overflow:auto;border-collapse:collapse;table-layout:fixed}.st-table:not(.virtual-scroll-enabled) .st-table-element thead{background-color:#fff;border-bottom:1px solid #E6E9EB}.st-table:not(.virtual-scroll-enabled) .st-table-element thead.sticky{position:sticky;top:0;z-index:3;background-color:#fff;will-change:top;backface-visibility:hidden}.st-table:not(.virtual-scroll-enabled) .st-table-element thead.sticky:after{content:\"\";position:absolute;bottom:-2px;left:0;right:0;height:2px;background:linear-gradient(to bottom,rgba(0,0,0,.1),transparent)}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th{padding:0;vertical-align:middle;position:relative;background-color:#fff;border-right:1px solid #E6E9EB}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-left{position:sticky;left:0;border-right:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-left:not(:has(~ th.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-right{position:sticky;right:0;border-left:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.sticky-right-first:not(.settings-column){box-shadow:-2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.settings-column{width:2rem;text-align:center;font-weight:600;font-size:12px;border-right:none;position:sticky;right:0}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle{position:absolute;top:0;right:0;bottom:0;width:8px;cursor:col-resize;z-index:4;pointer-events:auto}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:after{content:\"\";position:absolute;top:50%;right:3px;transform:translateY(-50%);width:2px;height:20px;background-color:#cbd5e0;opacity:0;transition:opacity .2s}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:hover:after,.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.resizable .resize-handle:active:after{opacity:1}.st-table:not(.virtual-scroll-enabled) .st-table-element thead tr th.row-number-header{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody{will-change:transform;position:relative;z-index:1}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr{height:2rem;box-sizing:border-box}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr:last-child{border-bottom:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td{padding:0;vertical-align:middle;height:2rem;background-color:#fff;border:1px solid #E6E9EB;border-left:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.row-number-cell{text-align:center;font-weight:300;font-size:12px;background-color:#f8f8f8}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.align-center{text-align:center}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.align-right{text-align:right}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-left{position:sticky;z-index:2;border-right:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-left:not(:has(~ td.sticky-left)){box-shadow:2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-right{position:sticky;z-index:2;border-left:1px solid #E6E9EB!important}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.sticky-right-first:not(.settings-column){box-shadow:-2px 0 5px -2px #0003}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.settings-column{position:sticky;right:0;width:2rem;text-align:center;border-right:none}.st-table:not(.virtual-scroll-enabled) .st-table-element tbody tr td.settings-column .settings-trigger{background:none;border:none;font-size:1rem;line-height:1;cursor:pointer;border-radius:4px;transition:all .15s ease}.st-table:not(.virtual-scroll-enabled) .st-table-element .header-content{display:flex;height:2rem;align-items:center}.st-table:not(.virtual-scroll-enabled) .st-table-element .header-content .table-header-text{flex-grow:1;padding-left:4px}.st-table:not(.virtual-scroll-enabled) .st-table-element .settings-column>.header-content{display:flex;align-items:center;justify-content:center}.flex-center{display:flex;align-items:center;justify-content:center}.list-row{padding:1rem}.list-row .list-content{display:flex;justify-content:space-evenly;gap:4px;margin-bottom:1rem}\n"] }]
|
|
8983
8703
|
}], ctorParameters: function () { return [{ type: JsonSchemaValidatorService }, { type: ValidationLoggerService }, { type: VirtualScrollService }]; }, propDecorators: { tableConfig: [{
|
|
8984
8704
|
type: Input
|
|
8985
8705
|
}], data: [{
|
|
@@ -9168,6 +8888,306 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
9168
8888
|
type: Output
|
|
9169
8889
|
}] } });
|
|
9170
8890
|
|
|
8891
|
+
/**
|
|
8892
|
+
* Column Editor Component
|
|
8893
|
+
* Form-based column configuration
|
|
8894
|
+
*/
|
|
8895
|
+
class ColumnEditorComponent {
|
|
8896
|
+
constructor(fb) {
|
|
8897
|
+
this.fb = fb;
|
|
8898
|
+
this.columnUpdated = new EventEmitter();
|
|
8899
|
+
this.cancel = new EventEmitter();
|
|
8900
|
+
this.dataTypes = [
|
|
8901
|
+
{ value: CellDataType.STRING, label: 'Text' },
|
|
8902
|
+
{ value: CellDataType.NUMBER, label: 'Number' },
|
|
8903
|
+
{ value: CellDataType.DATE, label: 'Date' },
|
|
8904
|
+
{ value: CellDataType.BOOLEAN, label: 'Boolean' },
|
|
8905
|
+
{ value: CellDataType.CUSTOM, label: 'Custom' }
|
|
8906
|
+
];
|
|
8907
|
+
this.alignments = [
|
|
8908
|
+
{ value: CellAlignment.LEFT, label: 'Left' },
|
|
8909
|
+
{ value: CellAlignment.CENTER, label: 'Center' },
|
|
8910
|
+
{ value: CellAlignment.RIGHT, label: 'Right' }
|
|
8911
|
+
];
|
|
8912
|
+
this.verticalAlignments = [
|
|
8913
|
+
{ value: CellVerticalAlignment.TOP, label: 'Top' },
|
|
8914
|
+
{ value: CellVerticalAlignment.MIDDLE, label: 'Middle' },
|
|
8915
|
+
{ value: CellVerticalAlignment.BOTTOM, label: 'Bottom' }
|
|
8916
|
+
];
|
|
8917
|
+
this.editModes = [
|
|
8918
|
+
{ value: EditMode.CLICK, label: 'Click' },
|
|
8919
|
+
{ value: EditMode.MANUAL, label: 'Manual' },
|
|
8920
|
+
{ value: EditMode.NONE, label: 'None' }
|
|
8921
|
+
];
|
|
8922
|
+
this.stickyOptions = [
|
|
8923
|
+
{ value: false, label: 'None' },
|
|
8924
|
+
{ value: 'left', label: 'Left' },
|
|
8925
|
+
{ value: 'right', label: 'Right' }
|
|
8926
|
+
];
|
|
8927
|
+
}
|
|
8928
|
+
ngOnInit() {
|
|
8929
|
+
this.buildForm();
|
|
8930
|
+
}
|
|
8931
|
+
ngOnChanges(changes) {
|
|
8932
|
+
if (changes['column'] && !changes['column'].firstChange && this.form) {
|
|
8933
|
+
this.updateForm();
|
|
8934
|
+
}
|
|
8935
|
+
}
|
|
8936
|
+
/**
|
|
8937
|
+
* Build the reactive form
|
|
8938
|
+
*/
|
|
8939
|
+
buildForm() {
|
|
8940
|
+
var _a;
|
|
8941
|
+
this.form = this.fb.group({
|
|
8942
|
+
// Basic properties
|
|
8943
|
+
key: [this.column.key, [Validators.required, Validators.pattern(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/)]],
|
|
8944
|
+
header: [this.column.header || ''],
|
|
8945
|
+
dataType: [this.column.dataType || CellDataType.STRING],
|
|
8946
|
+
// Feature flags
|
|
8947
|
+
editable: [this.column.editable !== false],
|
|
8948
|
+
sortable: [this.column.sortable !== false],
|
|
8949
|
+
filterable: [this.column.filterable !== false],
|
|
8950
|
+
resizable: [this.column.resizable !== false],
|
|
8951
|
+
hideable: [this.column.hideable !== false],
|
|
8952
|
+
movable: [this.column.movable !== false],
|
|
8953
|
+
pinnable: [this.column.pinnable !== false],
|
|
8954
|
+
enableMenu: [this.column.enableMenu !== false],
|
|
8955
|
+
// Layout
|
|
8956
|
+
width: [this.column.width || ''],
|
|
8957
|
+
minWidth: [this.column.minWidth || ''],
|
|
8958
|
+
maxWidth: [this.column.maxWidth || ''],
|
|
8959
|
+
sticky: [this.column.sticky || false],
|
|
8960
|
+
alignment: [this.column.alignment || CellAlignment.LEFT],
|
|
8961
|
+
verticalAlignment: [this.column.verticalAlignment || CellVerticalAlignment.MIDDLE],
|
|
8962
|
+
// Edit mode
|
|
8963
|
+
editMode: [this.column.editMode || EditMode.CLICK],
|
|
8964
|
+
// Display
|
|
8965
|
+
visible: [this.column.visible !== false],
|
|
8966
|
+
truncate: [this.column.truncate || false]
|
|
8967
|
+
});
|
|
8968
|
+
// Subscribe to hideable changes to enforce visible=true when hideable=false
|
|
8969
|
+
(_a = this.form.get('hideable')) === null || _a === void 0 ? void 0 : _a.valueChanges.subscribe(hideable => {
|
|
8970
|
+
var _a;
|
|
8971
|
+
if (!hideable) {
|
|
8972
|
+
(_a = this.form.get('visible')) === null || _a === void 0 ? void 0 : _a.setValue(true, { emitEvent: false });
|
|
8973
|
+
}
|
|
8974
|
+
});
|
|
8975
|
+
// Update form when column changes
|
|
8976
|
+
this.updateForm();
|
|
8977
|
+
}
|
|
8978
|
+
/**
|
|
8979
|
+
* Update form values from column
|
|
8980
|
+
*/
|
|
8981
|
+
updateForm() {
|
|
8982
|
+
if (!this.form || !this.column)
|
|
8983
|
+
return;
|
|
8984
|
+
this.form.patchValue({
|
|
8985
|
+
key: this.column.key,
|
|
8986
|
+
header: this.column.header || '',
|
|
8987
|
+
dataType: this.column.dataType || CellDataType.STRING,
|
|
8988
|
+
editable: this.column.editable !== false,
|
|
8989
|
+
sortable: this.column.sortable !== false,
|
|
8990
|
+
filterable: this.column.filterable !== false,
|
|
8991
|
+
resizable: this.column.resizable !== false,
|
|
8992
|
+
hideable: this.column.hideable !== false,
|
|
8993
|
+
movable: this.column.movable !== false,
|
|
8994
|
+
pinnable: this.column.pinnable !== false,
|
|
8995
|
+
enableMenu: this.column.enableMenu !== false,
|
|
8996
|
+
width: this.column.width || '',
|
|
8997
|
+
minWidth: this.column.minWidth || '',
|
|
8998
|
+
maxWidth: this.column.maxWidth || '',
|
|
8999
|
+
sticky: this.column.sticky || false,
|
|
9000
|
+
alignment: this.column.alignment || CellAlignment.LEFT,
|
|
9001
|
+
verticalAlignment: this.column.verticalAlignment || CellVerticalAlignment.MIDDLE,
|
|
9002
|
+
editMode: this.column.editMode || EditMode.CLICK,
|
|
9003
|
+
visible: this.column.visible !== false,
|
|
9004
|
+
truncate: this.column.truncate || false
|
|
9005
|
+
}, { emitEvent: false });
|
|
9006
|
+
}
|
|
9007
|
+
/**
|
|
9008
|
+
* Handle form submission
|
|
9009
|
+
*/
|
|
9010
|
+
onSave() {
|
|
9011
|
+
if (this.form.valid) {
|
|
9012
|
+
const formValue = this.form.value;
|
|
9013
|
+
const updates = {
|
|
9014
|
+
key: formValue.key,
|
|
9015
|
+
header: formValue.header || undefined,
|
|
9016
|
+
dataType: formValue.dataType,
|
|
9017
|
+
editable: formValue.editable,
|
|
9018
|
+
sortable: formValue.sortable,
|
|
9019
|
+
filterable: formValue.filterable,
|
|
9020
|
+
resizable: formValue.resizable,
|
|
9021
|
+
hideable: formValue.hideable,
|
|
9022
|
+
movable: formValue.movable,
|
|
9023
|
+
pinnable: formValue.pinnable,
|
|
9024
|
+
enableMenu: formValue.enableMenu,
|
|
9025
|
+
width: formValue.width || undefined,
|
|
9026
|
+
minWidth: formValue.minWidth || undefined,
|
|
9027
|
+
maxWidth: formValue.maxWidth || undefined,
|
|
9028
|
+
sticky: formValue.sticky || undefined,
|
|
9029
|
+
alignment: formValue.alignment,
|
|
9030
|
+
verticalAlignment: formValue.verticalAlignment,
|
|
9031
|
+
editMode: formValue.editMode,
|
|
9032
|
+
visible: formValue.visible,
|
|
9033
|
+
truncate: formValue.truncate
|
|
9034
|
+
};
|
|
9035
|
+
// Convert empty strings to undefined
|
|
9036
|
+
Object.keys(updates).forEach(key => {
|
|
9037
|
+
const value = updates[key];
|
|
9038
|
+
if (value === '' || value === null) {
|
|
9039
|
+
updates[key] = undefined;
|
|
9040
|
+
}
|
|
9041
|
+
});
|
|
9042
|
+
this.columnUpdated.emit(updates);
|
|
9043
|
+
}
|
|
9044
|
+
else {
|
|
9045
|
+
// Mark all fields as touched to show validation errors
|
|
9046
|
+
Object.keys(this.form.controls).forEach(key => {
|
|
9047
|
+
var _a;
|
|
9048
|
+
(_a = this.form.get(key)) === null || _a === void 0 ? void 0 : _a.markAsTouched();
|
|
9049
|
+
});
|
|
9050
|
+
}
|
|
9051
|
+
}
|
|
9052
|
+
/**
|
|
9053
|
+
* Handle cancel
|
|
9054
|
+
*/
|
|
9055
|
+
onCancel() {
|
|
9056
|
+
this.cancel.emit();
|
|
9057
|
+
}
|
|
9058
|
+
/**
|
|
9059
|
+
* Get form control error message
|
|
9060
|
+
*/
|
|
9061
|
+
getErrorMessage(controlName) {
|
|
9062
|
+
const control = this.form.get(controlName);
|
|
9063
|
+
if (control === null || control === void 0 ? void 0 : control.hasError('required')) {
|
|
9064
|
+
return 'This field is required';
|
|
9065
|
+
}
|
|
9066
|
+
if (control === null || control === void 0 ? void 0 : control.hasError('pattern')) {
|
|
9067
|
+
return 'Invalid format';
|
|
9068
|
+
}
|
|
9069
|
+
return '';
|
|
9070
|
+
}
|
|
9071
|
+
/**
|
|
9072
|
+
* Check if form control has error
|
|
9073
|
+
*/
|
|
9074
|
+
hasError(controlName) {
|
|
9075
|
+
const control = this.form.get(controlName);
|
|
9076
|
+
return !!(control && control.invalid && (control.dirty || control.touched));
|
|
9077
|
+
}
|
|
9078
|
+
}
|
|
9079
|
+
ColumnEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ColumnEditorComponent, deps: [{ token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
9080
|
+
ColumnEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ColumnEditorComponent, selector: "st-column-editor", inputs: { column: "column", columnIndex: "columnIndex" }, outputs: { columnUpdated: "columnUpdated", cancel: "cancel" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"column-editor\">\n <div class=\"editor-header\">\n <h3>Column Editor</h3>\n <div class=\"editor-actions\">\n <button class=\"btn btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"btn btn-primary\" (click)=\"onSave()\">Save</button>\n </div>\n </div>\n\n <form [formGroup]=\"form\" class=\"editor-form\">\n <!-- Basic Properties -->\n <div class=\"form-section\">\n <h4>Basic Properties</h4>\n <div class=\"form-group\">\n <label for=\"key\">Key *</label>\n <input\n id=\"key\"\n type=\"text\"\n formControlName=\"key\"\n class=\"form-control\"\n [class.error]=\"hasError('key')\"\n placeholder=\"columnKey\">\n <span class=\"error-message\" *ngIf=\"hasError('key')\">\n {{ getErrorMessage('key') }}\n </span>\n </div>\n\n <div class=\"form-group\">\n <label for=\"header\">Header</label>\n <input\n id=\"header\"\n type=\"text\"\n formControlName=\"header\"\n class=\"form-control\"\n placeholder=\"Column Header\">\n </div>\n\n <div class=\"form-group\">\n <label for=\"dataType\">Data Type</label>\n <select id=\"dataType\" formControlName=\"dataType\" class=\"form-control\">\n <option *ngFor=\"let type of dataTypes\" [value]=\"type.value\">\n {{ type.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Features -->\n <div class=\"form-section\">\n <h4>Features</h4>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"editable\">\n <span>Editable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"sortable\">\n <span>Sortable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"filterable\">\n <span>Filterable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"resizable\">\n <span>Resizable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"hideable\">\n <span>Hideable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"movable\">\n <span>Movable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"pinnable\">\n <span>Pinnable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"enableMenu\">\n <span>Enable Menu</span>\n </label>\n </div>\n </div>\n\n <!-- Layout -->\n <div class=\"form-section\">\n <h4>Layout</h4>\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"width\">Width</label>\n <input\n id=\"width\"\n type=\"text\"\n formControlName=\"width\"\n class=\"form-control\"\n placeholder=\"150 or 'auto'\">\n </div>\n <div class=\"form-group\">\n <label for=\"minWidth\">Min Width</label>\n <input\n id=\"minWidth\"\n type=\"number\"\n formControlName=\"minWidth\"\n class=\"form-control\"\n placeholder=\"50\">\n </div>\n <div class=\"form-group\">\n <label for=\"maxWidth\">Max Width</label>\n <input\n id=\"maxWidth\"\n type=\"number\"\n formControlName=\"maxWidth\"\n class=\"form-control\"\n placeholder=\"500\">\n </div>\n </div>\n\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"sticky\">Sticky</label>\n <select id=\"sticky\" formControlName=\"sticky\" class=\"form-control\">\n <option *ngFor=\"let option of stickyOptions\" [value]=\"option.value\">\n {{ option.label }}\n </option>\n </select>\n </div>\n <div class=\"form-group\">\n <label for=\"alignment\">Alignment</label>\n <select id=\"alignment\" formControlName=\"alignment\" class=\"form-control\">\n <option *ngFor=\"let align of alignments\" [value]=\"align.value\">\n {{ align.label }}\n </option>\n </select>\n </div>\n <div class=\"form-group\">\n <label for=\"verticalAlignment\">Vertical Alignment</label>\n <select id=\"verticalAlignment\" formControlName=\"verticalAlignment\" class=\"form-control\">\n <option *ngFor=\"let align of verticalAlignments\" [value]=\"align.value\">\n {{ align.label }}\n </option>\n </select>\n </div>\n </div>\n </div>\n\n <!-- Edit Mode -->\n <div class=\"form-section\">\n <h4>Edit Mode</h4>\n <div class=\"form-group\">\n <label for=\"editMode\">Edit Trigger</label>\n <select id=\"editMode\" formControlName=\"editMode\" class=\"form-control\">\n <option *ngFor=\"let mode of editModes\" [value]=\"mode.value\">\n {{ mode.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Display -->\n <div class=\"form-section\">\n <h4>Display</h4>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-label\" [class.disabled]=\"!form.get('hideable')?.value\">\n <input type=\"checkbox\" \n formControlName=\"visible\"\n [disabled]=\"!form.get('hideable')?.value\"\n [title]=\"!form.get('hideable')?.value ? 'Column visibility cannot be changed when hideable is disabled' : ''\">\n <span>Visible</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"truncate\">\n <span>Truncate Text</span>\n </label>\n </div>\n </div>\n </form>\n</div>\n\n", styles: [".column-editor{display:flex;flex-direction:column;height:100%}.editor-header{display:flex;justify-content:space-between;align-items:center;padding:1rem;border-bottom:1px solid #e0e0e0;background-color:#f8f8f8}.editor-header h3{margin:0;font-size:1.125rem;font-weight:600;color:#333}.editor-actions{display:flex;gap:.5rem}.btn{padding:.5rem 1rem;border:1px solid #d0d0d0;border-radius:4px;cursor:pointer;font-size:.875rem;transition:all .2s}.btn.btn-primary{background-color:#2196f3;color:#fff;border-color:#2196f3}.btn.btn-primary:hover{background-color:#1976d2;border-color:#1976d2}.btn.btn-secondary{background-color:#fff;color:#333}.btn.btn-secondary:hover{background-color:#f5f5f5}.editor-form{flex:1;overflow-y:auto;padding:1rem}.form-section{margin-bottom:2rem}.form-section h4{margin:0 0 1rem;font-size:.875rem;font-weight:600;color:#666;text-transform:uppercase;letter-spacing:.5px}.form-group{margin-bottom:1rem}.form-group label{display:block;margin-bottom:.5rem;font-size:.875rem;font-weight:500;color:#333}.form-control{width:100%;padding:.5rem;border:1px solid #d0d0d0;border-radius:4px;font-size:.875rem;transition:border-color .2s}.form-control:focus{outline:none;border-color:#2196f3}.form-control.error{border-color:#f44336}.form-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));grid-gap:1rem;gap:1rem}.checkbox-group{display:flex;row-gap:1rem;flex-wrap:wrap;gap:.75rem}.checkbox-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem;color:#333}.checkbox-label input[type=checkbox]{width:18px;height:18px;cursor:pointer}.checkbox-label input[type=checkbox]:disabled{cursor:not-allowed;opacity:.5}.checkbox-label.disabled{opacity:.6;cursor:not-allowed}.checkbox-label.disabled span{color:#999}.error-message{display:block;margin-top:.25rem;font-size:.75rem;color:#f44336}\n"], directives: [{ type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }] });
|
|
9081
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ColumnEditorComponent, decorators: [{
|
|
9082
|
+
type: Component,
|
|
9083
|
+
args: [{ selector: 'st-column-editor', template: "<div class=\"column-editor\">\n <div class=\"editor-header\">\n <h3>Column Editor</h3>\n <div class=\"editor-actions\">\n <button class=\"btn btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"btn btn-primary\" (click)=\"onSave()\">Save</button>\n </div>\n </div>\n\n <form [formGroup]=\"form\" class=\"editor-form\">\n <!-- Basic Properties -->\n <div class=\"form-section\">\n <h4>Basic Properties</h4>\n <div class=\"form-group\">\n <label for=\"key\">Key *</label>\n <input\n id=\"key\"\n type=\"text\"\n formControlName=\"key\"\n class=\"form-control\"\n [class.error]=\"hasError('key')\"\n placeholder=\"columnKey\">\n <span class=\"error-message\" *ngIf=\"hasError('key')\">\n {{ getErrorMessage('key') }}\n </span>\n </div>\n\n <div class=\"form-group\">\n <label for=\"header\">Header</label>\n <input\n id=\"header\"\n type=\"text\"\n formControlName=\"header\"\n class=\"form-control\"\n placeholder=\"Column Header\">\n </div>\n\n <div class=\"form-group\">\n <label for=\"dataType\">Data Type</label>\n <select id=\"dataType\" formControlName=\"dataType\" class=\"form-control\">\n <option *ngFor=\"let type of dataTypes\" [value]=\"type.value\">\n {{ type.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Features -->\n <div class=\"form-section\">\n <h4>Features</h4>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"editable\">\n <span>Editable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"sortable\">\n <span>Sortable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"filterable\">\n <span>Filterable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"resizable\">\n <span>Resizable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"hideable\">\n <span>Hideable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"movable\">\n <span>Movable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"pinnable\">\n <span>Pinnable</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"enableMenu\">\n <span>Enable Menu</span>\n </label>\n </div>\n </div>\n\n <!-- Layout -->\n <div class=\"form-section\">\n <h4>Layout</h4>\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"width\">Width</label>\n <input\n id=\"width\"\n type=\"text\"\n formControlName=\"width\"\n class=\"form-control\"\n placeholder=\"150 or 'auto'\">\n </div>\n <div class=\"form-group\">\n <label for=\"minWidth\">Min Width</label>\n <input\n id=\"minWidth\"\n type=\"number\"\n formControlName=\"minWidth\"\n class=\"form-control\"\n placeholder=\"50\">\n </div>\n <div class=\"form-group\">\n <label for=\"maxWidth\">Max Width</label>\n <input\n id=\"maxWidth\"\n type=\"number\"\n formControlName=\"maxWidth\"\n class=\"form-control\"\n placeholder=\"500\">\n </div>\n </div>\n\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"sticky\">Sticky</label>\n <select id=\"sticky\" formControlName=\"sticky\" class=\"form-control\">\n <option *ngFor=\"let option of stickyOptions\" [value]=\"option.value\">\n {{ option.label }}\n </option>\n </select>\n </div>\n <div class=\"form-group\">\n <label for=\"alignment\">Alignment</label>\n <select id=\"alignment\" formControlName=\"alignment\" class=\"form-control\">\n <option *ngFor=\"let align of alignments\" [value]=\"align.value\">\n {{ align.label }}\n </option>\n </select>\n </div>\n <div class=\"form-group\">\n <label for=\"verticalAlignment\">Vertical Alignment</label>\n <select id=\"verticalAlignment\" formControlName=\"verticalAlignment\" class=\"form-control\">\n <option *ngFor=\"let align of verticalAlignments\" [value]=\"align.value\">\n {{ align.label }}\n </option>\n </select>\n </div>\n </div>\n </div>\n\n <!-- Edit Mode -->\n <div class=\"form-section\">\n <h4>Edit Mode</h4>\n <div class=\"form-group\">\n <label for=\"editMode\">Edit Trigger</label>\n <select id=\"editMode\" formControlName=\"editMode\" class=\"form-control\">\n <option *ngFor=\"let mode of editModes\" [value]=\"mode.value\">\n {{ mode.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Display -->\n <div class=\"form-section\">\n <h4>Display</h4>\n <div class=\"checkbox-group\">\n <label class=\"checkbox-label\" [class.disabled]=\"!form.get('hideable')?.value\">\n <input type=\"checkbox\" \n formControlName=\"visible\"\n [disabled]=\"!form.get('hideable')?.value\"\n [title]=\"!form.get('hideable')?.value ? 'Column visibility cannot be changed when hideable is disabled' : ''\">\n <span>Visible</span>\n </label>\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" formControlName=\"truncate\">\n <span>Truncate Text</span>\n </label>\n </div>\n </div>\n </form>\n</div>\n\n", styles: [".column-editor{display:flex;flex-direction:column;height:100%}.editor-header{display:flex;justify-content:space-between;align-items:center;padding:1rem;border-bottom:1px solid #e0e0e0;background-color:#f8f8f8}.editor-header h3{margin:0;font-size:1.125rem;font-weight:600;color:#333}.editor-actions{display:flex;gap:.5rem}.btn{padding:.5rem 1rem;border:1px solid #d0d0d0;border-radius:4px;cursor:pointer;font-size:.875rem;transition:all .2s}.btn.btn-primary{background-color:#2196f3;color:#fff;border-color:#2196f3}.btn.btn-primary:hover{background-color:#1976d2;border-color:#1976d2}.btn.btn-secondary{background-color:#fff;color:#333}.btn.btn-secondary:hover{background-color:#f5f5f5}.editor-form{flex:1;overflow-y:auto;padding:1rem}.form-section{margin-bottom:2rem}.form-section h4{margin:0 0 1rem;font-size:.875rem;font-weight:600;color:#666;text-transform:uppercase;letter-spacing:.5px}.form-group{margin-bottom:1rem}.form-group label{display:block;margin-bottom:.5rem;font-size:.875rem;font-weight:500;color:#333}.form-control{width:100%;padding:.5rem;border:1px solid #d0d0d0;border-radius:4px;font-size:.875rem;transition:border-color .2s}.form-control:focus{outline:none;border-color:#2196f3}.form-control.error{border-color:#f44336}.form-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));grid-gap:1rem;gap:1rem}.checkbox-group{display:flex;row-gap:1rem;flex-wrap:wrap;gap:.75rem}.checkbox-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem;color:#333}.checkbox-label input[type=checkbox]{width:18px;height:18px;cursor:pointer}.checkbox-label input[type=checkbox]:disabled{cursor:not-allowed;opacity:.5}.checkbox-label.disabled{opacity:.6;cursor:not-allowed}.checkbox-label.disabled span{color:#999}.error-message{display:block;margin-top:.25rem;font-size:.75rem;color:#f44336}\n"] }]
|
|
9084
|
+
}], ctorParameters: function () { return [{ type: i1$1.FormBuilder }]; }, propDecorators: { column: [{
|
|
9085
|
+
type: Input
|
|
9086
|
+
}], columnIndex: [{
|
|
9087
|
+
type: Input
|
|
9088
|
+
}], columnUpdated: [{
|
|
9089
|
+
type: Output
|
|
9090
|
+
}], cancel: [{
|
|
9091
|
+
type: Output
|
|
9092
|
+
}] } });
|
|
9093
|
+
|
|
9094
|
+
class StColumnEditorModalComponent {
|
|
9095
|
+
constructor() {
|
|
9096
|
+
this.columnCreated = new EventEmitter();
|
|
9097
|
+
this.cancelled = new EventEmitter();
|
|
9098
|
+
this.columnIndex = -1;
|
|
9099
|
+
}
|
|
9100
|
+
ngOnInit() {
|
|
9101
|
+
// Create a default column that will be edited
|
|
9102
|
+
this.newColumn = this.createDefaultColumn();
|
|
9103
|
+
}
|
|
9104
|
+
ngOnDestroy() {
|
|
9105
|
+
// Cleanup if needed
|
|
9106
|
+
}
|
|
9107
|
+
/**
|
|
9108
|
+
* Create a default column configuration
|
|
9109
|
+
*/
|
|
9110
|
+
createDefaultColumn() {
|
|
9111
|
+
return ColumnConfigFactory.text('newColumn', {
|
|
9112
|
+
header: 'New Column',
|
|
9113
|
+
editable: true,
|
|
9114
|
+
sortable: true,
|
|
9115
|
+
filterable: true,
|
|
9116
|
+
resizable: true,
|
|
9117
|
+
hideable: true,
|
|
9118
|
+
visible: true
|
|
9119
|
+
});
|
|
9120
|
+
}
|
|
9121
|
+
/**
|
|
9122
|
+
* Trigger save from external button
|
|
9123
|
+
*/
|
|
9124
|
+
onSave() {
|
|
9125
|
+
// Call the column editor's save method
|
|
9126
|
+
if (this.columnEditor) {
|
|
9127
|
+
this.columnEditor.onSave();
|
|
9128
|
+
}
|
|
9129
|
+
}
|
|
9130
|
+
/**
|
|
9131
|
+
* Handle column updates from the editor
|
|
9132
|
+
*/
|
|
9133
|
+
onColumnUpdated(updates) {
|
|
9134
|
+
// Merge updates into the new column
|
|
9135
|
+
this.newColumn = Object.assign(Object.assign({}, this.newColumn), updates);
|
|
9136
|
+
// Use ColumnConfigFactory to create proper column based on data type
|
|
9137
|
+
let finalColumn;
|
|
9138
|
+
const key = updates.key || this.newColumn.key;
|
|
9139
|
+
const dataType = updates.dataType || this.newColumn.dataType;
|
|
9140
|
+
switch (dataType) {
|
|
9141
|
+
case CellDataType.NUMBER:
|
|
9142
|
+
finalColumn = ColumnConfigFactory.number(key, this.newColumn);
|
|
9143
|
+
break;
|
|
9144
|
+
case CellDataType.DATE:
|
|
9145
|
+
finalColumn = ColumnConfigFactory.date(key, this.newColumn);
|
|
9146
|
+
break;
|
|
9147
|
+
case CellDataType.BOOLEAN:
|
|
9148
|
+
finalColumn = ColumnConfigFactory.boolean(key, this.newColumn);
|
|
9149
|
+
break;
|
|
9150
|
+
default:
|
|
9151
|
+
finalColumn = ColumnConfigFactory.text(key, this.newColumn);
|
|
9152
|
+
}
|
|
9153
|
+
// Emit the created column
|
|
9154
|
+
this.columnCreated.emit(finalColumn);
|
|
9155
|
+
}
|
|
9156
|
+
/**
|
|
9157
|
+
* Handle cancel from the editor
|
|
9158
|
+
*/
|
|
9159
|
+
onCancel() {
|
|
9160
|
+
this.cancelled.emit();
|
|
9161
|
+
}
|
|
9162
|
+
/**
|
|
9163
|
+
* Handle backdrop click to close modal
|
|
9164
|
+
*/
|
|
9165
|
+
onBackdropClick(event) {
|
|
9166
|
+
if (event.target === event.currentTarget) {
|
|
9167
|
+
this.cancelled.emit();
|
|
9168
|
+
}
|
|
9169
|
+
}
|
|
9170
|
+
/**
|
|
9171
|
+
* Prevent event propagation from modal content
|
|
9172
|
+
*/
|
|
9173
|
+
onModalContentClick(event) {
|
|
9174
|
+
event.stopPropagation();
|
|
9175
|
+
}
|
|
9176
|
+
}
|
|
9177
|
+
StColumnEditorModalComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StColumnEditorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9178
|
+
StColumnEditorModalComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StColumnEditorModalComponent, selector: "st-column-editor-modal", outputs: { columnCreated: "columnCreated", cancelled: "cancelled" }, viewQueries: [{ propertyName: "columnEditor", first: true, predicate: ColumnEditorComponent, descendants: true }], ngImport: i0, template: "<div class=\"modal-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"modal-content\" (click)=\"onModalContentClick($event)\">\n <div class=\"modal-header\">\n <h2>Add New Column</h2>\n <button class=\"close-button\" (click)=\"onCancel()\" type=\"button\" aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n <div class=\"modal-body\">\n <!-- Now using the shared st-column-editor component from SharedTableComponentsModule -->\n <st-column-editor\n [column]=\"newColumn\"\n [columnIndex]=\"columnIndex\"\n (columnUpdated)=\"onColumnUpdated($event)\"\n (cancel)=\"onCancel()\">\n </st-column-editor>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"onSave()\">Add Column</button>\n </div>\n </div>\n</div>\n", styles: [".modal-backdrop{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:2000;animation:fadeIn .2s ease-in-out}.modal-content{background:white;border-radius:8px;box-shadow:0 11px 15px -7px #0003,0 24px 38px 3px #00000024,0 9px 46px 8px #0000001f;max-width:600px;max-height:90vh;width:90%;display:flex;flex-direction:column;animation:slideUp .3s cubic-bezier(.4,0,.2,1)}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;border-bottom:1px solid #e0e0e0;flex-shrink:0}.modal-header h2{margin:0;font-size:20px;font-weight:500;color:#212121}.close-button{background:none;border:none;cursor:pointer;padding:8px;display:flex;align-items:center;justify-content:center;border-radius:50%;color:#757575;transition:all .2s ease}.close-button:hover{background-color:#0000000a;color:#212121}.close-button:active{background-color:#00000014}.close-button:focus{outline:none;box-shadow:0 0 0 2px #1976d24d}.close-button svg{width:24px;height:24px}.modal-body{padding:0;overflow-y:auto;flex:1;min-height:0}.modal-body ::ng-deep st-column-editor{display:block}.modal-body ::ng-deep st-column-editor .column-editor{padding:0;border:none;box-shadow:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-header{display:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-actions{display:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-form{padding:24px}.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #e0e0e0;flex-shrink:0;background-color:#f5f5f5}.modal-footer .btn{padding:10px 20px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.modal-footer .btn:focus{outline:none;box-shadow:0 0 0 2px #0000001a}.modal-footer .btn.btn-secondary{background-color:#fff;color:#424242;border:1px solid #d0d0d0}.modal-footer .btn.btn-secondary:hover{background-color:#f5f5f5}.modal-footer .btn.btn-secondary:active{background-color:#eee}.modal-footer .btn.btn-primary{background-color:#1976d2;color:#fff}.modal-footer .btn.btn-primary:hover{background-color:#1565c0}.modal-footer .btn.btn-primary:active{background-color:#0d47a1}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(50px)}to{opacity:1;transform:translateY(0)}}\n"], components: [{ type: ColumnEditorComponent, selector: "st-column-editor", inputs: ["column", "columnIndex"], outputs: ["columnUpdated", "cancel"] }] });
|
|
9179
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StColumnEditorModalComponent, decorators: [{
|
|
9180
|
+
type: Component,
|
|
9181
|
+
args: [{ selector: 'st-column-editor-modal', template: "<div class=\"modal-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"modal-content\" (click)=\"onModalContentClick($event)\">\n <div class=\"modal-header\">\n <h2>Add New Column</h2>\n <button class=\"close-button\" (click)=\"onCancel()\" type=\"button\" aria-label=\"Close\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n <div class=\"modal-body\">\n <!-- Now using the shared st-column-editor component from SharedTableComponentsModule -->\n <st-column-editor\n [column]=\"newColumn\"\n [columnIndex]=\"columnIndex\"\n (columnUpdated)=\"onColumnUpdated($event)\"\n (cancel)=\"onCancel()\">\n </st-column-editor>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"onSave()\">Add Column</button>\n </div>\n </div>\n</div>\n", styles: [".modal-backdrop{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:2000;animation:fadeIn .2s ease-in-out}.modal-content{background:white;border-radius:8px;box-shadow:0 11px 15px -7px #0003,0 24px 38px 3px #00000024,0 9px 46px 8px #0000001f;max-width:600px;max-height:90vh;width:90%;display:flex;flex-direction:column;animation:slideUp .3s cubic-bezier(.4,0,.2,1)}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;border-bottom:1px solid #e0e0e0;flex-shrink:0}.modal-header h2{margin:0;font-size:20px;font-weight:500;color:#212121}.close-button{background:none;border:none;cursor:pointer;padding:8px;display:flex;align-items:center;justify-content:center;border-radius:50%;color:#757575;transition:all .2s ease}.close-button:hover{background-color:#0000000a;color:#212121}.close-button:active{background-color:#00000014}.close-button:focus{outline:none;box-shadow:0 0 0 2px #1976d24d}.close-button svg{width:24px;height:24px}.modal-body{padding:0;overflow-y:auto;flex:1;min-height:0}.modal-body ::ng-deep st-column-editor{display:block}.modal-body ::ng-deep st-column-editor .column-editor{padding:0;border:none;box-shadow:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-header{display:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-actions{display:none}.modal-body ::ng-deep st-column-editor .column-editor .editor-form{padding:24px}.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #e0e0e0;flex-shrink:0;background-color:#f5f5f5}.modal-footer .btn{padding:10px 20px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.modal-footer .btn:focus{outline:none;box-shadow:0 0 0 2px #0000001a}.modal-footer .btn.btn-secondary{background-color:#fff;color:#424242;border:1px solid #d0d0d0}.modal-footer .btn.btn-secondary:hover{background-color:#f5f5f5}.modal-footer .btn.btn-secondary:active{background-color:#eee}.modal-footer .btn.btn-primary{background-color:#1976d2;color:#fff}.modal-footer .btn.btn-primary:hover{background-color:#1565c0}.modal-footer .btn.btn-primary:active{background-color:#0d47a1}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(50px)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
9182
|
+
}], propDecorators: { columnCreated: [{
|
|
9183
|
+
type: Output
|
|
9184
|
+
}], cancelled: [{
|
|
9185
|
+
type: Output
|
|
9186
|
+
}], columnEditor: [{
|
|
9187
|
+
type: ViewChild,
|
|
9188
|
+
args: [ColumnEditorComponent]
|
|
9189
|
+
}] } });
|
|
9190
|
+
|
|
9171
9191
|
class StSheetActionsComponent {
|
|
9172
9192
|
constructor() {
|
|
9173
9193
|
/**
|