@aquera/ngx-smart-table 0.0.12-alpha → 0.0.14-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 +143 -21
- package/esm2020/lib/renderer/components/st-cell/st-cell.component.mjs +2 -2
- package/esm2020/lib/renderer/components/st-table/st-table.component.mjs +44 -1
- package/esm2020/lib/renderer/components/st-workbook/st-workbook.component.mjs +30 -4
- package/fesm2015/aquera-ngx-smart-table.mjs +217 -25
- package/fesm2015/aquera-ngx-smart-table.mjs.map +1 -1
- package/fesm2020/aquera-ngx-smart-table.mjs +214 -24
- package/fesm2020/aquera-ngx-smart-table.mjs.map +1 -1
- package/lib/editors/nile-select-editor.d.ts +7 -0
- package/lib/renderer/components/st-table/st-table.component.d.ts +11 -0
- package/lib/renderer/components/st-workbook/st-workbook.component.d.ts +16 -0
- package/package.json +1 -1
|
@@ -3533,6 +3533,7 @@ class NileSelectEditor {
|
|
|
3533
3533
|
this.acceptsInitialKeypress = false;
|
|
3534
3534
|
this.eventListeners = [];
|
|
3535
3535
|
this.currentOptions = [];
|
|
3536
|
+
this.isInitializing = false; // Flag to prevent immediate close during initialization
|
|
3536
3537
|
// Handle Observable options
|
|
3537
3538
|
if (isObservable(options.options)) {
|
|
3538
3539
|
this.optionsSubscription = options.options.subscribe(opts => {
|
|
@@ -3551,18 +3552,99 @@ class NileSelectEditor {
|
|
|
3551
3552
|
}
|
|
3552
3553
|
}
|
|
3553
3554
|
}
|
|
3555
|
+
/**
|
|
3556
|
+
* Inject global styles to remove border from nile-select combobox
|
|
3557
|
+
* Uses ::part selector which works across shadow DOM boundaries
|
|
3558
|
+
*/
|
|
3559
|
+
injectBorderlessStyles() {
|
|
3560
|
+
if (NileSelectEditor.stylesInjected)
|
|
3561
|
+
return;
|
|
3562
|
+
const styleId = 'nile-select-borderless-styles';
|
|
3563
|
+
if (document.getElementById(styleId)) {
|
|
3564
|
+
NileSelectEditor.stylesInjected = true;
|
|
3565
|
+
return;
|
|
3566
|
+
}
|
|
3567
|
+
const style = document.createElement('style');
|
|
3568
|
+
style.id = styleId;
|
|
3569
|
+
style.textContent = `
|
|
3570
|
+
.st-cell-editor::part(combobox) {
|
|
3571
|
+
border: none !important;
|
|
3572
|
+
outline: none !important;
|
|
3573
|
+
box-shadow: none !important;
|
|
3574
|
+
min-height: unset !important;
|
|
3575
|
+
height: 100% !important;
|
|
3576
|
+
padding: 0 !important;
|
|
3577
|
+
}
|
|
3578
|
+
.st-cell-editor::part(combobox):hover {
|
|
3579
|
+
border: none !important;
|
|
3580
|
+
outline: none !important;
|
|
3581
|
+
box-shadow: none !important;
|
|
3582
|
+
}
|
|
3583
|
+
.st-cell-editor::part(combobox):focus {
|
|
3584
|
+
border: none !important;
|
|
3585
|
+
outline: none !important;
|
|
3586
|
+
box-shadow: none !important;
|
|
3587
|
+
}
|
|
3588
|
+
// .st-cell-editor::part(tag) {
|
|
3589
|
+
// margin: 1px 2px !important;
|
|
3590
|
+
// border-radius: 3px !important;
|
|
3591
|
+
// background-color: #e2e8f0 !important;
|
|
3592
|
+
// font-size: 12px !important;
|
|
3593
|
+
// height: auto !important;
|
|
3594
|
+
// }
|
|
3595
|
+
// .st-cell-editor::part(tag__base) {
|
|
3596
|
+
// border: none !important;
|
|
3597
|
+
// outline: none !important;
|
|
3598
|
+
// padding: 0 2px !important;
|
|
3599
|
+
// height: auto !important;
|
|
3600
|
+
// }
|
|
3601
|
+
// .st-cell-editor::part(tag__content) {
|
|
3602
|
+
// padding: 0 !important;
|
|
3603
|
+
// }
|
|
3604
|
+
.st-cell-editor::part(tags) {
|
|
3605
|
+
gap: 2px !important;
|
|
3606
|
+
align-items: center !important;
|
|
3607
|
+
}
|
|
3608
|
+
.st-cell-editor::part(tags-count) {
|
|
3609
|
+
margin: 0 !important;
|
|
3610
|
+
}
|
|
3611
|
+
.st-cell-editor::part(footer) {
|
|
3612
|
+
height: 35px !important;
|
|
3613
|
+
min-height: 35px !important;
|
|
3614
|
+
padding: 8px !important;
|
|
3615
|
+
padding-bottom: 30px !important;
|
|
3616
|
+
box-sizing: border-box !important;
|
|
3617
|
+
}
|
|
3618
|
+
.st-cell-editor::part(listbox) {
|
|
3619
|
+
margin-bottom: 0 !important;
|
|
3620
|
+
padding-bottom: 0 !important;
|
|
3621
|
+
}
|
|
3622
|
+
`;
|
|
3623
|
+
document.head.appendChild(style);
|
|
3624
|
+
NileSelectEditor.stylesInjected = true;
|
|
3625
|
+
}
|
|
3554
3626
|
edit(context) {
|
|
3555
3627
|
if (!context.container) {
|
|
3556
3628
|
console.warn('NileSelectEditor requires a container element');
|
|
3557
3629
|
return;
|
|
3558
3630
|
}
|
|
3631
|
+
// Set initializing flag to prevent immediate close
|
|
3632
|
+
this.isInitializing = true;
|
|
3559
3633
|
// Create NileSelect custom element using document.createElement
|
|
3560
3634
|
this.select = document.createElement('nile-select');
|
|
3561
3635
|
this.select.className = 'st-cell-editor';
|
|
3562
|
-
// Apply inline styles for proper cell fitting
|
|
3563
|
-
this.select.style.width = '100%';
|
|
3564
|
-
this.select.style.height = '
|
|
3636
|
+
// Apply inline styles for proper cell fitting - prevent height changes
|
|
3637
|
+
this.select.style.width = 'calc(100% - 4px)';
|
|
3638
|
+
this.select.style.height = '100%';
|
|
3639
|
+
this.select.style.maxHeight = '100%';
|
|
3565
3640
|
this.select.style.boxSizing = 'border-box';
|
|
3641
|
+
this.select.style.margin = '0 2px';
|
|
3642
|
+
this.select.style.overflow = 'hidden';
|
|
3643
|
+
// Inject styles to remove border using ::part selector
|
|
3644
|
+
this.injectBorderlessStyles();
|
|
3645
|
+
// Also try removing outline on host element
|
|
3646
|
+
this.select.style.outline = 'none';
|
|
3647
|
+
this.select.style.border = 'none';
|
|
3566
3648
|
// Set initial value
|
|
3567
3649
|
this.setInitialValue(context.value);
|
|
3568
3650
|
// Apply all configuration options
|
|
@@ -3574,16 +3656,22 @@ class NileSelectEditor {
|
|
|
3574
3656
|
// Clear container and append select
|
|
3575
3657
|
context.container.innerHTML = '';
|
|
3576
3658
|
context.container.appendChild(this.select);
|
|
3577
|
-
// Focus after render
|
|
3659
|
+
// Focus and auto-open after render
|
|
3578
3660
|
setTimeout(() => {
|
|
3579
|
-
var _a
|
|
3661
|
+
var _a;
|
|
3580
3662
|
(_a = this.select) === null || _a === void 0 ? void 0 : _a.focus();
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
// Portal div is appended to document body
|
|
3585
|
-
this.portalDiv = document.querySelector('.nile-select-portal-append');
|
|
3663
|
+
// Auto-open the dropdown
|
|
3664
|
+
if (this.select) {
|
|
3665
|
+
this.select.open = true;
|
|
3586
3666
|
}
|
|
3667
|
+
// Clear initializing flag after dropdown has opened
|
|
3668
|
+
setTimeout(() => {
|
|
3669
|
+
this.isInitializing = false;
|
|
3670
|
+
// For multi-select, find the portal div for click detection
|
|
3671
|
+
if (this.options.multiple) {
|
|
3672
|
+
this.portalDiv = document.querySelector('.nile-select-portal-append');
|
|
3673
|
+
}
|
|
3674
|
+
}, 100);
|
|
3587
3675
|
}, 0);
|
|
3588
3676
|
}
|
|
3589
3677
|
/**
|
|
@@ -3667,9 +3755,13 @@ class NileSelectEditor {
|
|
|
3667
3755
|
if (this.options.pill) {
|
|
3668
3756
|
this.select.pill = this.options.pill;
|
|
3669
3757
|
}
|
|
3670
|
-
if (this.options.hoist) {
|
|
3758
|
+
if (this.options.hoist !== undefined) {
|
|
3671
3759
|
this.select.hoist = this.options.hoist;
|
|
3672
3760
|
}
|
|
3761
|
+
else {
|
|
3762
|
+
// Default hoist to true for all selects to prevent clipping issues in table cells
|
|
3763
|
+
this.select.hoist = true;
|
|
3764
|
+
}
|
|
3673
3765
|
if (this.options.placement) {
|
|
3674
3766
|
this.select.placement = this.options.placement;
|
|
3675
3767
|
}
|
|
@@ -3744,6 +3836,13 @@ class NileSelectEditor {
|
|
|
3744
3836
|
if (!this.select)
|
|
3745
3837
|
return;
|
|
3746
3838
|
const validateOnSave = this.options.validateOnSave !== false;
|
|
3839
|
+
// Prevent click events from bubbling up to the cell container
|
|
3840
|
+
// This prevents parent handlers from interfering with nile-select's toggle
|
|
3841
|
+
const clickHandler = (e) => {
|
|
3842
|
+
e.stopPropagation();
|
|
3843
|
+
};
|
|
3844
|
+
this.select.addEventListener('click', clickHandler);
|
|
3845
|
+
this.eventListeners.push({ event: 'click', handler: clickHandler });
|
|
3747
3846
|
// Handle keyboard events (keydown is not replaced by custom events)
|
|
3748
3847
|
const keydownHandler = (e) => {
|
|
3749
3848
|
const keyEvent = e;
|
|
@@ -3758,6 +3857,10 @@ class NileSelectEditor {
|
|
|
3758
3857
|
// Use nile-change custom event as primary save trigger
|
|
3759
3858
|
const changeHandler = (e) => {
|
|
3760
3859
|
var _a, _b;
|
|
3860
|
+
// Ignore change events during initialization (can fire when setting initial value)
|
|
3861
|
+
if (this.isInitializing) {
|
|
3862
|
+
return;
|
|
3863
|
+
}
|
|
3761
3864
|
const customEvent = e;
|
|
3762
3865
|
if (validateOnSave && !((_a = this.select) === null || _a === void 0 ? void 0 : _a.checkValidity())) {
|
|
3763
3866
|
(_b = this.select) === null || _b === void 0 ? void 0 : _b.reportValidity();
|
|
@@ -3771,14 +3874,22 @@ class NileSelectEditor {
|
|
|
3771
3874
|
};
|
|
3772
3875
|
this.select.addEventListener('nile-change', changeHandler);
|
|
3773
3876
|
this.eventListeners.push({ event: 'nile-change', handler: changeHandler });
|
|
3774
|
-
// Handle blur as secondary save trigger
|
|
3877
|
+
// Handle blur as secondary save trigger - only for single-select
|
|
3878
|
+
// Multi-select uses hide event instead
|
|
3775
3879
|
const blurHandler = (e) => {
|
|
3776
3880
|
var _a, _b;
|
|
3881
|
+
// Ignore blur during initialization
|
|
3882
|
+
if (this.isInitializing) {
|
|
3883
|
+
return;
|
|
3884
|
+
}
|
|
3777
3885
|
if (validateOnSave && !((_a = this.select) === null || _a === void 0 ? void 0 : _a.checkValidity())) {
|
|
3778
3886
|
(_b = this.select) === null || _b === void 0 ? void 0 : _b.reportValidity();
|
|
3779
3887
|
return;
|
|
3780
3888
|
}
|
|
3781
|
-
//
|
|
3889
|
+
// For single-select, save on blur (when clicking outside)
|
|
3890
|
+
if (!this.options.multiple) {
|
|
3891
|
+
context.onSave(this.getCurrentValue());
|
|
3892
|
+
}
|
|
3782
3893
|
};
|
|
3783
3894
|
this.select.addEventListener('nile-blur', blurHandler);
|
|
3784
3895
|
this.eventListeners.push({ event: 'nile-blur', handler: blurHandler });
|
|
@@ -3823,12 +3934,20 @@ class NileSelectEditor {
|
|
|
3823
3934
|
}
|
|
3824
3935
|
// Otherwise, click is inside - do nothing (dropdown stays open)
|
|
3825
3936
|
};
|
|
3826
|
-
//
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3937
|
+
// Delay adding the document click handler to prevent the initial click
|
|
3938
|
+
// (that opened the editor) from immediately triggering it and closing the dropdown
|
|
3939
|
+
// Use 200ms to ensure the dropdown has fully opened
|
|
3940
|
+
setTimeout(() => {
|
|
3941
|
+
// Only add if select still exists (editor not destroyed)
|
|
3942
|
+
if (this.select) {
|
|
3943
|
+
// Use bubbling phase (false) instead of capture to not interfere with nile-select's toggle
|
|
3944
|
+
document.addEventListener('click', documentClickHandler, false);
|
|
3945
|
+
this.eventListeners.push({
|
|
3946
|
+
event: 'document-click',
|
|
3947
|
+
handler: documentClickHandler
|
|
3948
|
+
});
|
|
3949
|
+
}
|
|
3950
|
+
}, 200);
|
|
3832
3951
|
}
|
|
3833
3952
|
}
|
|
3834
3953
|
/**
|
|
@@ -3849,6 +3968,8 @@ class NileSelectEditor {
|
|
|
3849
3968
|
return value;
|
|
3850
3969
|
}
|
|
3851
3970
|
destroy() {
|
|
3971
|
+
// Reset initialization flag
|
|
3972
|
+
this.isInitializing = false;
|
|
3852
3973
|
// Unsubscribe from options Observable
|
|
3853
3974
|
if (this.optionsSubscription) {
|
|
3854
3975
|
this.optionsSubscription.unsubscribe();
|
|
@@ -3859,8 +3980,8 @@ class NileSelectEditor {
|
|
|
3859
3980
|
this.eventListeners.forEach(({ event, handler }) => {
|
|
3860
3981
|
var _a;
|
|
3861
3982
|
if (event === 'document-click') {
|
|
3862
|
-
// Remove from document for multi-select click handler
|
|
3863
|
-
document.removeEventListener('click', handler,
|
|
3983
|
+
// Remove from document for multi-select click handler (bubbling phase)
|
|
3984
|
+
document.removeEventListener('click', handler, false);
|
|
3864
3985
|
}
|
|
3865
3986
|
else {
|
|
3866
3987
|
// Remove from select element
|
|
@@ -3890,6 +4011,7 @@ class NileSelectEditor {
|
|
|
3890
4011
|
return (Array.isArray(value) ? (value.length > 0 ? value[0] : '') : value);
|
|
3891
4012
|
}
|
|
3892
4013
|
}
|
|
4014
|
+
NileSelectEditor.stylesInjected = false;
|
|
3893
4015
|
|
|
3894
4016
|
/**
|
|
3895
4017
|
* Custom editor using NileAutoComplete from @aquera/nile-elements
|
|
@@ -5105,10 +5227,10 @@ class StCellComponent {
|
|
|
5105
5227
|
}
|
|
5106
5228
|
}
|
|
5107
5229
|
StCellComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5108
|
-
StCellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StCellComponent, selector: "st-cell", inputs: { cell: "cell", editMode: "editMode", tableState: "tableState", tableConfig: "tableConfig", columnIndex: "columnIndex" }, outputs: { cellChange: "cellChange", cellEdit: "cellEdit", cellSave: "cellSave", cellCancel: "cellCancel", cellSaveAndNavigate: "cellSaveAndNavigate" }, host: { listeners: { "keydown": "onCellKeyDown($event)" } }, viewQueries: [{ propertyName: "editorContainer", first: true, predicate: ["editorContainer"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"st-cell\" \n [ngClass]=\"{\n 'editing': cell.isEditing(),\n 'dirty': cell.isDirty(),\n 'invalid': !cell.isValid(),\n 'readonly': !isEditable\n }\"\n (click)=\"onCellClick()\" \n (dblclick)=\"onCellDoubleClick()\">\n\n <!-- Display Mode with Template Support -->\n <ng-container *ngIf=\"!cell.isEditing()\">\n <!-- Custom Template -->\n <ng-container *ngIf=\"hasCellTemplate\">\n <ng-container *ngTemplateOutlet=\"cellTemplate; context: templateContext\"></ng-container>\n </ng-container>\n\n <!-- Default Text Rendering -->\n <span *ngIf=\"!hasCellTemplate\" class=\"cell-display\">\n {{ cell.render() }}\n </span>\n </ng-container>\n\n <!-- Edit Mode -->\n <div *ngIf=\"cell.isEditing()\" class=\"cell-editor\" #editorContainer>\n </div>\n</div>", styles: [".st-cell{position:relative;cursor:pointer;transition:background-color .2s;min-height:28px;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;box-sizing:border-box}.st-cell.invalid{border-left:2px solid #e53e3e}.st-cell.readonly{cursor:default}.cell-display{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-content:center;width:100%;height:100%;padding-left:8px;padding-right:8px;font-size:12px;font-weight:300;letter-spacing:.2px;line-height:14px}.cell-editor{display:flex;height:100%;width:100%}.cell-editor input,.cell-editor select,.cell-editor textarea{width:100%;border:none;outline:none;font:inherit;padding:0;background:transparent;color:inherit}.cell-editor input[type=number]{text-align:inherit}.cell-error{position:absolute;right:4px;top:50%;transform:translateY(-50%);color:#e53e3e;font-weight:700;cursor:help;font-size:14px}\n"], directives: [{ type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }] });
|
|
5230
|
+
StCellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StCellComponent, selector: "st-cell", inputs: { cell: "cell", editMode: "editMode", tableState: "tableState", tableConfig: "tableConfig", columnIndex: "columnIndex" }, outputs: { cellChange: "cellChange", cellEdit: "cellEdit", cellSave: "cellSave", cellCancel: "cellCancel", cellSaveAndNavigate: "cellSaveAndNavigate" }, host: { listeners: { "keydown": "onCellKeyDown($event)" } }, viewQueries: [{ propertyName: "editorContainer", first: true, predicate: ["editorContainer"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"st-cell\" \n [ngClass]=\"{\n 'editing': cell.isEditing(),\n 'dirty': cell.isDirty(),\n 'invalid': !cell.isValid(),\n 'readonly': !isEditable\n }\"\n (click)=\"onCellClick()\" \n (dblclick)=\"onCellDoubleClick()\">\n\n <!-- Display Mode with Template Support -->\n <ng-container *ngIf=\"!cell.isEditing()\">\n <!-- Custom Template -->\n <ng-container *ngIf=\"hasCellTemplate\">\n <ng-container *ngTemplateOutlet=\"cellTemplate; context: templateContext\"></ng-container>\n </ng-container>\n\n <!-- Default Text Rendering -->\n <span *ngIf=\"!hasCellTemplate\" class=\"cell-display\">\n {{ cell.render() }}\n </span>\n </ng-container>\n\n <!-- Edit Mode -->\n <div *ngIf=\"cell.isEditing()\" class=\"cell-editor\" #editorContainer>\n </div>\n</div>", styles: [".st-cell{position:relative;cursor:pointer;transition:background-color .2s;min-height:28px;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;box-sizing:border-box}.st-cell.invalid{border-left:2px solid #e53e3e}.st-cell.readonly{cursor:default}.cell-display{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-content:center;width:100%;height:100%;padding-left:8px;padding-right:8px;font-size:12px;font-weight:300;letter-spacing:.2px;line-height:14px}.cell-editor{display:flex;height:100%;width:100%}.cell-editor input,.cell-editor select,.cell-editor textarea{width:100%;border:none;outline:none;font:inherit;padding:0;background:transparent;color:inherit}.cell-editor input[type=number]{text-align:inherit}.cell-editor nile-select::part(combobox){border:none!important;outline:none!important;box-shadow:none!important}.cell-editor nile-select::part(tag){border:none!important;outline:none!important}.cell-editor nile-select::part(listbox){border:none!important}.cell-error{position:absolute;right:4px;top:50%;transform:translateY(-50%);color:#e53e3e;font-weight:700;cursor:help;font-size:14px}\n"], directives: [{ type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }] });
|
|
5109
5231
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StCellComponent, decorators: [{
|
|
5110
5232
|
type: Component,
|
|
5111
|
-
args: [{ selector: 'st-cell', template: "<div class=\"st-cell\" \n [ngClass]=\"{\n 'editing': cell.isEditing(),\n 'dirty': cell.isDirty(),\n 'invalid': !cell.isValid(),\n 'readonly': !isEditable\n }\"\n (click)=\"onCellClick()\" \n (dblclick)=\"onCellDoubleClick()\">\n\n <!-- Display Mode with Template Support -->\n <ng-container *ngIf=\"!cell.isEditing()\">\n <!-- Custom Template -->\n <ng-container *ngIf=\"hasCellTemplate\">\n <ng-container *ngTemplateOutlet=\"cellTemplate; context: templateContext\"></ng-container>\n </ng-container>\n\n <!-- Default Text Rendering -->\n <span *ngIf=\"!hasCellTemplate\" class=\"cell-display\">\n {{ cell.render() }}\n </span>\n </ng-container>\n\n <!-- Edit Mode -->\n <div *ngIf=\"cell.isEditing()\" class=\"cell-editor\" #editorContainer>\n </div>\n</div>", styles: [".st-cell{position:relative;cursor:pointer;transition:background-color .2s;min-height:28px;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;box-sizing:border-box}.st-cell.invalid{border-left:2px solid #e53e3e}.st-cell.readonly{cursor:default}.cell-display{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-content:center;width:100%;height:100%;padding-left:8px;padding-right:8px;font-size:12px;font-weight:300;letter-spacing:.2px;line-height:14px}.cell-editor{display:flex;height:100%;width:100%}.cell-editor input,.cell-editor select,.cell-editor textarea{width:100%;border:none;outline:none;font:inherit;padding:0;background:transparent;color:inherit}.cell-editor input[type=number]{text-align:inherit}.cell-error{position:absolute;right:4px;top:50%;transform:translateY(-50%);color:#e53e3e;font-weight:700;cursor:help;font-size:14px}\n"] }]
|
|
5233
|
+
args: [{ selector: 'st-cell', template: "<div class=\"st-cell\" \n [ngClass]=\"{\n 'editing': cell.isEditing(),\n 'dirty': cell.isDirty(),\n 'invalid': !cell.isValid(),\n 'readonly': !isEditable\n }\"\n (click)=\"onCellClick()\" \n (dblclick)=\"onCellDoubleClick()\">\n\n <!-- Display Mode with Template Support -->\n <ng-container *ngIf=\"!cell.isEditing()\">\n <!-- Custom Template -->\n <ng-container *ngIf=\"hasCellTemplate\">\n <ng-container *ngTemplateOutlet=\"cellTemplate; context: templateContext\"></ng-container>\n </ng-container>\n\n <!-- Default Text Rendering -->\n <span *ngIf=\"!hasCellTemplate\" class=\"cell-display\">\n {{ cell.render() }}\n </span>\n </ng-container>\n\n <!-- Edit Mode -->\n <div *ngIf=\"cell.isEditing()\" class=\"cell-editor\" #editorContainer>\n </div>\n</div>", styles: [".st-cell{position:relative;cursor:pointer;transition:background-color .2s;min-height:28px;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;box-sizing:border-box}.st-cell.invalid{border-left:2px solid #e53e3e}.st-cell.readonly{cursor:default}.cell-display{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;align-content:center;width:100%;height:100%;padding-left:8px;padding-right:8px;font-size:12px;font-weight:300;letter-spacing:.2px;line-height:14px}.cell-editor{display:flex;height:100%;width:100%}.cell-editor input,.cell-editor select,.cell-editor textarea{width:100%;border:none;outline:none;font:inherit;padding:0;background:transparent;color:inherit}.cell-editor input[type=number]{text-align:inherit}.cell-editor nile-select::part(combobox){border:none!important;outline:none!important;box-shadow:none!important}.cell-editor nile-select::part(tag){border:none!important;outline:none!important}.cell-editor nile-select::part(listbox){border:none!important}.cell-error{position:absolute;right:4px;top:50%;transform:translateY(-50%);color:#e53e3e;font-weight:700;cursor:help;font-size:14px}\n"] }]
|
|
5112
5234
|
}], ctorParameters: function () { return []; }, propDecorators: { cell: [{
|
|
5113
5235
|
type: Input
|
|
5114
5236
|
}], editMode: [{
|
|
@@ -8706,6 +8828,51 @@ class StTableComponent {
|
|
|
8706
8828
|
scrollContainer.scrollTop += (cellRect.bottom - visibleBottom);
|
|
8707
8829
|
}
|
|
8708
8830
|
}
|
|
8831
|
+
/**
|
|
8832
|
+
* Scroll to a specific row by index and optionally focus it
|
|
8833
|
+
* @param rowIndex - The index of the row to scroll to
|
|
8834
|
+
* @param focusFirstCell - Whether to focus the first editable cell (default: false)
|
|
8835
|
+
*/
|
|
8836
|
+
scrollToRowAndFocus(rowIndex, focusFirstCell = false) {
|
|
8837
|
+
setTimeout(() => {
|
|
8838
|
+
var _a;
|
|
8839
|
+
const hostElement = (_a = this.elementRef) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
8840
|
+
if (!hostElement)
|
|
8841
|
+
return;
|
|
8842
|
+
// Find the target row
|
|
8843
|
+
const rows = hostElement.querySelectorAll('tbody tr');
|
|
8844
|
+
const targetRow = rows[rowIndex];
|
|
8845
|
+
if (targetRow) {
|
|
8846
|
+
// Scroll the row into view
|
|
8847
|
+
targetRow.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
8848
|
+
// Optionally focus the first editable cell
|
|
8849
|
+
if (focusFirstCell) {
|
|
8850
|
+
const cells = targetRow.querySelectorAll('td:not(.settings-column):not(.row-number-cell)');
|
|
8851
|
+
const firstCell = cells[0];
|
|
8852
|
+
if (firstCell && typeof firstCell.focus === 'function') {
|
|
8853
|
+
setTimeout(() => {
|
|
8854
|
+
firstCell.focus();
|
|
8855
|
+
// Update table state focus position
|
|
8856
|
+
if (this.tableState) {
|
|
8857
|
+
this.tableState.focusCell(rowIndex, 0);
|
|
8858
|
+
}
|
|
8859
|
+
}, 100);
|
|
8860
|
+
}
|
|
8861
|
+
}
|
|
8862
|
+
}
|
|
8863
|
+
}, 0);
|
|
8864
|
+
}
|
|
8865
|
+
/**
|
|
8866
|
+
* Scroll to the last row in the table
|
|
8867
|
+
* @param focusFirstCell - Whether to focus the first editable cell (default: true)
|
|
8868
|
+
*/
|
|
8869
|
+
scrollToLastRow(focusFirstCell = true) {
|
|
8870
|
+
var _a;
|
|
8871
|
+
const rowCount = ((_a = this.data) === null || _a === void 0 ? void 0 : _a.length) || 0;
|
|
8872
|
+
if (rowCount > 0) {
|
|
8873
|
+
this.scrollToRowAndFocus(rowCount - 1, focusFirstCell);
|
|
8874
|
+
}
|
|
8875
|
+
}
|
|
8709
8876
|
/**
|
|
8710
8877
|
* Get the scroll container element
|
|
8711
8878
|
*/
|
|
@@ -10243,12 +10410,34 @@ class StWorkbookComponent {
|
|
|
10243
10410
|
};
|
|
10244
10411
|
window.addEventListener('beforeunload', this.beforeUnloadHandler);
|
|
10245
10412
|
}
|
|
10413
|
+
// ===================================================
|
|
10414
|
+
// Public API Methods
|
|
10415
|
+
// ===================================================
|
|
10416
|
+
/**
|
|
10417
|
+
* Scroll to a specific row in the current table
|
|
10418
|
+
* @param rowIndex - The index of the row to scroll to
|
|
10419
|
+
* @param focusFirstCell - Whether to focus the first editable cell (default: false)
|
|
10420
|
+
*/
|
|
10421
|
+
scrollToRow(rowIndex, focusFirstCell = false) {
|
|
10422
|
+
if (this.tableComponent) {
|
|
10423
|
+
this.tableComponent.scrollToRowAndFocus(rowIndex, focusFirstCell);
|
|
10424
|
+
}
|
|
10425
|
+
}
|
|
10426
|
+
/**
|
|
10427
|
+
* Scroll to the last row in the current table
|
|
10428
|
+
* @param focusFirstCell - Whether to focus the first editable cell (default: true)
|
|
10429
|
+
*/
|
|
10430
|
+
scrollToLastRow(focusFirstCell = true) {
|
|
10431
|
+
if (this.tableComponent) {
|
|
10432
|
+
this.tableComponent.scrollToLastRow(focusFirstCell);
|
|
10433
|
+
}
|
|
10434
|
+
}
|
|
10246
10435
|
}
|
|
10247
10436
|
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 });
|
|
10248
|
-
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" }, 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-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 } });
|
|
10437
|
+
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 } });
|
|
10249
10438
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StWorkbookComponent, decorators: [{
|
|
10250
10439
|
type: Component,
|
|
10251
|
-
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 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-panel::part(base){padding:0;max-height:30rem}\n"] }]
|
|
10440
|
+
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 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"] }]
|
|
10252
10441
|
}], ctorParameters: function () { return [{ type: AutosaveService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { config: [{
|
|
10253
10442
|
type: Input
|
|
10254
10443
|
}], sheetsData: [{
|
|
@@ -10273,6 +10462,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
10273
10462
|
type: Output
|
|
10274
10463
|
}], requestAddRow: [{
|
|
10275
10464
|
type: Output
|
|
10465
|
+
}], tableComponent: [{
|
|
10466
|
+
type: ViewChild,
|
|
10467
|
+
args: [StTableComponent]
|
|
10276
10468
|
}] } });
|
|
10277
10469
|
|
|
10278
10470
|
/**
|