@aquera/ngx-smart-table 0.0.15-alpha → 0.0.16-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-select-editor.mjs +126 -225
- package/esm2020/lib/models/workbook-action.interface.mjs +1 -1
- package/esm2020/lib/renderer/components/st-table/st-table.component.mjs +25 -2
- package/esm2020/lib/renderer/components/st-workbook/st-workbook.component.mjs +13 -5
- package/fesm2015/aquera-ngx-smart-table.mjs +165 -233
- package/fesm2015/aquera-ngx-smart-table.mjs.map +1 -1
- package/fesm2020/aquera-ngx-smart-table.mjs +161 -229
- package/fesm2020/aquera-ngx-smart-table.mjs.map +1 -1
- package/lib/editors/nile-select-editor.d.ts +0 -10
- package/lib/models/workbook-action.interface.d.ts +5 -0
- package/lib/renderer/components/st-workbook/st-workbook.component.d.ts +5 -1
- package/package.json +1 -1
|
@@ -3523,6 +3523,72 @@ class NileInputEditor {
|
|
|
3523
3523
|
* Custom editor using NileSelect from @aquera/nile-elements
|
|
3524
3524
|
* This demonstrates how to create dropdown/select editors for ngx-smart-table
|
|
3525
3525
|
*/
|
|
3526
|
+
/**
|
|
3527
|
+
* Inject global styles for nile-select dropdown height limit
|
|
3528
|
+
*/
|
|
3529
|
+
let dropdownStylesInjected = false;
|
|
3530
|
+
function injectDropdownStyles() {
|
|
3531
|
+
if (dropdownStylesInjected)
|
|
3532
|
+
return;
|
|
3533
|
+
dropdownStylesInjected = true;
|
|
3534
|
+
const styleId = 'nile-select-dropdown-styles';
|
|
3535
|
+
if (document.getElementById(styleId))
|
|
3536
|
+
return;
|
|
3537
|
+
const style = document.createElement('style');
|
|
3538
|
+
style.id = styleId;
|
|
3539
|
+
style.textContent = `
|
|
3540
|
+
/* Limit nile-select dropdown height and enable scrolling */
|
|
3541
|
+
.nile-select-portal-append {
|
|
3542
|
+
max-height: 300px !important;
|
|
3543
|
+
}
|
|
3544
|
+
.nile-select-portal-append .select__listbox {
|
|
3545
|
+
min-width: 220px !important;
|
|
3546
|
+
max-height: 260px !important;
|
|
3547
|
+
overflow-y: auto !important;
|
|
3548
|
+
width: auto !important;
|
|
3549
|
+
}
|
|
3550
|
+
.nile-select-portal-append .select__footer {
|
|
3551
|
+
height: 35px !important;
|
|
3552
|
+
}
|
|
3553
|
+
/* Prevent option text truncation - target the options container */
|
|
3554
|
+
.nile-select-portal-append .select__options {
|
|
3555
|
+
width: auto !important;
|
|
3556
|
+
}
|
|
3557
|
+
.nile-select-portal-append nile-option {
|
|
3558
|
+
width: auto !important;
|
|
3559
|
+
max-width: none !important;
|
|
3560
|
+
}
|
|
3561
|
+
.nile-select-portal-append nile-option::part(base) {
|
|
3562
|
+
white-space: nowrap !important;
|
|
3563
|
+
text-overflow: clip !important;
|
|
3564
|
+
overflow: visible !important;
|
|
3565
|
+
max-width: none !important;
|
|
3566
|
+
}
|
|
3567
|
+
/* Fix option text truncation by changing flex direction */
|
|
3568
|
+
.nile-select-portal-append nile-option::part(option_label_container) {
|
|
3569
|
+
flex-direction: row !important;
|
|
3570
|
+
}
|
|
3571
|
+
/* Combobox styling using ::part() selector */
|
|
3572
|
+
nile-select.st-cell-editor::part(combobox) {
|
|
3573
|
+
background-color: var(--nile-colors-white-base, var(--ng-colors-bg-primary)) !important;
|
|
3574
|
+
border: solid 1px transparent !important;
|
|
3575
|
+
margin: 1px 4px !important;
|
|
3576
|
+
}
|
|
3577
|
+
nile-select.st-cell-editor::part(combobox):hover {
|
|
3578
|
+
border: solid 1px transparent !important;
|
|
3579
|
+
}
|
|
3580
|
+
.st-cell-editor::part(combobox) {
|
|
3581
|
+
background-color: var(--nile-colors-white-base, var(--ng-colors-bg-primary)) !important;
|
|
3582
|
+
border: solid 1px transparent !important;
|
|
3583
|
+
margin: 1px 4px !important;
|
|
3584
|
+
}
|
|
3585
|
+
/* Search input full width */
|
|
3586
|
+
.nile-select-portal-append .select__search {
|
|
3587
|
+
width: 100% !important;
|
|
3588
|
+
}
|
|
3589
|
+
`;
|
|
3590
|
+
document.head.appendChild(style);
|
|
3591
|
+
}
|
|
3526
3592
|
/**
|
|
3527
3593
|
* Custom editor that uses NileSelect component
|
|
3528
3594
|
* @template T The value type (string for single selection, string[] for multiple)
|
|
@@ -3533,9 +3599,6 @@ class NileSelectEditor {
|
|
|
3533
3599
|
this.acceptsInitialKeypress = false;
|
|
3534
3600
|
this.eventListeners = [];
|
|
3535
3601
|
this.currentOptions = [];
|
|
3536
|
-
this.isInitializing = false; // Flag to prevent immediate close during initialization
|
|
3537
|
-
this.hasSaved = false; // Flag to prevent double-save
|
|
3538
|
-
this.lastSelectedValue = ''; // Track the last selected value
|
|
3539
3602
|
// Handle Observable options
|
|
3540
3603
|
if (isObservable(options.options)) {
|
|
3541
3604
|
this.optionsSubscription = options.options.subscribe(opts => {
|
|
@@ -3554,101 +3617,20 @@ class NileSelectEditor {
|
|
|
3554
3617
|
}
|
|
3555
3618
|
}
|
|
3556
3619
|
}
|
|
3557
|
-
/**
|
|
3558
|
-
* Inject global styles to remove border from nile-select combobox
|
|
3559
|
-
* Uses ::part selector which works across shadow DOM boundaries
|
|
3560
|
-
*/
|
|
3561
|
-
injectBorderlessStyles() {
|
|
3562
|
-
if (NileSelectEditor.stylesInjected)
|
|
3563
|
-
return;
|
|
3564
|
-
const styleId = 'nile-select-borderless-styles';
|
|
3565
|
-
if (document.getElementById(styleId)) {
|
|
3566
|
-
NileSelectEditor.stylesInjected = true;
|
|
3567
|
-
return;
|
|
3568
|
-
}
|
|
3569
|
-
const style = document.createElement('style');
|
|
3570
|
-
style.id = styleId;
|
|
3571
|
-
style.textContent = `
|
|
3572
|
-
.st-cell-editor::part(combobox) {
|
|
3573
|
-
border: none !important;
|
|
3574
|
-
outline: none !important;
|
|
3575
|
-
box-shadow: none !important;
|
|
3576
|
-
min-height: unset !important;
|
|
3577
|
-
height: 100% !important;
|
|
3578
|
-
padding: 0 !important;
|
|
3579
|
-
}
|
|
3580
|
-
.st-cell-editor::part(combobox):hover {
|
|
3581
|
-
border: none !important;
|
|
3582
|
-
outline: none !important;
|
|
3583
|
-
box-shadow: none !important;
|
|
3584
|
-
}
|
|
3585
|
-
.st-cell-editor::part(combobox):focus {
|
|
3586
|
-
border: none !important;
|
|
3587
|
-
outline: none !important;
|
|
3588
|
-
box-shadow: none !important;
|
|
3589
|
-
}
|
|
3590
|
-
// .st-cell-editor::part(tag) {
|
|
3591
|
-
// margin: 1px 2px !important;
|
|
3592
|
-
// border-radius: 3px !important;
|
|
3593
|
-
// background-color: #e2e8f0 !important;
|
|
3594
|
-
// font-size: 12px !important;
|
|
3595
|
-
// height: auto !important;
|
|
3596
|
-
// }
|
|
3597
|
-
// .st-cell-editor::part(tag__base) {
|
|
3598
|
-
// border: none !important;
|
|
3599
|
-
// outline: none !important;
|
|
3600
|
-
// padding: 0 2px !important;
|
|
3601
|
-
// height: auto !important;
|
|
3602
|
-
// }
|
|
3603
|
-
// .st-cell-editor::part(tag__content) {
|
|
3604
|
-
// padding: 0 !important;
|
|
3605
|
-
// }
|
|
3606
|
-
.st-cell-editor::part(tags) {
|
|
3607
|
-
gap: 2px !important;
|
|
3608
|
-
align-items: center !important;
|
|
3609
|
-
}
|
|
3610
|
-
.st-cell-editor::part(tags-count) {
|
|
3611
|
-
margin: 0 !important;
|
|
3612
|
-
}
|
|
3613
|
-
.st-cell-editor::part(footer) {
|
|
3614
|
-
height: 35px !important;
|
|
3615
|
-
min-height: 35px !important;
|
|
3616
|
-
padding: 8px !important;
|
|
3617
|
-
padding-bottom: 30px !important;
|
|
3618
|
-
box-sizing: border-box !important;
|
|
3619
|
-
}
|
|
3620
|
-
.st-cell-editor::part(listbox) {
|
|
3621
|
-
margin-bottom: 0 !important;
|
|
3622
|
-
padding-bottom: 0 !important;
|
|
3623
|
-
}
|
|
3624
|
-
`;
|
|
3625
|
-
document.head.appendChild(style);
|
|
3626
|
-
NileSelectEditor.stylesInjected = true;
|
|
3627
|
-
}
|
|
3628
3620
|
edit(context) {
|
|
3629
3621
|
if (!context.container) {
|
|
3630
3622
|
console.warn('NileSelectEditor requires a container element');
|
|
3631
3623
|
return;
|
|
3632
3624
|
}
|
|
3633
|
-
//
|
|
3634
|
-
|
|
3635
|
-
this.hasSaved = false;
|
|
3636
|
-
this.lastSelectedValue = '';
|
|
3625
|
+
// Inject dropdown height styles once
|
|
3626
|
+
injectDropdownStyles();
|
|
3637
3627
|
// Create NileSelect custom element using document.createElement
|
|
3638
3628
|
this.select = document.createElement('nile-select');
|
|
3639
3629
|
this.select.className = 'st-cell-editor';
|
|
3640
|
-
// Apply inline styles for proper cell fitting
|
|
3641
|
-
this.select.style.width = '
|
|
3642
|
-
this.select.style.height = '
|
|
3643
|
-
this.select.style.maxHeight = '100%';
|
|
3630
|
+
// Apply inline styles for proper cell fitting
|
|
3631
|
+
this.select.style.width = '100%';
|
|
3632
|
+
this.select.style.height = 'inherit';
|
|
3644
3633
|
this.select.style.boxSizing = 'border-box';
|
|
3645
|
-
this.select.style.margin = '0 2px';
|
|
3646
|
-
this.select.style.overflow = 'hidden';
|
|
3647
|
-
// Inject styles to remove border using ::part selector
|
|
3648
|
-
this.injectBorderlessStyles();
|
|
3649
|
-
// Also try removing outline on host element
|
|
3650
|
-
this.select.style.outline = 'none';
|
|
3651
|
-
this.select.style.border = 'none';
|
|
3652
3634
|
// Set initial value
|
|
3653
3635
|
this.setInitialValue(context.value);
|
|
3654
3636
|
// Apply all configuration options
|
|
@@ -3662,20 +3644,10 @@ class NileSelectEditor {
|
|
|
3662
3644
|
context.container.appendChild(this.select);
|
|
3663
3645
|
// Focus and auto-open after render
|
|
3664
3646
|
setTimeout(() => {
|
|
3665
|
-
var _a;
|
|
3666
|
-
(_a = this.select) === null || _a === void 0 ? void 0 : _a.focus();
|
|
3667
|
-
// Auto-open the dropdown
|
|
3668
3647
|
if (this.select) {
|
|
3648
|
+
this.select.focus();
|
|
3669
3649
|
this.select.open = true;
|
|
3670
3650
|
}
|
|
3671
|
-
// Clear initializing flag after dropdown has opened
|
|
3672
|
-
setTimeout(() => {
|
|
3673
|
-
this.isInitializing = false;
|
|
3674
|
-
// For multi-select, find the portal div for click detection
|
|
3675
|
-
if (this.options.multiple) {
|
|
3676
|
-
this.portalDiv = document.querySelector('.nile-select-portal-append');
|
|
3677
|
-
}
|
|
3678
|
-
}, 100);
|
|
3679
3651
|
}, 0);
|
|
3680
3652
|
}
|
|
3681
3653
|
/**
|
|
@@ -3759,13 +3731,9 @@ class NileSelectEditor {
|
|
|
3759
3731
|
if (this.options.pill) {
|
|
3760
3732
|
this.select.pill = this.options.pill;
|
|
3761
3733
|
}
|
|
3762
|
-
if (this.options.hoist
|
|
3734
|
+
if (this.options.hoist) {
|
|
3763
3735
|
this.select.hoist = this.options.hoist;
|
|
3764
3736
|
}
|
|
3765
|
-
else {
|
|
3766
|
-
// Default hoist to true for all selects to prevent clipping issues in table cells
|
|
3767
|
-
this.select.hoist = true;
|
|
3768
|
-
}
|
|
3769
3737
|
if (this.options.placement) {
|
|
3770
3738
|
this.select.placement = this.options.placement;
|
|
3771
3739
|
}
|
|
@@ -3775,12 +3743,8 @@ class NileSelectEditor {
|
|
|
3775
3743
|
if (this.options.disableLocalSearch) {
|
|
3776
3744
|
this.select.disableLocalSearch = this.options.disableLocalSearch;
|
|
3777
3745
|
}
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
}
|
|
3781
|
-
else {
|
|
3782
|
-
this.select.portal = true; // Default to portal mode for better positioning
|
|
3783
|
-
}
|
|
3746
|
+
// Enable portal mode by default to prevent dropdown clipping in table cells
|
|
3747
|
+
this.select.portal = this.options.portal !== false;
|
|
3784
3748
|
// Prevent width syncing issues in table cells
|
|
3785
3749
|
this.select.noWidthSync = true;
|
|
3786
3750
|
}
|
|
@@ -3840,31 +3804,6 @@ class NileSelectEditor {
|
|
|
3840
3804
|
if (!this.select)
|
|
3841
3805
|
return;
|
|
3842
3806
|
const validateOnSave = this.options.validateOnSave !== false;
|
|
3843
|
-
// Prevent click events from bubbling up to the cell container
|
|
3844
|
-
const selectClickHandler = (e) => {
|
|
3845
|
-
e.stopPropagation();
|
|
3846
|
-
};
|
|
3847
|
-
this.select.addEventListener('click', selectClickHandler);
|
|
3848
|
-
this.eventListeners.push({ event: 'click', handler: selectClickHandler });
|
|
3849
|
-
// For single-select with portal, listen to document mousedown to detect option selection
|
|
3850
|
-
// Use mousedown because it fires before blur
|
|
3851
|
-
if (!this.options.multiple) {
|
|
3852
|
-
const documentMouseDownHandler = (e) => {
|
|
3853
|
-
var _a, _b;
|
|
3854
|
-
const composedPath = ((_a = e.composedPath) === null || _a === void 0 ? void 0 : _a.call(e)) || [];
|
|
3855
|
-
// Look for nile-option in the event path
|
|
3856
|
-
for (const el of composedPath) {
|
|
3857
|
-
if (el instanceof HTMLElement && ((_b = el.tagName) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === 'nile-option') {
|
|
3858
|
-
const optionValue = el.getAttribute('value') || el.value || '';
|
|
3859
|
-
this.lastSelectedValue = optionValue;
|
|
3860
|
-
return;
|
|
3861
|
-
}
|
|
3862
|
-
}
|
|
3863
|
-
};
|
|
3864
|
-
// Add listener immediately (mousedown fires before blur, so no need for delay)
|
|
3865
|
-
document.addEventListener('mousedown', documentMouseDownHandler, true); // capture phase
|
|
3866
|
-
this.eventListeners.push({ event: 'document-mousedown', handler: documentMouseDownHandler });
|
|
3867
|
-
}
|
|
3868
3807
|
// Handle keyboard events (keydown is not replaced by custom events)
|
|
3869
3808
|
const keydownHandler = (e) => {
|
|
3870
3809
|
const keyEvent = e;
|
|
@@ -3876,46 +3815,56 @@ class NileSelectEditor {
|
|
|
3876
3815
|
};
|
|
3877
3816
|
this.select.addEventListener('keydown', keydownHandler);
|
|
3878
3817
|
this.eventListeners.push({ event: 'keydown', handler: keydownHandler });
|
|
3879
|
-
// Use nile-
|
|
3880
|
-
//
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3818
|
+
// Use nile-change custom event as save trigger - ONLY for single-select
|
|
3819
|
+
// Multi-select should stay open until user clicks outside
|
|
3820
|
+
if (!this.options.multiple) {
|
|
3821
|
+
const changeHandler = (e) => {
|
|
3822
|
+
var _a, _b;
|
|
3823
|
+
const customEvent = e;
|
|
3824
|
+
if (validateOnSave && !((_a = this.select) === null || _a === void 0 ? void 0 : _a.checkValidity())) {
|
|
3825
|
+
(_b = this.select) === null || _b === void 0 ? void 0 : _b.reportValidity();
|
|
3826
|
+
return;
|
|
3827
|
+
}
|
|
3828
|
+
context.onSave(this.parseValue(customEvent.detail.value));
|
|
3829
|
+
};
|
|
3830
|
+
this.select.addEventListener('nile-change', changeHandler);
|
|
3831
|
+
this.eventListeners.push({ event: 'nile-change', handler: changeHandler });
|
|
3832
|
+
}
|
|
3833
|
+
// Track if save was already triggered (to prevent double save)
|
|
3834
|
+
let saveTriggered = false;
|
|
3835
|
+
// Use mousedown on document to detect clicks outside the select and portal
|
|
3836
|
+
const documentMousedownHandler = (e) => {
|
|
3837
|
+
var _a, _b;
|
|
3838
|
+
if (saveTriggered)
|
|
3839
|
+
return;
|
|
3840
|
+
if (!this.select)
|
|
3841
|
+
return;
|
|
3842
|
+
const target = e.target;
|
|
3843
|
+
// Check if click is inside the select element
|
|
3844
|
+
if (this.select.contains(target)) {
|
|
3885
3845
|
return;
|
|
3886
3846
|
}
|
|
3887
|
-
//
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
}
|
|
3900
|
-
// Use lastSelectedValue if available, otherwise get from element
|
|
3901
|
-
const target = e.target;
|
|
3902
|
-
const value = this.lastSelectedValue || (target === null || target === void 0 ? void 0 : target.value) || ((_c = this.select) === null || _c === void 0 ? void 0 : _c.value) || '';
|
|
3903
|
-
this.hasSaved = true;
|
|
3904
|
-
context.onSave(this.parseValue(value));
|
|
3905
|
-
}, 50); // 50ms delay to allow value to update
|
|
3847
|
+
// Check if click is inside any nile-select portal
|
|
3848
|
+
const portals = document.querySelectorAll('.nile-select-portal-append');
|
|
3849
|
+
for (let i = 0; i < portals.length; i++) {
|
|
3850
|
+
if (portals[i].contains(target)) {
|
|
3851
|
+
return;
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
// Click is outside - save and exit
|
|
3855
|
+
saveTriggered = true;
|
|
3856
|
+
if (validateOnSave && !((_a = this.select) === null || _a === void 0 ? void 0 : _a.checkValidity())) {
|
|
3857
|
+
(_b = this.select) === null || _b === void 0 ? void 0 : _b.reportValidity();
|
|
3858
|
+
return;
|
|
3906
3859
|
}
|
|
3860
|
+
context.onSave(this.getCurrentValue());
|
|
3907
3861
|
};
|
|
3908
|
-
//
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
this.
|
|
3914
|
-
// Also listen to change events as fallback
|
|
3915
|
-
this.select.addEventListener('nile-change', singleSelectSaveHandler);
|
|
3916
|
-
this.eventListeners.push({ event: 'nile-change', handler: singleSelectSaveHandler });
|
|
3917
|
-
this.select.addEventListener('change', singleSelectSaveHandler);
|
|
3918
|
-
this.eventListeners.push({ event: 'change', handler: singleSelectSaveHandler });
|
|
3862
|
+
// Add listener after a short delay to avoid capturing the initial click that opened the editor
|
|
3863
|
+
setTimeout(() => {
|
|
3864
|
+
document.addEventListener('mousedown', documentMousedownHandler, true);
|
|
3865
|
+
}, 50);
|
|
3866
|
+
// Store for cleanup
|
|
3867
|
+
this._documentMousedownHandler = documentMousedownHandler;
|
|
3919
3868
|
// Handle clear button if enabled
|
|
3920
3869
|
if (this.options.clearable) {
|
|
3921
3870
|
const clearHandler = (e) => {
|
|
@@ -3934,44 +3883,6 @@ class NileSelectEditor {
|
|
|
3934
3883
|
this.select.addEventListener('nile-search', searchHandler);
|
|
3935
3884
|
this.eventListeners.push({ event: 'nile-search', handler: searchHandler });
|
|
3936
3885
|
}
|
|
3937
|
-
// For multi-select: detect clicks outside portal and select
|
|
3938
|
-
if (this.options.multiple) {
|
|
3939
|
-
const documentClickHandler = (e) => {
|
|
3940
|
-
var _a, _b, _c, _d;
|
|
3941
|
-
const mouseEvent = e;
|
|
3942
|
-
const target = mouseEvent.target;
|
|
3943
|
-
// Check if portal div exists (might take a moment to render)
|
|
3944
|
-
if (!this.portalDiv) {
|
|
3945
|
-
this.portalDiv = document.querySelector('.nile-select-portal-append');
|
|
3946
|
-
}
|
|
3947
|
-
// Determine if click is inside the select or portal
|
|
3948
|
-
const clickedInsideSelect = (_a = this.select) === null || _a === void 0 ? void 0 : _a.contains(target);
|
|
3949
|
-
const clickedInsidePortal = (_b = this.portalDiv) === null || _b === void 0 ? void 0 : _b.contains(target);
|
|
3950
|
-
// If clicked outside both select and portal, save and close
|
|
3951
|
-
if (!clickedInsideSelect && !clickedInsidePortal) {
|
|
3952
|
-
if (validateOnSave && !((_c = this.select) === null || _c === void 0 ? void 0 : _c.checkValidity())) {
|
|
3953
|
-
(_d = this.select) === null || _d === void 0 ? void 0 : _d.reportValidity();
|
|
3954
|
-
return;
|
|
3955
|
-
}
|
|
3956
|
-
context.onSave(this.getCurrentValue());
|
|
3957
|
-
}
|
|
3958
|
-
// Otherwise, click is inside - do nothing (dropdown stays open)
|
|
3959
|
-
};
|
|
3960
|
-
// Delay adding the document click handler to prevent the initial click
|
|
3961
|
-
// (that opened the editor) from immediately triggering it and closing the dropdown
|
|
3962
|
-
// Use 200ms to ensure the dropdown has fully opened
|
|
3963
|
-
setTimeout(() => {
|
|
3964
|
-
// Only add if select still exists (editor not destroyed)
|
|
3965
|
-
if (this.select) {
|
|
3966
|
-
// Use bubbling phase (false) instead of capture to not interfere with nile-select's toggle
|
|
3967
|
-
document.addEventListener('click', documentClickHandler, false);
|
|
3968
|
-
this.eventListeners.push({
|
|
3969
|
-
event: 'document-click',
|
|
3970
|
-
handler: documentClickHandler
|
|
3971
|
-
});
|
|
3972
|
-
}
|
|
3973
|
-
}, 200);
|
|
3974
|
-
}
|
|
3975
3886
|
}
|
|
3976
3887
|
/**
|
|
3977
3888
|
* Parse value based on selection mode
|
|
@@ -3991,36 +3902,25 @@ class NileSelectEditor {
|
|
|
3991
3902
|
return value;
|
|
3992
3903
|
}
|
|
3993
3904
|
destroy() {
|
|
3994
|
-
// Reset flags
|
|
3995
|
-
this.isInitializing = false;
|
|
3996
|
-
this.hasSaved = false;
|
|
3997
|
-
this.lastSelectedValue = '';
|
|
3998
3905
|
// Unsubscribe from options Observable
|
|
3999
3906
|
if (this.optionsSubscription) {
|
|
4000
3907
|
this.optionsSubscription.unsubscribe();
|
|
4001
3908
|
this.optionsSubscription = undefined;
|
|
4002
3909
|
}
|
|
3910
|
+
// Remove document mousedown handler if exists
|
|
3911
|
+
if (this._documentMousedownHandler) {
|
|
3912
|
+
document.removeEventListener('mousedown', this._documentMousedownHandler, true);
|
|
3913
|
+
delete this._documentMousedownHandler;
|
|
3914
|
+
}
|
|
4003
3915
|
// Remove all event listeners
|
|
4004
3916
|
if (this.select) {
|
|
4005
3917
|
this.eventListeners.forEach(({ event, handler }) => {
|
|
4006
3918
|
var _a;
|
|
4007
|
-
|
|
4008
|
-
// Remove from document for multi-select click handler (bubbling phase)
|
|
4009
|
-
document.removeEventListener('click', handler, false);
|
|
4010
|
-
}
|
|
4011
|
-
else if (event === 'document-mousedown') {
|
|
4012
|
-
// Remove from document for single-select option mousedown handler (capture phase)
|
|
4013
|
-
document.removeEventListener('mousedown', handler, true);
|
|
4014
|
-
}
|
|
4015
|
-
else {
|
|
4016
|
-
// Remove from select element
|
|
4017
|
-
(_a = this.select) === null || _a === void 0 ? void 0 : _a.removeEventListener(event, handler);
|
|
4018
|
-
}
|
|
3919
|
+
(_a = this.select) === null || _a === void 0 ? void 0 : _a.removeEventListener(event, handler);
|
|
4019
3920
|
});
|
|
4020
3921
|
this.eventListeners = [];
|
|
4021
3922
|
this.select.remove();
|
|
4022
3923
|
this.select = undefined;
|
|
4023
|
-
this.portalDiv = undefined; // Clean up portal reference
|
|
4024
3924
|
}
|
|
4025
3925
|
}
|
|
4026
3926
|
focus() {
|
|
@@ -4040,7 +3940,6 @@ class NileSelectEditor {
|
|
|
4040
3940
|
return (Array.isArray(value) ? (value.length > 0 ? value[0] : '') : value);
|
|
4041
3941
|
}
|
|
4042
3942
|
}
|
|
4043
|
-
NileSelectEditor.stylesInjected = false;
|
|
4044
3943
|
|
|
4045
3944
|
/**
|
|
4046
3945
|
* Custom editor using NileAutoComplete from @aquera/nile-elements
|
|
@@ -8784,6 +8683,15 @@ class StTableComponent {
|
|
|
8784
8683
|
// Use setTimeout to ensure DOM has updated
|
|
8785
8684
|
setTimeout(() => {
|
|
8786
8685
|
var _a;
|
|
8686
|
+
// Don't steal focus from editors - if a cell is being edited,
|
|
8687
|
+
// the editor should keep focus
|
|
8688
|
+
const editingPosition = this.getActiveTableState().getEditingPosition();
|
|
8689
|
+
if (editingPosition &&
|
|
8690
|
+
editingPosition.rowIndex === rowIndex &&
|
|
8691
|
+
editingPosition.columnIndex === colIndex) {
|
|
8692
|
+
// Cell is being edited, don't steal focus from the editor
|
|
8693
|
+
return;
|
|
8694
|
+
}
|
|
8787
8695
|
// Use absolute row index for virtual scroll compatibility
|
|
8788
8696
|
const absoluteRowIndex = this.getAbsoluteRowIndex(rowIndex);
|
|
8789
8697
|
// Query within this component's host element to avoid selecting rows from other tables
|
|
@@ -9044,11 +8952,27 @@ class StTableComponent {
|
|
|
9044
8952
|
* Clear focus when clicking outside table
|
|
9045
8953
|
*/
|
|
9046
8954
|
onDocumentClick(event) {
|
|
8955
|
+
var _a;
|
|
9047
8956
|
if (!this.isKeyboardNavigationEnabled())
|
|
9048
8957
|
return;
|
|
9049
8958
|
const target = event.target;
|
|
9050
8959
|
const tableElement = target.closest('.st-table');
|
|
9051
|
-
if (
|
|
8960
|
+
// Also check if click is inside a portal (e.g., nile-select dropdown)
|
|
8961
|
+
// These are rendered outside the table but are part of the editing experience
|
|
8962
|
+
const portalElement = target.closest('.nile-select-portal-append');
|
|
8963
|
+
// Check composedPath for shadow DOM elements (e.g., nile-option, nile-input inside shadow root)
|
|
8964
|
+
const composedPath = ((_a = event.composedPath) === null || _a === void 0 ? void 0 : _a.call(event)) || [];
|
|
8965
|
+
const isInsideNileElement = composedPath.some((el) => {
|
|
8966
|
+
var _a, _b;
|
|
8967
|
+
if (el instanceof HTMLElement) {
|
|
8968
|
+
const tagName = (_a = el.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
8969
|
+
// Check for any nile-* custom elements used in editors
|
|
8970
|
+
return (tagName === null || tagName === void 0 ? void 0 : tagName.startsWith('nile-')) ||
|
|
8971
|
+
((_b = el.classList) === null || _b === void 0 ? void 0 : _b.contains('nile-select-portal-append'));
|
|
8972
|
+
}
|
|
8973
|
+
return false;
|
|
8974
|
+
});
|
|
8975
|
+
if (!tableElement && !portalElement && !isInsideNileElement) {
|
|
9052
8976
|
this.getActiveTableState().clearFocus();
|
|
9053
8977
|
this.getActiveTableState().clearEditingCell();
|
|
9054
8978
|
}
|
|
@@ -10016,9 +9940,13 @@ class StWorkbookComponent {
|
|
|
10016
9940
|
this.workbookActionsOpen = false;
|
|
10017
9941
|
this.workbookActionsPosition = {};
|
|
10018
9942
|
/**
|
|
10019
|
-
* Visible workbook actions (filtered by hidden)
|
|
9943
|
+
* Visible workbook actions for dropdown (filtered by hidden and showInToolbar)
|
|
10020
9944
|
*/
|
|
10021
9945
|
this.visibleWorkbookActions = [];
|
|
9946
|
+
/**
|
|
9947
|
+
* Workbook actions to show directly in toolbar
|
|
9948
|
+
*/
|
|
9949
|
+
this.toolbarWorkbookActions = [];
|
|
10022
9950
|
/**
|
|
10023
9951
|
* Destroy subject for cleanup
|
|
10024
9952
|
*/
|
|
@@ -10259,14 +10187,18 @@ class StWorkbookComponent {
|
|
|
10259
10187
|
updateVisibleWorkbookActions() {
|
|
10260
10188
|
if (!this.config.workbookActions) {
|
|
10261
10189
|
this.visibleWorkbookActions = [];
|
|
10190
|
+
this.toolbarWorkbookActions = [];
|
|
10262
10191
|
return;
|
|
10263
10192
|
}
|
|
10264
|
-
|
|
10193
|
+
const visibleActions = this.config.workbookActions.filter(action => {
|
|
10265
10194
|
if (typeof action.hidden === 'function') {
|
|
10266
10195
|
return !action.hidden();
|
|
10267
10196
|
}
|
|
10268
10197
|
return !action.hidden;
|
|
10269
10198
|
});
|
|
10199
|
+
// Separate toolbar actions from dropdown actions
|
|
10200
|
+
this.toolbarWorkbookActions = visibleActions.filter(action => action.showInToolbar === true);
|
|
10201
|
+
this.visibleWorkbookActions = visibleActions.filter(action => action.showInToolbar !== true);
|
|
10270
10202
|
}
|
|
10271
10203
|
/**
|
|
10272
10204
|
* Check if workbook action is disabled
|
|
@@ -10463,10 +10395,10 @@ class StWorkbookComponent {
|
|
|
10463
10395
|
}
|
|
10464
10396
|
}
|
|
10465
10397
|
StWorkbookComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StWorkbookComponent, deps: [{ token: AutosaveService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
10466
|
-
StWorkbookComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StWorkbookComponent, selector: "st-workbook", inputs: { config: "config", sheetsData: "sheetsData", state: "state" }, outputs: { sheetChanged: "sheetChanged", addSheet: "addSheet", sheetTabAction: "sheetTabAction", workbookAction: "workbookAction", cellChange: "cellChange", cellSave: "cellSave", tableStateChange: "tableStateChange", fullscreenToggle: "fullscreenToggle", requestAddRow: "requestAddRow" }, viewQueries: [{ propertyName: "tableComponent", first: true, predicate: StTableComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"workbook-container\" [class.fullscreen]=\"isFullscreen$ | async\">\n <nile-tab-group [activeIndex]=\"activeSheetIndex\">\n \n <!-- Sheet Tabs (one per sheet) -->\n <nile-tab *ngFor=\"let sheet of sheets; let i = index\"\n slot=\"nav\" \n panel=\"shared-panel\"\n [class.active]=\"i === activeSheetIndex\"\n (click)=\"onTabChange(i)\">\n <div class=\"sheet-tab-content\">\n <span class=\"sheet-name\">{{ sheet.name }}</span>\n \n <!-- Tab actions dropdown button -->\n <button class=\"tab-actions-button\"\n (click)=\"openTabActions($event, sheet, i)\"\n *ngIf=\"hasTabActions(sheet)\">\n <nile-icon name=\"arrowdown\" size=\"14\"></nile-icon>\n </button>\n </div>\n </nile-tab>\n \n <!-- Toolbar Tab (for workbook controls) -->\n <nile-tab slot=\"nav\" \n panel=\"shared-panel\"\n class=\"workbook-toolbar-tab\"\n [disabled]=\"true\">\n <div class=\"workbook-toolbar-content\">\n <!-- Autosave Indicator -->\n <div class=\"autosave-indicator\" *ngIf=\"autosaveEnabled\">\n <nile-icon \n *ngIf=\"!isSaving && lastSaveTime\" \n name=\"save\" \n size=\"14\"\n [title]=\"'Saved at ' + (lastSaveTime | date:'HH:mm:ss')\">\n </nile-icon>\n <nile-icon \n *ngIf=\"isSaving\" \n name=\"loader\" \n size=\"14\"\n title=\"Saving...\">\n </nile-icon>\n </div>\n\n <!-- Workbook Actions Dropdown -->\n <button class=\"workbook-actions-button\"\n *ngIf=\"config.workbookActions && config.workbookActions.length > 0\"\n (click)=\"toggleWorkbookActions($event)\"\n title=\"Workbook Actions\">\n <nile-icon name=\"settings\"></nile-icon>\n </button>\n \n <!-- Add Sheet Button -->\n <button class=\"add-sheet-button\"\n *ngIf=\"canAddSheet\"\n (click)=\"onAddSheet()\"\n title=\"Add Sheet\">\n <nile-icon name=\"plus\"></nile-icon>\n </button>\n \n <!-- Fullscreen Button -->\n <button class=\"fullscreen-button\"\n *ngIf=\"config.display?.allowFullscreen !== false\"\n (click)=\"toggleFullscreen()\"\n [title]=\"(isFullscreen$ | async) ? 'Exit Fullscreen' : 'Fullscreen'\">\n <nile-icon [name]=\"(isFullscreen$ | async) ? 'collapse' : 'expand-06'\"></nile-icon>\n </button>\n </div>\n </nile-tab>\n \n <!-- Single Shared Tab Panel -->\n <nile-tab-panel name=\"shared-panel\">\n <!-- Lazy loading strategy: table is destroyed and recreated with new config/state when sheet changes -->\n <!-- Using ngFor with trackBy to force complete reinitialization when tableComponentKey changes -->\n <ng-container *ngFor=\"let key of [tableComponentKey]; trackBy: trackByKey\">\n <st-table *ngIf=\"currentTableConfig && currentTableState\"\n [attr.data-sheet-key]=\"key\"\n [tableConfig]=\"currentTableConfig\"\n [data$]=\"currentTableData$\"\n [tableState]=\"currentTableState\"\n (cellChange)=\"onCellChange($event)\"\n (cellSave)=\"onCellSave($event)\"\n (stateChange)=\"onTableStateChange($event)\"\n (requestAddRow)=\"onRequestAddRow($event)\">\n </st-table>\n </ng-container>\n </nile-tab-panel>\n \n </nile-tab-group>\n</div>\n\n<!-- Tab Actions Dropdown -->\n<div class=\"tab-actions-dropdown\" \n *ngIf=\"tabActionsOpen\"\n [ngStyle]=\"tabActionsPosition\">\n <div class=\"dropdown-backdrop\" (click)=\"closeTabActions()\"></div>\n <div class=\"dropdown-menu\">\n <nile-menu>\n <nile-menu-item *ngFor=\"let action of selectedSheet?.tabActions\" \n (click)=\"onTabActionClick(action, $event)\">\n <nile-icon *ngIf=\"action.icon\" slot=\"prefix\" size=\"14\" [name]=\"action.icon\"></nile-icon>\n {{ action.label }}\n </nile-menu-item>\n </nile-menu>\n </div>\n</div>\n\n<!-- Workbook Actions Dropdown -->\n<div class=\"workbook-actions-dropdown\"\n *ngIf=\"workbookActionsOpen\"\n [ngStyle]=\"workbookActionsPosition\">\n <div class=\"dropdown-backdrop\" (click)=\"closeWorkbookActions()\"></div>\n <div class=\"dropdown-menu\">\n <nile-menu>\n <nile-menu-item *ngFor=\"let action of visibleWorkbookActions\"\n [class.disabled]=\"isActionDisabled(action)\"\n (click)=\"onWorkbookActionClick(action, $event)\">\n <nile-icon *ngIf=\"action.icon\" slot=\"prefix\" size=\"14\" [name]=\"action.icon\"></nile-icon>\n {{ action.label }}\n </nile-menu-item>\n </nile-menu>\n </div>\n</div>\n\n<!-- Fullscreen Backdrop -->\n<div class=\"fullscreen-backdrop\" \n *ngIf=\"isFullscreen$ | async\"\n (click)=\"toggleFullscreen()\">\n</div>\n\n", styles: ["@import\"@aquera/nile/lib/styles/variables.css\";:host{display:block;width:100%;height:100%}.workbook-container{display:flex;flex-direction:column;height:100%;background:white;border:1px solid var(--nile-color-neutral-200);border-radius:4px;overflow:hidden}.workbook-container.fullscreen{position:fixed;inset:0;z-index:2000;border:none;border-radius:0}.workbook-container nile-tab-group{height:100%;display:flex;flex-direction:column}.sheet-tab-content{display:flex;align-items:center;gap:8px;padding:0 4px}.sheet-tab-content .sheet-name{font-size:12px;font-weight:500;font-family:var(--nile-font-family-sans-serif);color:#000}.sheet-tab-content .tab-actions-button{width:20px;height:20px;padding:0;background:transparent;border:none;cursor:pointer}.workbook-toolbar-tab{margin-left:auto!important;pointer-events:auto!important;border-left:1px solid var(--nile-color-neutral-200)}.workbook-toolbar-tab .workbook-toolbar-content{display:flex;gap:4px;align-items:center;padding:0 8px}.workbook-toolbar-tab .workbook-toolbar-content .autosave-indicator{display:flex;align-items:center;margin-right:8px;color:var(--nile-color-success-500)}.workbook-toolbar-tab button{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;background:transparent;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s;color:var(--nile-color-neutral-600)}.workbook-toolbar-tab button:hover{background-color:var(--nile-color-neutral-100);color:var(--nile-color-neutral-900)}.workbook-toolbar-tab button:active{background-color:var(--nile-color-neutral-200)}.workbook-toolbar-tab button nile-icon{font-size:16px}.tab-actions-dropdown{position:fixed;z-index:1001}.tab-actions-dropdown .dropdown-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:transparent;z-index:1000}.tab-actions-dropdown .dropdown-menu{position:relative;min-width:180px;background:white;border-radius:8px;box-shadow:0 4px 12px #00000026;z-index:1001;overflow:hidden}.tab-actions-dropdown .dropdown-menu nile-menu{display:block}.workbook-actions-dropdown{position:fixed;z-index:1001}.workbook-actions-dropdown .dropdown-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:transparent;z-index:1000}.workbook-actions-dropdown .dropdown-menu{position:relative;min-width:200px;background:white;border-radius:8px;box-shadow:0 4px 12px #00000026;z-index:1001;overflow:hidden}.workbook-actions-dropdown .dropdown-menu nile-menu{display:block}.fullscreen-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:1999;cursor:pointer}nile-tab-group::part(nav){background-color:#fafafa}nile-tab-group::part(active-tab-indicator-path){background:none}nile-tab-group::part(active-tab-indicator){border-bottom:none}nile-tab-group::part(tabs){gap:0}nile-tab-group nile-tab{border:1px solid #e0e0e0;border-top-left-radius:6px;border-top-right-radius:6px}nile-tab-group nile-tab::part(base){padding-left:.5rem;padding-top:.5rem;padding-bottom:.5rem;border-bottom-left-radius:0;border-bottom-right-radius:0}nile-tab-group nile-tab.active{background-color:#fff;color:#000}nile-tab-group nile-tab.active .sheet-name{font-weight:600}nile-tab-group nile-tab-panel::part(base){padding:0;max-height:30rem}\n"], components: [{ type: StTableComponent, selector: "st-table", inputs: ["tableConfig", "data", "data$", "tableState", "enableSorting", "enableFiltering", "validateConfig"], outputs: ["stateChange", "dataChange", "cellEdit", "cellSave", "cellCancel", "cellChange", "columnResized", "columnMoved", "configValidationErrors", "columnAdded", "rowAction", "validationStateChange", "requestAddRow"] }], directives: [{ type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], pipes: { "async": i1.AsyncPipe, "date": i1.DatePipe } });
|
|
10398
|
+
StWorkbookComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StWorkbookComponent, selector: "st-workbook", inputs: { config: "config", sheetsData: "sheetsData", state: "state" }, outputs: { sheetChanged: "sheetChanged", addSheet: "addSheet", sheetTabAction: "sheetTabAction", workbookAction: "workbookAction", cellChange: "cellChange", cellSave: "cellSave", tableStateChange: "tableStateChange", fullscreenToggle: "fullscreenToggle", requestAddRow: "requestAddRow" }, viewQueries: [{ propertyName: "tableComponent", first: true, predicate: StTableComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"workbook-container\" [class.fullscreen]=\"isFullscreen$ | async\">\n <nile-tab-group [activeIndex]=\"activeSheetIndex\">\n \n <!-- Sheet Tabs (one per sheet) -->\n <nile-tab *ngFor=\"let sheet of sheets; let i = index\"\n slot=\"nav\" \n panel=\"shared-panel\"\n [class.active]=\"i === activeSheetIndex\"\n (click)=\"onTabChange(i)\">\n <div class=\"sheet-tab-content\">\n <span class=\"sheet-name\">{{ sheet.name }}</span>\n \n <!-- Tab actions dropdown button -->\n <button class=\"tab-actions-button\"\n (click)=\"openTabActions($event, sheet, i)\"\n *ngIf=\"hasTabActions(sheet)\">\n <nile-icon name=\"arrowdown\" size=\"14\"></nile-icon>\n </button>\n </div>\n </nile-tab>\n \n <!-- Toolbar Tab (for workbook controls) -->\n <nile-tab slot=\"nav\" \n panel=\"shared-panel\"\n class=\"workbook-toolbar-tab\"\n [disabled]=\"true\">\n <div class=\"workbook-toolbar-content\">\n <!-- Autosave Indicator -->\n <div class=\"autosave-indicator\" *ngIf=\"autosaveEnabled\">\n <nile-icon \n *ngIf=\"!isSaving && lastSaveTime\" \n name=\"save\" \n size=\"14\"\n [title]=\"'Saved at ' + (lastSaveTime | date:'HH:mm:ss')\">\n </nile-icon>\n <nile-icon \n *ngIf=\"isSaving\" \n name=\"loader\" \n size=\"14\"\n title=\"Saving...\">\n </nile-icon>\n </div>\n\n <!-- Toolbar Workbook Actions (shown as individual buttons) -->\n <button *ngFor=\"let action of toolbarWorkbookActions\"\n class=\"toolbar-action-button\"\n [class.disabled]=\"isActionDisabled(action)\"\n [title]=\"action.label\"\n (click)=\"onWorkbookActionClick(action, $event)\">\n <nile-icon *ngIf=\"action.icon\" [name]=\"action.icon\"></nile-icon>\n <span *ngIf=\"!action.icon\">{{ action.label }}</span>\n </button>\n\n <!-- Workbook Actions Dropdown -->\n <button class=\"workbook-actions-button\"\n *ngIf=\"visibleWorkbookActions.length > 0\"\n (click)=\"toggleWorkbookActions($event)\"\n title=\"Workbook Actions\">\n <nile-icon name=\"settings\"></nile-icon>\n </button>\n \n <!-- Add Sheet Button -->\n <button class=\"add-sheet-button\"\n *ngIf=\"canAddSheet\"\n (click)=\"onAddSheet()\"\n title=\"Add Sheet\">\n <nile-icon name=\"plus\"></nile-icon>\n </button>\n \n <!-- Fullscreen Button -->\n <button class=\"fullscreen-button\"\n *ngIf=\"config.display?.allowFullscreen !== false\"\n (click)=\"toggleFullscreen()\"\n [title]=\"(isFullscreen$ | async) ? 'Exit Fullscreen' : 'Fullscreen'\">\n <nile-icon [name]=\"(isFullscreen$ | async) ? 'collapse' : 'expand-06'\"></nile-icon>\n </button>\n </div>\n </nile-tab>\n \n <!-- Single Shared Tab Panel -->\n <nile-tab-panel name=\"shared-panel\">\n <!-- Lazy loading strategy: table is destroyed and recreated with new config/state when sheet changes -->\n <!-- Using ngFor with trackBy to force complete reinitialization when tableComponentKey changes -->\n <ng-container *ngFor=\"let key of [tableComponentKey]; trackBy: trackByKey\">\n <st-table *ngIf=\"currentTableConfig && currentTableState\"\n [attr.data-sheet-key]=\"key\"\n [tableConfig]=\"currentTableConfig\"\n [data$]=\"currentTableData$\"\n [tableState]=\"currentTableState\"\n (cellChange)=\"onCellChange($event)\"\n (cellSave)=\"onCellSave($event)\"\n (stateChange)=\"onTableStateChange($event)\"\n (requestAddRow)=\"onRequestAddRow($event)\">\n </st-table>\n </ng-container>\n </nile-tab-panel>\n \n </nile-tab-group>\n</div>\n\n<!-- Tab Actions Dropdown -->\n<div class=\"tab-actions-dropdown\" \n *ngIf=\"tabActionsOpen\"\n [ngStyle]=\"tabActionsPosition\">\n <div class=\"dropdown-backdrop\" (click)=\"closeTabActions()\"></div>\n <div class=\"dropdown-menu\">\n <nile-menu>\n <nile-menu-item *ngFor=\"let action of selectedSheet?.tabActions\" \n (click)=\"onTabActionClick(action, $event)\">\n <nile-icon *ngIf=\"action.icon\" slot=\"prefix\" size=\"14\" [name]=\"action.icon\"></nile-icon>\n {{ action.label }}\n </nile-menu-item>\n </nile-menu>\n </div>\n</div>\n\n<!-- Workbook Actions Dropdown -->\n<div class=\"workbook-actions-dropdown\"\n *ngIf=\"workbookActionsOpen\"\n [ngStyle]=\"workbookActionsPosition\">\n <div class=\"dropdown-backdrop\" (click)=\"closeWorkbookActions()\"></div>\n <div class=\"dropdown-menu\">\n <nile-menu>\n <nile-menu-item *ngFor=\"let action of visibleWorkbookActions\"\n [class.disabled]=\"isActionDisabled(action)\"\n (click)=\"onWorkbookActionClick(action, $event)\">\n <nile-icon *ngIf=\"action.icon\" slot=\"prefix\" size=\"14\" [name]=\"action.icon\"></nile-icon>\n {{ action.label }}\n </nile-menu-item>\n </nile-menu>\n </div>\n</div>\n\n<!-- Fullscreen Backdrop -->\n<div class=\"fullscreen-backdrop\" \n *ngIf=\"isFullscreen$ | async\"\n (click)=\"toggleFullscreen()\">\n</div>\n\n", styles: ["@import\"@aquera/nile/lib/styles/variables.css\";:host{display:block;width:100%;height:100%}.workbook-container{display:flex;flex-direction:column;height:100%;background:white;border:1px solid var(--nile-color-neutral-200);border-radius:4px;overflow:hidden}.workbook-container.fullscreen{position:fixed;inset:0;z-index:2000;border:none;border-radius:0}.workbook-container nile-tab-group{height:100%;display:flex;flex-direction:column}.sheet-tab-content{display:flex;align-items:center;gap:8px;padding:0 4px}.sheet-tab-content .sheet-name{font-size:12px;font-weight:500;font-family:var(--nile-font-family-sans-serif);color:#000}.sheet-tab-content .tab-actions-button{width:20px;height:20px;padding:0;background:transparent;border:none;cursor:pointer}.workbook-toolbar-tab{margin-left:auto!important;pointer-events:auto!important;border-left:1px solid var(--nile-color-neutral-200)}.workbook-toolbar-tab .workbook-toolbar-content{display:flex;gap:4px;align-items:center;padding:0 8px}.workbook-toolbar-tab .workbook-toolbar-content .autosave-indicator{display:flex;align-items:center;margin-right:8px;color:var(--nile-color-success-500)}.workbook-toolbar-tab button{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;background:transparent;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s;color:var(--nile-color-neutral-600)}.workbook-toolbar-tab button:hover{background-color:var(--nile-color-neutral-100);color:var(--nile-color-neutral-900)}.workbook-toolbar-tab button:active{background-color:var(--nile-color-neutral-200)}.workbook-toolbar-tab button nile-icon{font-size:16px}.workbook-toolbar-tab button.disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tab-actions-dropdown{position:fixed;z-index:1001}.tab-actions-dropdown .dropdown-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:transparent;z-index:1000}.tab-actions-dropdown .dropdown-menu{position:relative;min-width:180px;background:white;border-radius:8px;box-shadow:0 4px 12px #00000026;z-index:1001;overflow:hidden}.tab-actions-dropdown .dropdown-menu nile-menu{display:block}.workbook-actions-dropdown{position:fixed;z-index:1001}.workbook-actions-dropdown .dropdown-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:transparent;z-index:1000}.workbook-actions-dropdown .dropdown-menu{position:relative;min-width:200px;background:white;border-radius:8px;box-shadow:0 4px 12px #00000026;z-index:1001;overflow:hidden}.workbook-actions-dropdown .dropdown-menu nile-menu{display:block}.fullscreen-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:1999;cursor:pointer}nile-tab-group::part(nav){background-color:#fafafa}nile-tab-group::part(active-tab-indicator-path){background:none}nile-tab-group::part(active-tab-indicator){border-bottom:none}nile-tab-group::part(tabs){gap:0}nile-tab-group nile-tab{border:1px solid #e0e0e0;border-top-left-radius:6px;border-top-right-radius:6px}nile-tab-group nile-tab::part(base){padding-left:.5rem;padding-top:.5rem;padding-bottom:.5rem;border-bottom-left-radius:0;border-bottom-right-radius:0}nile-tab-group nile-tab.active{background-color:#fff;color:#000}nile-tab-group nile-tab.active .sheet-name{font-weight:600}nile-tab-group nile-tab-panel::part(base){padding:0;max-height:30rem}\n"], components: [{ type: StTableComponent, selector: "st-table", inputs: ["tableConfig", "data", "data$", "tableState", "enableSorting", "enableFiltering", "validateConfig"], outputs: ["stateChange", "dataChange", "cellEdit", "cellSave", "cellCancel", "cellChange", "columnResized", "columnMoved", "configValidationErrors", "columnAdded", "rowAction", "validationStateChange", "requestAddRow"] }], directives: [{ type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], pipes: { "async": i1.AsyncPipe, "date": i1.DatePipe } });
|
|
10467
10399
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StWorkbookComponent, decorators: [{
|
|
10468
10400
|
type: Component,
|
|
10469
|
-
args: [{ selector: 'st-workbook', template: "<div class=\"workbook-container\" [class.fullscreen]=\"isFullscreen$ | async\">\n <nile-tab-group [activeIndex]=\"activeSheetIndex\">\n \n <!-- Sheet Tabs (one per sheet) -->\n <nile-tab *ngFor=\"let sheet of sheets; let i = index\"\n slot=\"nav\" \n panel=\"shared-panel\"\n [class.active]=\"i === activeSheetIndex\"\n (click)=\"onTabChange(i)\">\n <div class=\"sheet-tab-content\">\n <span class=\"sheet-name\">{{ sheet.name }}</span>\n \n <!-- Tab actions dropdown button -->\n <button class=\"tab-actions-button\"\n (click)=\"openTabActions($event, sheet, i)\"\n *ngIf=\"hasTabActions(sheet)\">\n <nile-icon name=\"arrowdown\" size=\"14\"></nile-icon>\n </button>\n </div>\n </nile-tab>\n \n <!-- Toolbar Tab (for workbook controls) -->\n <nile-tab slot=\"nav\" \n panel=\"shared-panel\"\n class=\"workbook-toolbar-tab\"\n [disabled]=\"true\">\n <div class=\"workbook-toolbar-content\">\n <!-- Autosave Indicator -->\n <div class=\"autosave-indicator\" *ngIf=\"autosaveEnabled\">\n <nile-icon \n *ngIf=\"!isSaving && lastSaveTime\" \n name=\"save\" \n size=\"14\"\n [title]=\"'Saved at ' + (lastSaveTime | date:'HH:mm:ss')\">\n </nile-icon>\n <nile-icon \n *ngIf=\"isSaving\" \n name=\"loader\" \n size=\"14\"\n title=\"Saving...\">\n </nile-icon>\n </div>\n\n <!-- Workbook Actions
|
|
10401
|
+
args: [{ selector: 'st-workbook', template: "<div class=\"workbook-container\" [class.fullscreen]=\"isFullscreen$ | async\">\n <nile-tab-group [activeIndex]=\"activeSheetIndex\">\n \n <!-- Sheet Tabs (one per sheet) -->\n <nile-tab *ngFor=\"let sheet of sheets; let i = index\"\n slot=\"nav\" \n panel=\"shared-panel\"\n [class.active]=\"i === activeSheetIndex\"\n (click)=\"onTabChange(i)\">\n <div class=\"sheet-tab-content\">\n <span class=\"sheet-name\">{{ sheet.name }}</span>\n \n <!-- Tab actions dropdown button -->\n <button class=\"tab-actions-button\"\n (click)=\"openTabActions($event, sheet, i)\"\n *ngIf=\"hasTabActions(sheet)\">\n <nile-icon name=\"arrowdown\" size=\"14\"></nile-icon>\n </button>\n </div>\n </nile-tab>\n \n <!-- Toolbar Tab (for workbook controls) -->\n <nile-tab slot=\"nav\" \n panel=\"shared-panel\"\n class=\"workbook-toolbar-tab\"\n [disabled]=\"true\">\n <div class=\"workbook-toolbar-content\">\n <!-- Autosave Indicator -->\n <div class=\"autosave-indicator\" *ngIf=\"autosaveEnabled\">\n <nile-icon \n *ngIf=\"!isSaving && lastSaveTime\" \n name=\"save\" \n size=\"14\"\n [title]=\"'Saved at ' + (lastSaveTime | date:'HH:mm:ss')\">\n </nile-icon>\n <nile-icon \n *ngIf=\"isSaving\" \n name=\"loader\" \n size=\"14\"\n title=\"Saving...\">\n </nile-icon>\n </div>\n\n <!-- Toolbar Workbook Actions (shown as individual buttons) -->\n <button *ngFor=\"let action of toolbarWorkbookActions\"\n class=\"toolbar-action-button\"\n [class.disabled]=\"isActionDisabled(action)\"\n [title]=\"action.label\"\n (click)=\"onWorkbookActionClick(action, $event)\">\n <nile-icon *ngIf=\"action.icon\" [name]=\"action.icon\"></nile-icon>\n <span *ngIf=\"!action.icon\">{{ action.label }}</span>\n </button>\n\n <!-- Workbook Actions Dropdown -->\n <button class=\"workbook-actions-button\"\n *ngIf=\"visibleWorkbookActions.length > 0\"\n (click)=\"toggleWorkbookActions($event)\"\n title=\"Workbook Actions\">\n <nile-icon name=\"settings\"></nile-icon>\n </button>\n \n <!-- Add Sheet Button -->\n <button class=\"add-sheet-button\"\n *ngIf=\"canAddSheet\"\n (click)=\"onAddSheet()\"\n title=\"Add Sheet\">\n <nile-icon name=\"plus\"></nile-icon>\n </button>\n \n <!-- Fullscreen Button -->\n <button class=\"fullscreen-button\"\n *ngIf=\"config.display?.allowFullscreen !== false\"\n (click)=\"toggleFullscreen()\"\n [title]=\"(isFullscreen$ | async) ? 'Exit Fullscreen' : 'Fullscreen'\">\n <nile-icon [name]=\"(isFullscreen$ | async) ? 'collapse' : 'expand-06'\"></nile-icon>\n </button>\n </div>\n </nile-tab>\n \n <!-- Single Shared Tab Panel -->\n <nile-tab-panel name=\"shared-panel\">\n <!-- Lazy loading strategy: table is destroyed and recreated with new config/state when sheet changes -->\n <!-- Using ngFor with trackBy to force complete reinitialization when tableComponentKey changes -->\n <ng-container *ngFor=\"let key of [tableComponentKey]; trackBy: trackByKey\">\n <st-table *ngIf=\"currentTableConfig && currentTableState\"\n [attr.data-sheet-key]=\"key\"\n [tableConfig]=\"currentTableConfig\"\n [data$]=\"currentTableData$\"\n [tableState]=\"currentTableState\"\n (cellChange)=\"onCellChange($event)\"\n (cellSave)=\"onCellSave($event)\"\n (stateChange)=\"onTableStateChange($event)\"\n (requestAddRow)=\"onRequestAddRow($event)\">\n </st-table>\n </ng-container>\n </nile-tab-panel>\n \n </nile-tab-group>\n</div>\n\n<!-- Tab Actions Dropdown -->\n<div class=\"tab-actions-dropdown\" \n *ngIf=\"tabActionsOpen\"\n [ngStyle]=\"tabActionsPosition\">\n <div class=\"dropdown-backdrop\" (click)=\"closeTabActions()\"></div>\n <div class=\"dropdown-menu\">\n <nile-menu>\n <nile-menu-item *ngFor=\"let action of selectedSheet?.tabActions\" \n (click)=\"onTabActionClick(action, $event)\">\n <nile-icon *ngIf=\"action.icon\" slot=\"prefix\" size=\"14\" [name]=\"action.icon\"></nile-icon>\n {{ action.label }}\n </nile-menu-item>\n </nile-menu>\n </div>\n</div>\n\n<!-- Workbook Actions Dropdown -->\n<div class=\"workbook-actions-dropdown\"\n *ngIf=\"workbookActionsOpen\"\n [ngStyle]=\"workbookActionsPosition\">\n <div class=\"dropdown-backdrop\" (click)=\"closeWorkbookActions()\"></div>\n <div class=\"dropdown-menu\">\n <nile-menu>\n <nile-menu-item *ngFor=\"let action of visibleWorkbookActions\"\n [class.disabled]=\"isActionDisabled(action)\"\n (click)=\"onWorkbookActionClick(action, $event)\">\n <nile-icon *ngIf=\"action.icon\" slot=\"prefix\" size=\"14\" [name]=\"action.icon\"></nile-icon>\n {{ action.label }}\n </nile-menu-item>\n </nile-menu>\n </div>\n</div>\n\n<!-- Fullscreen Backdrop -->\n<div class=\"fullscreen-backdrop\" \n *ngIf=\"isFullscreen$ | async\"\n (click)=\"toggleFullscreen()\">\n</div>\n\n", styles: ["@import\"@aquera/nile/lib/styles/variables.css\";:host{display:block;width:100%;height:100%}.workbook-container{display:flex;flex-direction:column;height:100%;background:white;border:1px solid var(--nile-color-neutral-200);border-radius:4px;overflow:hidden}.workbook-container.fullscreen{position:fixed;inset:0;z-index:2000;border:none;border-radius:0}.workbook-container nile-tab-group{height:100%;display:flex;flex-direction:column}.sheet-tab-content{display:flex;align-items:center;gap:8px;padding:0 4px}.sheet-tab-content .sheet-name{font-size:12px;font-weight:500;font-family:var(--nile-font-family-sans-serif);color:#000}.sheet-tab-content .tab-actions-button{width:20px;height:20px;padding:0;background:transparent;border:none;cursor:pointer}.workbook-toolbar-tab{margin-left:auto!important;pointer-events:auto!important;border-left:1px solid var(--nile-color-neutral-200)}.workbook-toolbar-tab .workbook-toolbar-content{display:flex;gap:4px;align-items:center;padding:0 8px}.workbook-toolbar-tab .workbook-toolbar-content .autosave-indicator{display:flex;align-items:center;margin-right:8px;color:var(--nile-color-success-500)}.workbook-toolbar-tab button{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;background:transparent;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s;color:var(--nile-color-neutral-600)}.workbook-toolbar-tab button:hover{background-color:var(--nile-color-neutral-100);color:var(--nile-color-neutral-900)}.workbook-toolbar-tab button:active{background-color:var(--nile-color-neutral-200)}.workbook-toolbar-tab button nile-icon{font-size:16px}.workbook-toolbar-tab button.disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tab-actions-dropdown{position:fixed;z-index:1001}.tab-actions-dropdown .dropdown-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:transparent;z-index:1000}.tab-actions-dropdown .dropdown-menu{position:relative;min-width:180px;background:white;border-radius:8px;box-shadow:0 4px 12px #00000026;z-index:1001;overflow:hidden}.tab-actions-dropdown .dropdown-menu nile-menu{display:block}.workbook-actions-dropdown{position:fixed;z-index:1001}.workbook-actions-dropdown .dropdown-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:transparent;z-index:1000}.workbook-actions-dropdown .dropdown-menu{position:relative;min-width:200px;background:white;border-radius:8px;box-shadow:0 4px 12px #00000026;z-index:1001;overflow:hidden}.workbook-actions-dropdown .dropdown-menu nile-menu{display:block}.fullscreen-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:1999;cursor:pointer}nile-tab-group::part(nav){background-color:#fafafa}nile-tab-group::part(active-tab-indicator-path){background:none}nile-tab-group::part(active-tab-indicator){border-bottom:none}nile-tab-group::part(tabs){gap:0}nile-tab-group nile-tab{border:1px solid #e0e0e0;border-top-left-radius:6px;border-top-right-radius:6px}nile-tab-group nile-tab::part(base){padding-left:.5rem;padding-top:.5rem;padding-bottom:.5rem;border-bottom-left-radius:0;border-bottom-right-radius:0}nile-tab-group nile-tab.active{background-color:#fff;color:#000}nile-tab-group nile-tab.active .sheet-name{font-weight:600}nile-tab-group nile-tab-panel::part(base){padding:0;max-height:30rem}\n"] }]
|
|
10470
10402
|
}], ctorParameters: function () { return [{ type: AutosaveService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { config: [{
|
|
10471
10403
|
type: Input
|
|
10472
10404
|
}], sheetsData: [{
|