@acorex/platform 20.7.13 → 20.7.15
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/common/index.d.ts +10 -1
- package/core/index.d.ts +93 -4
- package/fesm2022/{acorex-platform-common-common-settings.provider-BwBLG0Hl.mjs → acorex-platform-common-common-settings.provider-gyb6ohAE.mjs} +15 -1
- package/fesm2022/acorex-platform-common-common-settings.provider-gyb6ohAE.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +3 -2
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +428 -157
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +90 -74
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +954 -1223
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +600 -192
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +7 -7
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-file-list-popup.component-BfV3spe3.mjs → acorex-platform-layout-widgets-file-list-popup.component-B0omAUil.mjs} +18 -3
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-B0omAUil.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-repeater-widget-column.component-DnhR00cH.mjs → acorex-platform-layout-widgets-repeater-widget-column.component-fcCirNxz.mjs} +2 -2
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-fcCirNxz.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets.mjs +153 -37
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-create-view.component-CJcbkSBF.mjs → acorex-platform-themes-default-entity-master-create-view.component-CCiYPMhz.mjs} +29 -26
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-CCiYPMhz.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-HBr-ZTSt.mjs → acorex-platform-themes-default-entity-master-list-view.component-BQODc73e.mjs} +2 -2
- package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-HBr-ZTSt.mjs.map → acorex-platform-themes-default-entity-master-list-view.component-BQODc73e.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-modify-view.component-DAFQ4UI9.mjs → acorex-platform-themes-default-entity-master-modify-view.component-CgLUnYRq.mjs} +3 -4
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-CgLUnYRq.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-CwHHYmiK.mjs → acorex-platform-themes-default-entity-master-single-view.component-di5w_3K2.mjs} +4 -4
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-di5w_3K2.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +11 -11
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-shared.mjs +244 -246
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +0 -3
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/layout/components/index.d.ts +159 -248
- package/layout/entity/index.d.ts +42 -1
- package/layout/widgets/index.d.ts +41 -3
- package/package.json +9 -9
- package/themes/shared/index.d.ts +1 -1
- package/workflow/index.d.ts +33 -30
- package/fesm2022/acorex-platform-common-common-settings.provider-BwBLG0Hl.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-BfV3spe3.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-DnhR00cH.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-CJcbkSBF.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DAFQ4UI9.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-CwHHYmiK.mjs.map +0 -1
|
@@ -10,12 +10,12 @@ import * as i2 from '@acorex/components/skeleton';
|
|
|
10
10
|
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
|
11
11
|
import * as i4 from '@acorex/core/format';
|
|
12
12
|
import { AXFormatModule } from '@acorex/core/format';
|
|
13
|
-
import { getSystemActions, AXPExpressionEvaluatorService,
|
|
13
|
+
import { getSystemActions, AXPExpressionEvaluatorService, AXPColumnWidthService, AXPIconLogoConfig, AXPComponentLogoConfig, AXPImageUrlLogoConfig, AXPDataGenerator } from '@acorex/platform/core';
|
|
14
14
|
import { AXPWorkflowService } from '@acorex/platform/workflow';
|
|
15
15
|
import * as i1 from '@angular/common';
|
|
16
16
|
import { CommonModule, NgTemplateOutlet, AsyncPipe } from '@angular/common';
|
|
17
17
|
import * as i0 from '@angular/core';
|
|
18
|
-
import { input, ChangeDetectionStrategy, ViewEncapsulation, Component, inject, signal, effect, InjectionToken, computed, Injectable, Directive, viewChild, contentChild, ElementRef, output, afterNextRender, model,
|
|
18
|
+
import { input, ChangeDetectionStrategy, ViewEncapsulation, Component, inject, signal, effect, InjectionToken, computed, Injectable, Directive, viewChild, contentChild, ElementRef, output, afterNextRender, model, linkedSignal, untracked, HostListener, ViewChildren, Input, DestroyRef, EventEmitter, Output } from '@angular/core';
|
|
19
19
|
import { AXAccordionCdkModule } from '@acorex/cdk/accordion';
|
|
20
20
|
import { AXTagModule } from '@acorex/components/tag';
|
|
21
21
|
import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
|
|
@@ -34,7 +34,7 @@ import { AXSwitchModule } from '@acorex/components/switch';
|
|
|
34
34
|
import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
35
35
|
import * as i1$3 from '@angular/forms';
|
|
36
36
|
import { FormsModule } from '@angular/forms';
|
|
37
|
-
import { cloneDeep,
|
|
37
|
+
import { cloneDeep, isNil, isEmpty, isEqual, merge, get, set, unionBy, sortBy, isArray, capitalize } from 'lodash-es';
|
|
38
38
|
import * as i2$5 from '@acorex/components/form';
|
|
39
39
|
import { AXFormModule } from '@acorex/components/form';
|
|
40
40
|
import { AXTextBoxModule } from '@acorex/components/text-box';
|
|
@@ -44,7 +44,6 @@ import * as i1$4 from '@acorex/components/label';
|
|
|
44
44
|
import { AXLabelModule } from '@acorex/components/label';
|
|
45
45
|
import * as i6$1 from '@acorex/platform/layout/widget-core';
|
|
46
46
|
import { AXPWidgetCoreModule, AXPWidgetsCatalog, AXPWidgetRegistryService, AXPWidgetGroupEnum } from '@acorex/platform/layout/widget-core';
|
|
47
|
-
import { AXPSessionService } from '@acorex/platform/auth';
|
|
48
47
|
import * as i4$1 from '@acorex/components/data-table';
|
|
49
48
|
import { AXDataTableModule } from '@acorex/components/data-table';
|
|
50
49
|
import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
|
|
@@ -62,13 +61,13 @@ import * as i1$6 from '@acorex/components/image-editor';
|
|
|
62
61
|
import { AXImageEditorContainerComponent, AXImageEditorModule } from '@acorex/components/image-editor';
|
|
63
62
|
import * as i3$1 from '@acorex/components/toolbar';
|
|
64
63
|
import { AXToolBarModule } from '@acorex/components/toolbar';
|
|
64
|
+
import * as i2$6 from '@acorex/components/image';
|
|
65
|
+
import { AXImageModule } from '@acorex/components/image';
|
|
66
|
+
import { AXPlatform } from '@acorex/core/platform';
|
|
65
67
|
import { AXDialogService } from '@acorex/components/dialog';
|
|
66
68
|
import { AXToastService } from '@acorex/components/toast';
|
|
67
69
|
import { AXTreeViewComponent } from '@acorex/components/tree-view';
|
|
68
70
|
import { AXPLayoutBuilderService, AXPLayoutRendererComponent } from '@acorex/platform/layout/builder';
|
|
69
|
-
import * as i2$6 from '@acorex/components/image';
|
|
70
|
-
import { AXImageModule } from '@acorex/components/image';
|
|
71
|
-
import { AXPlatform } from '@acorex/core/platform';
|
|
72
71
|
import * as i2$7 from '@acorex/components/accordion';
|
|
73
72
|
import { AXAccordionModule } from '@acorex/components/accordion';
|
|
74
73
|
import { AXButtonGroupModule } from '@acorex/components/button-group';
|
|
@@ -1230,7 +1229,7 @@ class AXPColumnItemListComponent {
|
|
|
1230
1229
|
</div>
|
|
1231
1230
|
</div>
|
|
1232
1231
|
</ax-popover>
|
|
1233
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$3.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "
|
|
1232
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$3.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1234
1233
|
}
|
|
1235
1234
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPColumnItemListComponent, decorators: [{
|
|
1236
1235
|
type: Component,
|
|
@@ -1468,274 +1467,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1468
1467
|
], encapsulation: ViewEncapsulation.None, providers: [], template: "<!--\n #region ---- Compare View Table Layout ----\n-->\n<div class=\"axp-compare-view\">\n <div class=\"__table-container\">\n <table class=\"__table\">\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <th class=\"__field-header\">\n <ax-check-box\n [value]=\"showOnlyChanges()\"\n (valueChange)=\"toggleShowOnlyChanges()\"\n class=\"__show-changes-toggle\"\n >\n <ax-label>\n {{ '@activity-log:components.compare-view.show-only-differences' | translate | async }}\n </ax-label>\n </ax-check-box>\n </th>\n @for (obj of remainingObjects(); track obj.id) {\n <th class=\"__object-header\" [attr.data-id]=\"obj.id\">\n <div class=\"__object-title\" [title]=\"obj.description\">\n <span>{{ obj.title | translate | async }}</span>\n @if (remainingObjects().length > 2) {\n <span class=\"__remove-object-button\" (click)=\"removeObject(obj.id)\">\n <i class=\"fa-light fa-times\"></i>\n </span>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody class=\"__tbody\">\n @for (field of filteredFields(); track field.path; let i = $index) {\n <tr\n class=\"__row\"\n [class.__row--odd]=\"i % 2 === 1\"\n [class.__row--has-differences]=\"hasUnequalValues(field.path)\"\n [class.__row--has-equal-values]=\"hasEqualValues(field.path)\"\n >\n <td class=\"__field-cell\">\n <div class=\"__field-content\">\n <div class=\"__field-title\">\n {{ field.title | translate | async }}\n </div>\n @if (field.description) {\n <div class=\"__field-description\">{{ field.description }}</div>\n }\n </div>\n </td>\n @for (obj of remainingObjects(); track obj.id; let objIndex = $index) {\n <td\n class=\"__object-cell\"\n [attr.data-id]=\"obj.id\"\n [class.__cell--changed]=\"hasValueChangedFromPrevious(field.path, objIndex) && isChangesMode()\"\n >\n @if (obj.context[field.path] !== undefined) {\n <div class=\"__object-content\">\n <axp-widgets-container [context]=\"obj.context\">\n <ng-container axp-widget-renderer [node]=\"field.widget\" [mode]=\"'view'\"></ng-container>\n </axp-widgets-container>\n </div>\n } @else {\n <div class=\"__object-placeholder\">---</div>\n }\n @if (hasValueChangingToNext(field.path, objIndex) && isChangesMode()) {\n <div class=\"__change-indicator\">\n <i class=\"fa-light fa-arrow-right\"></i>\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n<!--\n #endregion\n-->\n", styles: [".axp-compare-view{display:flex;height:100%;width:100%;flex-direction:column;border-radius:.375rem;border-width:1px;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:relative}.axp-compare-view .__filter-controls{flex-shrink:0;border-bottom-width:1px;padding:1rem;background-color:rgb(var(--ax-sys-color-light-surface));color:rgb(var(--ax-sys-color-on-light-surface));border-color:rgb(var(--ax-sys-color-border-light-surface))}.axp-compare-view .__filter-controls .__show-changes-toggle{font-size:.875rem;line-height:1.25rem}.axp-compare-view .__table-container{flex:1 1 0%;overflow:auto;position:relative}.axp-compare-view .__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.axp-compare-view .__table .__thead{position:sticky;top:0;z-index:20}.axp-compare-view .__table .__thead .__header-row .__field-header{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;text-align:left;font-weight:700;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));position:sticky;left:0;z-index:25}.axp-compare-view .__table .__thead .__header-row .__object-header{position:relative;border-bottom-width:1px;padding:.75rem 1rem;text-align:center;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));min-width:250px;width:250px}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;font-weight:600}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-description{margin-top:.25rem;font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button{display:flex;width:1.5rem;height:1.5rem;cursor:pointer;align-items:center;justify-content:center;border-radius:9999px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));font-size:.875rem;line-height:1.25rem;position:absolute;top:50%;inset-inline-end:0px;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button:hover{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-100),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-danger-600),var(--tw-text-opacity, 1))}.axp-compare-view .__table .__tbody .__row{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.axp-compare-view .__table .__tbody .__row.__row--odd{background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-compare-view .__table .__tbody .__row.__row--has-differences{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{background-color:rgba(var(--ax-sys-color-warning-500),.05)}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{background-color:rgba(var(--ax-sys-color-success-500),.05)}.axp-compare-view .__table .__tbody .__row .__field-cell{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;vertical-align:top;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:sticky;left:0;z-index:15}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content{display:flex;flex-direction:column;gap:.25rem}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-title{font-weight:500}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-description{font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__tbody .__row .__object-cell{border-bottom-width:1px;padding:.75rem 1rem;text-align:center;vertical-align:middle;position:relative}.axp-compare-view .__table .__tbody .__row .__object-cell.__cell--changed .__object-content{border-width:1px;border-style:dashed;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-warning-200),var(--tw-border-opacity, 1));padding:.5rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-content{position:relative;display:flex;align-items:center;justify-content:center}.axp-compare-view .__table .__tbody .__row .__object-cell .__change-indicator{position:absolute;inset-inline-end:-.25rem;top:50%;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));line-height:1rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-warning-500),var(--tw-text-opacity, 1));font-size:.875rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-placeholder{opacity:.75}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-900),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-900),var(--tw-bg-opacity, 1))}\n"] }]
|
|
1469
1468
|
}], propDecorators: { inputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputs", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }] } });
|
|
1470
1469
|
|
|
1471
|
-
class AXPComponentSlot {
|
|
1472
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1473
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: AXPComponentSlot, isStandalone: true, ngImport: i0 }); }
|
|
1474
|
-
}
|
|
1475
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlot, decorators: [{
|
|
1476
|
-
type: Directive
|
|
1477
|
-
}] });
|
|
1478
|
-
|
|
1479
|
-
class AXPComponentSlotRegistryService {
|
|
1480
|
-
constructor() {
|
|
1481
|
-
this.registry = new Map();
|
|
1482
|
-
}
|
|
1483
|
-
register(slotName, config) {
|
|
1484
|
-
let configs = this.registry.get(slotName) || [];
|
|
1485
|
-
// Check if the component is already registered in this slot
|
|
1486
|
-
const isDuplicate = configs.some(existingConfig => existingConfig.name === config.name);
|
|
1487
|
-
if (!isDuplicate) {
|
|
1488
|
-
configs = [...configs, config]; // Add the new configuration
|
|
1489
|
-
this.registry.set(slotName, configs);
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
get(slotName) {
|
|
1493
|
-
return this.registry.get(slotName) || [];
|
|
1494
|
-
}
|
|
1495
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1496
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotRegistryService, providedIn: 'root' }); }
|
|
1497
|
-
}
|
|
1498
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotRegistryService, decorators: [{
|
|
1499
|
-
type: Injectable,
|
|
1500
|
-
args: [{
|
|
1501
|
-
providedIn: 'root'
|
|
1502
|
-
}]
|
|
1503
|
-
}] });
|
|
1504
|
-
|
|
1505
|
-
class AXPComponentSlotPlaceholderComponent {
|
|
1506
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotPlaceholderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1507
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: AXPComponentSlotPlaceholderComponent, isStandalone: true, selector: "axp-component-slot-placeholder", ngImport: i0, template: `<div>
|
|
1508
|
-
<ax-skeleton class="ax-w-full ax-h-10 ax-rounded-md"></ax-skeleton>
|
|
1509
|
-
</div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i2.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1510
|
-
}
|
|
1511
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotPlaceholderComponent, decorators: [{
|
|
1512
|
-
type: Component,
|
|
1513
|
-
args: [{
|
|
1514
|
-
selector: 'axp-component-slot-placeholder',
|
|
1515
|
-
template: `<div>
|
|
1516
|
-
<ax-skeleton class="ax-w-full ax-h-10 ax-rounded-md"></ax-skeleton>
|
|
1517
|
-
</div>`,
|
|
1518
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1519
|
-
imports: [AXSkeletonModule],
|
|
1520
|
-
standalone: true,
|
|
1521
|
-
}]
|
|
1522
|
-
}] });
|
|
1523
|
-
|
|
1524
|
-
class AXPComponentSlotDirective {
|
|
1525
|
-
constructor() {
|
|
1526
|
-
this.name = input.required(...(ngDevMode ? [{ debugName: "name" }] : []));
|
|
1527
|
-
this.host = input(...(ngDevMode ? [undefined, { debugName: "host" }] : []));
|
|
1528
|
-
this.context = input(...(ngDevMode ? [undefined, { debugName: "context" }] : []));
|
|
1529
|
-
this.elementRef = inject(ElementRef);
|
|
1530
|
-
this.registryService = inject(AXPComponentSlotRegistryService);
|
|
1531
|
-
this.injector = inject(Injector);
|
|
1532
|
-
this.evaluator = inject(AXPExpressionEvaluatorService);
|
|
1533
|
-
this.sessionService = inject(AXPSessionService);
|
|
1534
|
-
this.viewContainerRef = inject(ViewContainerRef);
|
|
1535
|
-
this.contextStore = inject(AXPContextStore);
|
|
1536
|
-
this.isEmpty = computed(() => this._viewCount() === 0, ...(ngDevMode ? [{ debugName: "isEmpty" }] : []));
|
|
1537
|
-
// Create a signal to store the count of children
|
|
1538
|
-
this._viewCount = signal(0, ...(ngDevMode ? [{ debugName: "_viewCount" }] : []));
|
|
1539
|
-
// Track component references for updates
|
|
1540
|
-
this.componentRefs = [];
|
|
1541
|
-
// Track placeholder references for replacement
|
|
1542
|
-
this.placeholderRefs = new Map();
|
|
1543
|
-
// Watch for context changes and update component instances
|
|
1544
|
-
effect(() => {
|
|
1545
|
-
const currentContext = this.context();
|
|
1546
|
-
const currentHost = this.host();
|
|
1547
|
-
// Update all component references with new context and host
|
|
1548
|
-
this.componentRefs.forEach(componentRef => {
|
|
1549
|
-
if (componentRef.instance) {
|
|
1550
|
-
Object.assign(componentRef.instance, {
|
|
1551
|
-
host: currentHost,
|
|
1552
|
-
context: currentContext,
|
|
1553
|
-
});
|
|
1554
|
-
}
|
|
1555
|
-
});
|
|
1556
|
-
});
|
|
1557
|
-
}
|
|
1558
|
-
async ngOnInit() {
|
|
1559
|
-
await this.loadComponents();
|
|
1560
|
-
// Update the signal after loading
|
|
1561
|
-
this._viewCount.set(this.viewContainerRef.length);
|
|
1562
|
-
}
|
|
1563
|
-
async loadComponents() {
|
|
1564
|
-
this.viewContainerRef.clear();
|
|
1565
|
-
// Clear previous component references
|
|
1566
|
-
this.componentRefs = [];
|
|
1567
|
-
this.placeholderRefs.clear();
|
|
1568
|
-
const configs = sortBy(this.registryService.get(this.name()), (c) => c.priority ?? 0);
|
|
1569
|
-
if (!configs) {
|
|
1570
|
-
console.error(`No component found for slot ${this.name()}`);
|
|
1571
|
-
return;
|
|
1572
|
-
}
|
|
1573
|
-
// Evaluate conditions and check features in parallel for performance
|
|
1574
|
-
const results = await Promise.all(configs.map(async (c) => {
|
|
1575
|
-
// Check condition if provided
|
|
1576
|
-
const conditionPassed = c.condition ? await this.evaluateCondition(c.condition) : true;
|
|
1577
|
-
// Check features if provided
|
|
1578
|
-
const featuresPassed = c.features && c.features.length > 0
|
|
1579
|
-
? this.sessionService.isFeatureEnabled(...c.features)
|
|
1580
|
-
: true;
|
|
1581
|
-
return {
|
|
1582
|
-
config: c,
|
|
1583
|
-
visible: conditionPassed && featuresPassed,
|
|
1584
|
-
};
|
|
1585
|
-
}));
|
|
1586
|
-
// Filter visible components while preserving priority order
|
|
1587
|
-
const slots = results.filter((r) => r.visible).map((r) => r.config);
|
|
1588
|
-
// Create skeleton placeholders immediately in priority order
|
|
1589
|
-
slots.forEach((config, index) => {
|
|
1590
|
-
const placeholderRef = this.viewContainerRef.createComponent(AXPComponentSlotPlaceholderComponent);
|
|
1591
|
-
this.placeholderRefs.set(index, placeholderRef);
|
|
1592
|
-
});
|
|
1593
|
-
// Load all components in parallel and replace placeholders as they become ready
|
|
1594
|
-
const loadPromises = slots.map(async (config, index) => {
|
|
1595
|
-
let component;
|
|
1596
|
-
let options = {};
|
|
1597
|
-
// load component
|
|
1598
|
-
if (typeof config.loadComponent === 'function') {
|
|
1599
|
-
await runInInjectionContext(this.injector, async () => {
|
|
1600
|
-
component = await config.loadComponent?.();
|
|
1601
|
-
});
|
|
1602
|
-
}
|
|
1603
|
-
else if (config.component) {
|
|
1604
|
-
component = config.component;
|
|
1605
|
-
}
|
|
1606
|
-
// load options
|
|
1607
|
-
if (typeof config.options === 'function') {
|
|
1608
|
-
await runInInjectionContext(this.injector, async () => {
|
|
1609
|
-
const fun = config.options;
|
|
1610
|
-
options = await fun();
|
|
1611
|
-
});
|
|
1612
|
-
}
|
|
1613
|
-
else if (config.options) {
|
|
1614
|
-
options = await this.evaluator.evaluate(config.options, {});
|
|
1615
|
-
}
|
|
1616
|
-
// Replace placeholder with actual component as soon as it's ready
|
|
1617
|
-
if (!component) {
|
|
1618
|
-
console.warn(`Component failed to load for slot ${this.name()} at index ${index}`);
|
|
1619
|
-
// Remove placeholder if component failed to load
|
|
1620
|
-
const placeholderRef = this.placeholderRefs.get(index);
|
|
1621
|
-
if (placeholderRef) {
|
|
1622
|
-
placeholderRef.destroy();
|
|
1623
|
-
this.placeholderRefs.delete(index);
|
|
1624
|
-
}
|
|
1625
|
-
return;
|
|
1626
|
-
}
|
|
1627
|
-
// Get the placeholder reference at this index
|
|
1628
|
-
const placeholderRef = this.placeholderRefs.get(index);
|
|
1629
|
-
if (!placeholderRef) {
|
|
1630
|
-
console.warn(`Placeholder not found for index ${index}`);
|
|
1631
|
-
return;
|
|
1632
|
-
}
|
|
1633
|
-
// Get the index of the placeholder in the view container
|
|
1634
|
-
const placeholderIndex = this.viewContainerRef.indexOf(placeholderRef.hostView);
|
|
1635
|
-
// Remove the placeholder
|
|
1636
|
-
placeholderRef.destroy();
|
|
1637
|
-
this.placeholderRefs.delete(index);
|
|
1638
|
-
// Create the actual component at the same position
|
|
1639
|
-
const componentRef = this.viewContainerRef.createComponent(component, { index: placeholderIndex });
|
|
1640
|
-
// Store the component reference for future updates
|
|
1641
|
-
this.componentRefs.push(componentRef);
|
|
1642
|
-
Object.assign(componentRef.instance, {
|
|
1643
|
-
host: this.host(),
|
|
1644
|
-
context: this.context(),
|
|
1645
|
-
...options,
|
|
1646
|
-
});
|
|
1647
|
-
});
|
|
1648
|
-
// Wait for all components to finish loading (they render as they become ready)
|
|
1649
|
-
await Promise.all(loadPromises);
|
|
1650
|
-
}
|
|
1651
|
-
async evaluateCondition(condition) {
|
|
1652
|
-
if (typeof condition === 'string') {
|
|
1653
|
-
const result = await this.evaluator.evaluate(condition, {});
|
|
1654
|
-
return result;
|
|
1655
|
-
}
|
|
1656
|
-
return condition(this.contextStore.data());
|
|
1657
|
-
//return condition(this.context());
|
|
1658
|
-
}
|
|
1659
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1660
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.16", type: AXPComponentSlotDirective, isStandalone: false, selector: "axp-component-slot", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, host: { classPropertyName: "host", publicName: "host", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["slot"], ngImport: i0 }); }
|
|
1661
|
-
}
|
|
1662
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotDirective, decorators: [{
|
|
1663
|
-
type: Directive,
|
|
1664
|
-
args: [{
|
|
1665
|
-
selector: 'axp-component-slot',
|
|
1666
|
-
standalone: false,
|
|
1667
|
-
exportAs: 'slot',
|
|
1668
|
-
}]
|
|
1669
|
-
}], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], host: [{ type: i0.Input, args: [{ isSignal: true, alias: "host", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }] } });
|
|
1670
|
-
|
|
1671
|
-
class AXPComponentSlotModule {
|
|
1672
|
-
static forRoot(configs) {
|
|
1673
|
-
return {
|
|
1674
|
-
ngModule: AXPComponentSlotModule,
|
|
1675
|
-
providers: [
|
|
1676
|
-
{
|
|
1677
|
-
provide: 'AXPComponentSlotModuleFactory',
|
|
1678
|
-
useFactory: (registry) => () => {
|
|
1679
|
-
if (configs) {
|
|
1680
|
-
for (const [key, value] of Object.entries(configs)) {
|
|
1681
|
-
value.forEach(v => {
|
|
1682
|
-
registry.register(key, v);
|
|
1683
|
-
});
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
},
|
|
1687
|
-
deps: [AXPComponentSlotRegistryService],
|
|
1688
|
-
multi: true
|
|
1689
|
-
}
|
|
1690
|
-
]
|
|
1691
|
-
};
|
|
1692
|
-
}
|
|
1693
|
-
static forChild(configs) {
|
|
1694
|
-
return {
|
|
1695
|
-
ngModule: AXPComponentSlotModule,
|
|
1696
|
-
providers: [
|
|
1697
|
-
{
|
|
1698
|
-
provide: 'AXPComponentSlotModuleFactory',
|
|
1699
|
-
useFactory: (registry) => () => {
|
|
1700
|
-
if (configs) {
|
|
1701
|
-
for (const [key, value] of Object.entries(configs)) {
|
|
1702
|
-
value.forEach(v => {
|
|
1703
|
-
registry.register(key, v);
|
|
1704
|
-
});
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
},
|
|
1708
|
-
deps: [AXPComponentSlotRegistryService],
|
|
1709
|
-
multi: true
|
|
1710
|
-
}
|
|
1711
|
-
]
|
|
1712
|
-
};
|
|
1713
|
-
}
|
|
1714
|
-
/**
|
|
1715
|
-
* @ignore
|
|
1716
|
-
*/
|
|
1717
|
-
constructor(instances) {
|
|
1718
|
-
instances?.forEach(f => {
|
|
1719
|
-
f();
|
|
1720
|
-
});
|
|
1721
|
-
}
|
|
1722
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotModule, deps: [{ token: 'AXPComponentSlotModuleFactory', optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1723
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotModule, declarations: [AXPComponentSlotDirective], exports: [AXPComponentSlotDirective] }); }
|
|
1724
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotModule }); }
|
|
1725
|
-
}
|
|
1726
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPComponentSlotModule, decorators: [{
|
|
1727
|
-
type: NgModule,
|
|
1728
|
-
args: [{
|
|
1729
|
-
declarations: [AXPComponentSlotDirective],
|
|
1730
|
-
exports: [AXPComponentSlotDirective]
|
|
1731
|
-
}]
|
|
1732
|
-
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1733
|
-
type: Optional
|
|
1734
|
-
}, {
|
|
1735
|
-
type: Inject,
|
|
1736
|
-
args: ['AXPComponentSlotModuleFactory']
|
|
1737
|
-
}] }] });
|
|
1738
|
-
|
|
1739
1470
|
//#endregion
|
|
1740
1471
|
class AXPDataSelectorComponent extends AXBasePageComponent {
|
|
1741
1472
|
//#endregion
|
|
@@ -2687,7 +2418,7 @@ class AXPQueryFiltersComponent {
|
|
|
2687
2418
|
}
|
|
2688
2419
|
}
|
|
2689
2420
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPQueryFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2690
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPQueryFiltersComponent, isStandalone: true, selector: "axp-query-filters", inputs: { filtersDefinitions: { classPropertyName: "filtersDefinitions", publicName: "filtersDefinitions", isSignal: true, isRequired: false, transformFunction: null }, initialFilters: { classPropertyName: "initialFilters", publicName: "initialFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onFiltersChanged: "onFiltersChanged" }, host: { listeners: { "document:keydown": "handleKeyboardEvent($event)" } }, viewQueries: [{ propertyName: "tagBox", first: true, predicate: ["tagBox"], descendants: true, isSignal: true }, { propertyName: "widgetRenderer", first: true, predicate: ["widgetRenderer"], descendants: true, isSignal: true }, { propertyName: "popover", first: true, predicate: ["popover"], descendants: true, isSignal: true }, { propertyName: "listItems", predicate: ["caseItem"], descendants: true }], ngImport: i0, template: "<div class=\"ax-flex ax-items-center ax-gap-2 ax-p-2\">\n <ax-button (keydown)=\"handleButtonKeyDown($event)\" (onClick)=\"popover.open()\" #filterButton [look]=\"'blank'\">\n <ax-icon class=\"far fa-bars-filter ax-cursor-pointer\"> </ax-icon>\n </ax-button>\n <ax-tag-box\n #tagBoxComponent\n [ngModel]=\"asyncTags()\"\n (onValueChanged)=\"handleSelectFilters($event)\"\n [textField]=\"'query'\"\n [valueField]=\"'id'\"\n [readonly]=\"filtersDefinitions().length === 0\"\n [look]=\"'none'\"\n [readonlyField]=\"'readOnly'\"\n [tagTemplate]=\"tagTemplate\"\n (onKeyDown)=\"handleKeyDown($event)\"\n [addOnEnter]=\"false\"\n [placeholder]=\"\n (filtersDefinitions().length === 0\n ? '@general:terms.interface.filter.no-filter-definitions'\n : '@general:terms.interface.filter.placeholder'\n )\n | translate\n | async\n \"\n #tagBox\n >\n <ax-suffix class=\"ax-hidden md:ax-block\"><span class=\"ax-text-gray-500\">Ctrl+F</span></ax-suffix>\n </ax-tag-box>\n\n <ng-template #tagTemplate let-item let-index=\"index\">\n <div\n class=\"ax-inline-flex ax-items-center ax-gap-1.5 hover:ax-bg-darkest ax-cursor-pointer ax-rounded-md ax-px-3 ax-py-1 ax-text-sm ax-surface\"\n [class.!ax-bg-primary]=\"item.field === 'all'\"\n [class.!ax-text-white]=\"item.field === 'all'\"\n (click)=\"handleTagClick(item)\"\n >\n <span>{{ item.query }}</span>\n <button (click)=\"handleRemoveTag($event, index)\" type=\"button\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n </div>\n </ng-template>\n</div>\n\n<ax-popover\n [offsetY]=\"activeFilter() ? -30 : 0\"\n [target]=\"tagBoxInput\"\n [openOn]=\"'toggle'\"\n (onOpened)=\"onPopoverOpened($event)\"\n [closeOn]=\"'clickOut'\"\n (onClosed)=\"handlePopoverClosed($event)\"\n [adaptivityEnabled]=\"true\"\n #popover\n>\n <div\n class=\"md:ax-min-w-72 ax-border ax-surface ax-w-full ax-rounded-md md:ax-max-h-96 ax-max-w-80 md:ax-overflow-auto\"\n >\n <axp-widgets-container [context]=\"context()\" (onContextChanged)=\"onContextChanged($event)\">\n @if (activeFilter()) {\n <div class=\"ax-flex ax-flex-col ax-lightest-surface ax-shadow-md\" (keydown.enter)=\"onEnterKeyPressed($event)\">\n <ax-header class=\"ax-border-b ax-border-light ax-px-4 ax-py-2\">{{\n activeFilter()?.title! | translate | async\n }}</ax-header>\n <ax-content class=\"ax-p-4\">\n <div class=\"ax-mb-2\">\n <ax-badge [text]=\"(getActiveOperator(activeFilter())! | translate | async) || ''\"></ax-badge>\n </div>\n <ng-container\n #widgetRenderer=\"widgetRenderer\"\n axp-widget-renderer\n [node]=\"{\n type: activeFilter()?.widget?.type || 'text-editor',\n path: activeFilter()?.field,\n options: activeFilter()?.widget?.options,\n }\"\n [mode]=\"'edit'\"\n >\n </ng-container>\n </ax-content>\n <ax-footer class=\"ax-border-t ax-flex ax-justify-end ax-border-light ax-w-full ax-px-4 ax-py-2\">\n <ax-button\n class=\"ax-xs\"\n [text]=\"'@general:actions.apply.title' | translate | async\"\n (onClick)=\"handleApplyFilter()\"\n ></ax-button>\n </ax-footer>\n </div>\n } @else {\n <div axListNavigation #list=\"axListNavigation\" class=\"axp-list-items\">\n <!-- @if (tagBox.inputValue()) {\n @for (inlineFilter of inlineFilters(); track inlineFilter.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n tabindex=\"0\"\n (click)=\"handleSelectInlineFilter(inlineFilter)\"\n (keydown)=\"handleInlineFilterKeyDown($event, inlineFilter)\"\n >\n {{ inlineFilter.title | translate | async }} {{ getActiveOperator(inlineFilter) }} '{{\n tagBox.inputValue()\n }}'\n </div>\n }\n <span class=\"ax-w-full ax-border-t ax-border-light ax-my-1\"></span>\n } -->\n @for (field of filterFields(); track field.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n (click)=\"handleSelectField(field)\"\n (keydown)=\"handleFieldKeyDown($event, field)\"\n tabindex=\"0\"\n >\n <div class=\"ax-flex ax-items-end ax-gap-2\">\n <ax-icon class=\"ax-w-5\" [class]=\"'fa-light ' + field.icon\"> </ax-icon>\n {{ field.title | translate | async }}\n </div>\n </div>\n }\n </div>\n }\n </axp-widgets-container>\n </div>\n</ax-popover>\n", styles: ["axp-query-filters{width:100%}.axp-list-items{display:flex;min-width:10rem;flex-direction:column;border-radius:.375rem;border-width:1px;padding-top:1rem;padding-bottom:1rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-list-items>div{min-width:7rem;cursor:pointer;padding:.5rem 1rem;text-align:start}.axp-list-items>div:focus{outline:none}.axp-list-items>div.axp-state-focused,.axp-list-items>div:hover{background-color:rgb(var(--ax-sys-color-surface));color:rgb(var(--ax-sys-color-on-surface));border-color:rgb(var(--ax-sys-color-border-surface))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$3.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "forceDisableActionSheetStyle", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSelectionListModule }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i5$2.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues", "tagTemplate"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onTagClick", "onTagDblClick", "onTagContextMenu"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i6$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i6$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXListNavigationModule }, { kind: "directive", type: i7.AXListNavigationDirective, selector: "[axListNavigation]", inputs: ["orientation"], outputs: ["onNavigationChanged", "onKeypress"], exportAs: ["axListNavigation"] }, { kind: "directive", type: i7.AXListNavigationItemDirective, selector: "[axListNavigationItem]", outputs: ["onKeypress"], exportAs: ["axListNavigationItem"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
2421
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPQueryFiltersComponent, isStandalone: true, selector: "axp-query-filters", inputs: { filtersDefinitions: { classPropertyName: "filtersDefinitions", publicName: "filtersDefinitions", isSignal: true, isRequired: false, transformFunction: null }, initialFilters: { classPropertyName: "initialFilters", publicName: "initialFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onFiltersChanged: "onFiltersChanged" }, host: { listeners: { "document:keydown": "handleKeyboardEvent($event)" } }, viewQueries: [{ propertyName: "tagBox", first: true, predicate: ["tagBox"], descendants: true, isSignal: true }, { propertyName: "widgetRenderer", first: true, predicate: ["widgetRenderer"], descendants: true, isSignal: true }, { propertyName: "popover", first: true, predicate: ["popover"], descendants: true, isSignal: true }, { propertyName: "listItems", predicate: ["caseItem"], descendants: true }], ngImport: i0, template: "<div class=\"ax-flex ax-items-center ax-gap-2 ax-p-2\">\n <ax-button (keydown)=\"handleButtonKeyDown($event)\" (onClick)=\"popover.open()\" #filterButton [look]=\"'blank'\">\n <ax-icon class=\"far fa-bars-filter ax-cursor-pointer\"> </ax-icon>\n </ax-button>\n <ax-tag-box\n #tagBoxComponent\n [ngModel]=\"asyncTags()\"\n (onValueChanged)=\"handleSelectFilters($event)\"\n [textField]=\"'query'\"\n [valueField]=\"'id'\"\n [readonly]=\"filtersDefinitions().length === 0\"\n [look]=\"'none'\"\n [readonlyField]=\"'readOnly'\"\n [tagTemplate]=\"tagTemplate\"\n (onKeyDown)=\"handleKeyDown($event)\"\n [addOnEnter]=\"false\"\n [placeholder]=\"\n (filtersDefinitions().length === 0\n ? '@general:terms.interface.filter.no-filter-definitions'\n : '@general:terms.interface.filter.placeholder'\n )\n | translate\n | async\n \"\n #tagBox\n >\n <ax-suffix class=\"ax-hidden md:ax-block\"><span class=\"ax-text-gray-500\">Ctrl+F</span></ax-suffix>\n </ax-tag-box>\n\n <ng-template #tagTemplate let-item let-index=\"index\">\n <div\n class=\"ax-inline-flex ax-items-center ax-gap-1.5 hover:ax-bg-darkest ax-cursor-pointer ax-rounded-md ax-px-3 ax-py-1 ax-text-sm ax-surface\"\n [class.!ax-bg-primary]=\"item.field === 'all'\"\n [class.!ax-text-white]=\"item.field === 'all'\"\n (click)=\"handleTagClick(item)\"\n >\n <span>{{ item.query }}</span>\n <button (click)=\"handleRemoveTag($event, index)\" type=\"button\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n </div>\n </ng-template>\n</div>\n\n<ax-popover\n [offsetY]=\"activeFilter() ? -30 : 0\"\n [target]=\"tagBoxInput\"\n [openOn]=\"'toggle'\"\n (onOpened)=\"onPopoverOpened($event)\"\n [closeOn]=\"'clickOut'\"\n (onClosed)=\"handlePopoverClosed($event)\"\n [adaptivityEnabled]=\"true\"\n #popover\n>\n <div class=\"md:ax-min-w-72 ax-w-full ax-rounded-md md:ax-max-h-96 ax-max-w-80 md:ax-overflow-auto\">\n <axp-widgets-container [context]=\"context()\" (onContextChanged)=\"onContextChanged($event)\">\n @if (activeFilter()) {\n <div class=\"ax-flex ax-flex-col ax-lightest-surface ax-shadow-md\" (keydown.enter)=\"onEnterKeyPressed($event)\">\n <ax-header class=\"ax-border-b ax-border-light ax-px-4 ax-py-2\">{{\n activeFilter()?.title! | translate | async\n }}</ax-header>\n <ax-content class=\"ax-p-4\">\n <div class=\"ax-mb-2\">\n <ax-badge [text]=\"(getActiveOperator(activeFilter())! | translate | async) || ''\"></ax-badge>\n </div>\n <ng-container\n #widgetRenderer=\"widgetRenderer\"\n axp-widget-renderer\n [node]=\"{\n type: activeFilter()?.widget?.type || 'text-editor',\n path: activeFilter()?.field,\n options: activeFilter()?.widget?.options,\n }\"\n [mode]=\"'edit'\"\n >\n </ng-container>\n </ax-content>\n <ax-footer class=\"ax-border-t ax-flex ax-justify-end ax-border-light ax-w-full ax-px-4 ax-py-2\">\n <ax-button\n class=\"ax-xs\"\n [text]=\"'@general:actions.apply.title' | translate | async\"\n (onClick)=\"handleApplyFilter()\"\n ></ax-button>\n </ax-footer>\n </div>\n } @else {\n <div axListNavigation #list=\"axListNavigation\" class=\"axp-list-items\">\n <!-- @if (tagBox.inputValue()) {\n @for (inlineFilter of inlineFilters(); track inlineFilter.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n tabindex=\"0\"\n (click)=\"handleSelectInlineFilter(inlineFilter)\"\n (keydown)=\"handleInlineFilterKeyDown($event, inlineFilter)\"\n >\n {{ inlineFilter.title | translate | async }} {{ getActiveOperator(inlineFilter) }} '{{\n tagBox.inputValue()\n }}'\n </div>\n }\n <span class=\"ax-w-full ax-border-t ax-border-light ax-my-1\"></span>\n } -->\n @for (field of filterFields(); track field.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n (click)=\"handleSelectField(field)\"\n (keydown)=\"handleFieldKeyDown($event, field)\"\n tabindex=\"0\"\n >\n <div class=\"ax-flex ax-items-end ax-gap-2\">\n <ax-icon class=\"ax-w-5\" [class]=\"'fa-light ' + field.icon\"> </ax-icon>\n {{ field.title | translate | async }}\n </div>\n </div>\n }\n </div>\n }\n </axp-widgets-container>\n </div>\n</ax-popover>\n", styles: ["axp-query-filters{width:100%}.axp-list-items{display:flex;min-width:10rem;flex-direction:column;border-radius:.375rem;border-width:1px;padding-top:1rem;padding-bottom:1rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-list-items>div{min-width:7rem;cursor:pointer;padding:.5rem 1rem;text-align:start}.axp-list-items>div:focus{outline:none}.axp-list-items>div.axp-state-focused,.axp-list-items>div:hover{background-color:rgb(var(--ax-sys-color-surface));color:rgb(var(--ax-sys-color-on-surface));border-color:rgb(var(--ax-sys-color-border-surface))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2$3.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSelectionListModule }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i5$2.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues", "tagTemplate"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onTagClick", "onTagDblClick", "onTagContextMenu"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i6$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i6$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXListNavigationModule }, { kind: "directive", type: i7.AXListNavigationDirective, selector: "[axListNavigation]", inputs: ["orientation"], outputs: ["onNavigationChanged", "onKeypress"], exportAs: ["axListNavigation"] }, { kind: "directive", type: i7.AXListNavigationItemDirective, selector: "[axListNavigationItem]", outputs: ["onKeypress"], exportAs: ["axListNavigationItem"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
2691
2422
|
}
|
|
2692
2423
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPQueryFiltersComponent, decorators: [{
|
|
2693
2424
|
type: Component,
|
|
@@ -2703,7 +2434,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2703
2434
|
AXPWidgetCoreModule,
|
|
2704
2435
|
AXListNavigationModule,
|
|
2705
2436
|
AXBadgeModule,
|
|
2706
|
-
], template: "<div class=\"ax-flex ax-items-center ax-gap-2 ax-p-2\">\n <ax-button (keydown)=\"handleButtonKeyDown($event)\" (onClick)=\"popover.open()\" #filterButton [look]=\"'blank'\">\n <ax-icon class=\"far fa-bars-filter ax-cursor-pointer\"> </ax-icon>\n </ax-button>\n <ax-tag-box\n #tagBoxComponent\n [ngModel]=\"asyncTags()\"\n (onValueChanged)=\"handleSelectFilters($event)\"\n [textField]=\"'query'\"\n [valueField]=\"'id'\"\n [readonly]=\"filtersDefinitions().length === 0\"\n [look]=\"'none'\"\n [readonlyField]=\"'readOnly'\"\n [tagTemplate]=\"tagTemplate\"\n (onKeyDown)=\"handleKeyDown($event)\"\n [addOnEnter]=\"false\"\n [placeholder]=\"\n (filtersDefinitions().length === 0\n ? '@general:terms.interface.filter.no-filter-definitions'\n : '@general:terms.interface.filter.placeholder'\n )\n | translate\n | async\n \"\n #tagBox\n >\n <ax-suffix class=\"ax-hidden md:ax-block\"><span class=\"ax-text-gray-500\">Ctrl+F</span></ax-suffix>\n </ax-tag-box>\n\n <ng-template #tagTemplate let-item let-index=\"index\">\n <div\n class=\"ax-inline-flex ax-items-center ax-gap-1.5 hover:ax-bg-darkest ax-cursor-pointer ax-rounded-md ax-px-3 ax-py-1 ax-text-sm ax-surface\"\n [class.!ax-bg-primary]=\"item.field === 'all'\"\n [class.!ax-text-white]=\"item.field === 'all'\"\n (click)=\"handleTagClick(item)\"\n >\n <span>{{ item.query }}</span>\n <button (click)=\"handleRemoveTag($event, index)\" type=\"button\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n </div>\n </ng-template>\n</div>\n\n<ax-popover\n [offsetY]=\"activeFilter() ? -30 : 0\"\n [target]=\"tagBoxInput\"\n [openOn]=\"'toggle'\"\n (onOpened)=\"onPopoverOpened($event)\"\n [closeOn]=\"'clickOut'\"\n (onClosed)=\"handlePopoverClosed($event)\"\n [adaptivityEnabled]=\"true\"\n #popover\n>\n <div
|
|
2437
|
+
], template: "<div class=\"ax-flex ax-items-center ax-gap-2 ax-p-2\">\n <ax-button (keydown)=\"handleButtonKeyDown($event)\" (onClick)=\"popover.open()\" #filterButton [look]=\"'blank'\">\n <ax-icon class=\"far fa-bars-filter ax-cursor-pointer\"> </ax-icon>\n </ax-button>\n <ax-tag-box\n #tagBoxComponent\n [ngModel]=\"asyncTags()\"\n (onValueChanged)=\"handleSelectFilters($event)\"\n [textField]=\"'query'\"\n [valueField]=\"'id'\"\n [readonly]=\"filtersDefinitions().length === 0\"\n [look]=\"'none'\"\n [readonlyField]=\"'readOnly'\"\n [tagTemplate]=\"tagTemplate\"\n (onKeyDown)=\"handleKeyDown($event)\"\n [addOnEnter]=\"false\"\n [placeholder]=\"\n (filtersDefinitions().length === 0\n ? '@general:terms.interface.filter.no-filter-definitions'\n : '@general:terms.interface.filter.placeholder'\n )\n | translate\n | async\n \"\n #tagBox\n >\n <ax-suffix class=\"ax-hidden md:ax-block\"><span class=\"ax-text-gray-500\">Ctrl+F</span></ax-suffix>\n </ax-tag-box>\n\n <ng-template #tagTemplate let-item let-index=\"index\">\n <div\n class=\"ax-inline-flex ax-items-center ax-gap-1.5 hover:ax-bg-darkest ax-cursor-pointer ax-rounded-md ax-px-3 ax-py-1 ax-text-sm ax-surface\"\n [class.!ax-bg-primary]=\"item.field === 'all'\"\n [class.!ax-text-white]=\"item.field === 'all'\"\n (click)=\"handleTagClick(item)\"\n >\n <span>{{ item.query }}</span>\n <button (click)=\"handleRemoveTag($event, index)\" type=\"button\">\n <ax-icon class=\"ax-icon ax-icon-close\"></ax-icon>\n </button>\n </div>\n </ng-template>\n</div>\n\n<ax-popover\n [offsetY]=\"activeFilter() ? -30 : 0\"\n [target]=\"tagBoxInput\"\n [openOn]=\"'toggle'\"\n (onOpened)=\"onPopoverOpened($event)\"\n [closeOn]=\"'clickOut'\"\n (onClosed)=\"handlePopoverClosed($event)\"\n [adaptivityEnabled]=\"true\"\n #popover\n>\n <div class=\"md:ax-min-w-72 ax-w-full ax-rounded-md md:ax-max-h-96 ax-max-w-80 md:ax-overflow-auto\">\n <axp-widgets-container [context]=\"context()\" (onContextChanged)=\"onContextChanged($event)\">\n @if (activeFilter()) {\n <div class=\"ax-flex ax-flex-col ax-lightest-surface ax-shadow-md\" (keydown.enter)=\"onEnterKeyPressed($event)\">\n <ax-header class=\"ax-border-b ax-border-light ax-px-4 ax-py-2\">{{\n activeFilter()?.title! | translate | async\n }}</ax-header>\n <ax-content class=\"ax-p-4\">\n <div class=\"ax-mb-2\">\n <ax-badge [text]=\"(getActiveOperator(activeFilter())! | translate | async) || ''\"></ax-badge>\n </div>\n <ng-container\n #widgetRenderer=\"widgetRenderer\"\n axp-widget-renderer\n [node]=\"{\n type: activeFilter()?.widget?.type || 'text-editor',\n path: activeFilter()?.field,\n options: activeFilter()?.widget?.options,\n }\"\n [mode]=\"'edit'\"\n >\n </ng-container>\n </ax-content>\n <ax-footer class=\"ax-border-t ax-flex ax-justify-end ax-border-light ax-w-full ax-px-4 ax-py-2\">\n <ax-button\n class=\"ax-xs\"\n [text]=\"'@general:actions.apply.title' | translate | async\"\n (onClick)=\"handleApplyFilter()\"\n ></ax-button>\n </ax-footer>\n </div>\n } @else {\n <div axListNavigation #list=\"axListNavigation\" class=\"axp-list-items\">\n <!-- @if (tagBox.inputValue()) {\n @for (inlineFilter of inlineFilters(); track inlineFilter.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n tabindex=\"0\"\n (click)=\"handleSelectInlineFilter(inlineFilter)\"\n (keydown)=\"handleInlineFilterKeyDown($event, inlineFilter)\"\n >\n {{ inlineFilter.title | translate | async }} {{ getActiveOperator(inlineFilter) }} '{{\n tagBox.inputValue()\n }}'\n </div>\n }\n <span class=\"ax-w-full ax-border-t ax-border-light ax-my-1\"></span>\n } -->\n @for (field of filterFields(); track field.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n (click)=\"handleSelectField(field)\"\n (keydown)=\"handleFieldKeyDown($event, field)\"\n tabindex=\"0\"\n >\n <div class=\"ax-flex ax-items-end ax-gap-2\">\n <ax-icon class=\"ax-w-5\" [class]=\"'fa-light ' + field.icon\"> </ax-icon>\n {{ field.title | translate | async }}\n </div>\n </div>\n }\n </div>\n }\n </axp-widgets-container>\n </div>\n</ax-popover>\n", styles: ["axp-query-filters{width:100%}.axp-list-items{display:flex;min-width:10rem;flex-direction:column;border-radius:.375rem;border-width:1px;padding-top:1rem;padding-bottom:1rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-list-items>div{min-width:7rem;cursor:pointer;padding:.5rem 1rem;text-align:start}.axp-list-items>div:focus{outline:none}.axp-list-items>div.axp-state-focused,.axp-list-items>div:hover{background-color:rgb(var(--ax-sys-color-surface));color:rgb(var(--ax-sys-color-on-surface));border-color:rgb(var(--ax-sys-color-border-surface))}\n"] }]
|
|
2707
2438
|
}], propDecorators: { filtersDefinitions: [{ type: i0.Input, args: [{ isSignal: true, alias: "filtersDefinitions", required: false }] }], initialFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialFilters", required: false }] }], onFiltersChanged: [{ type: i0.Output, args: ["onFiltersChanged"] }], tagBox: [{ type: i0.ViewChild, args: ['tagBox', { isSignal: true }] }], widgetRenderer: [{ type: i0.ViewChild, args: ['widgetRenderer', { isSignal: true }] }], listItems: [{
|
|
2708
2439
|
type: ViewChildren,
|
|
2709
2440
|
args: ['caseItem']
|
|
@@ -2877,6 +2608,50 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2877
2608
|
args: [{ providedIn: 'root' }]
|
|
2878
2609
|
}] });
|
|
2879
2610
|
|
|
2611
|
+
class AXPLogoComponent {
|
|
2612
|
+
constructor() {
|
|
2613
|
+
this.platform = inject(AXPlatform);
|
|
2614
|
+
}
|
|
2615
|
+
ngOnInit() {
|
|
2616
|
+
this.setLogoType();
|
|
2617
|
+
this.platform.themeMode$.subscribe(() => {
|
|
2618
|
+
this.setLogoTheme();
|
|
2619
|
+
});
|
|
2620
|
+
}
|
|
2621
|
+
ngOnChanges() {
|
|
2622
|
+
this.setLogoTheme();
|
|
2623
|
+
this.setLogoType();
|
|
2624
|
+
}
|
|
2625
|
+
setLogoType() {
|
|
2626
|
+
switch (true) {
|
|
2627
|
+
case this.source instanceof AXPImageUrlLogoConfig:
|
|
2628
|
+
this.logoType = 'url';
|
|
2629
|
+
break;
|
|
2630
|
+
case this.source instanceof AXPComponentLogoConfig:
|
|
2631
|
+
this.logoType = 'component';
|
|
2632
|
+
break;
|
|
2633
|
+
case this.source instanceof AXPIconLogoConfig:
|
|
2634
|
+
this.logoType = 'icon';
|
|
2635
|
+
break;
|
|
2636
|
+
default:
|
|
2637
|
+
break;
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
setLogoTheme() {
|
|
2641
|
+
if (this.source && this.source.dark && this.source.light) {
|
|
2642
|
+
this.source = this.platform.isDark() ? this.source.dark : this.source.light;
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2646
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPLogoComponent, isStandalone: true, selector: "axp-logo", inputs: { source: "source" }, host: { classAttribute: "ax-flex ax-justify-center" }, usesOnChanges: true, ngImport: i0, template: "@switch (logoType) { \n @case ('url') {\n <ax-image [width]=\"source.width\" [height]=\"source.height\" [src]=\"source.url\"></ax-image>\n } \n @case ('component') {\n <ng-container *ngComponentOutlet=\"source.component\"></ng-container>\n } \n @case ('icon') {\n <i [class]=\"source.icon\" [style.color]=\"source.color\"></i>\n } \n}\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i2$6.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXDecoratorModule }] }); }
|
|
2647
|
+
}
|
|
2648
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLogoComponent, decorators: [{
|
|
2649
|
+
type: Component,
|
|
2650
|
+
args: [{ selector: 'axp-logo', imports: [CommonModule, AXImageModule, AXDecoratorModule], host: { class: 'ax-flex ax-justify-center' }, template: "@switch (logoType) { \n @case ('url') {\n <ax-image [width]=\"source.width\" [height]=\"source.height\" [src]=\"source.url\"></ax-image>\n } \n @case ('component') {\n <ng-container *ngComponentOutlet=\"source.component\"></ng-container>\n } \n @case ('icon') {\n <i [class]=\"source.icon\" [style.color]=\"source.color\"></i>\n } \n}\n\n" }]
|
|
2651
|
+
}], propDecorators: { source: [{
|
|
2652
|
+
type: Input
|
|
2653
|
+
}] } });
|
|
2654
|
+
|
|
2880
2655
|
//#region ---- Imports ----
|
|
2881
2656
|
//#endregion
|
|
2882
2657
|
//#region ---- Service Interface ----
|
|
@@ -3440,1092 +3215,1048 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
3440
3215
|
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'axp-menu-customizer' }, template: "<!-- i18n path constants -->\n@let i18nBase = '@platform-management:menu-management';\n@let i18nEmptyStates = i18nBase + '.components.menu-list.empty-states';\n@let i18nActions = i18nBase + '.actions';\n\n<!-- Loading State -->\n@if (isLoading()) {\n <axp-state-message\n mode=\"loading\"\n icon=\"fa-light fa-spinner-third fa-spin\"\n [title]=\"(i18nEmptyStates + '.loading.title' | translate | async)!\"\n [description]=\"(i18nEmptyStates + '.loading.description' | translate | async)!\"\n />\n}\n\n<!-- Error State -->\n@else if (hasError()) {\n <axp-state-message\n mode=\"error\"\n icon=\"fa-light fa-circle-exclamation\"\n [title]=\"(i18nEmptyStates + '.error.title' | translate | async)!\"\n [description]=\"(i18nEmptyStates + '.error.description' | translate | async)!\"\n >\n <ax-button\n slot=\"actions\"\n [text]=\"'@general:actions.retry.title' | translate | async\"\n look=\"outline\"\n color=\"primary\"\n (onClick)=\"loadMenuItems()\"\n >\n <i class=\"fa-light fa-rotate-left\"></i>\n </ax-button>\n </axp-state-message>\n}\n\n<!-- Empty State -->\n@else if (showEmptyState()) {\n <axp-state-message\n mode=\"empty\"\n icon=\"fa-light fa-bars\"\n [title]=\"(i18nEmptyStates + '.no-data.title' | translate | async)!\"\n [description]=\"(i18nEmptyStates + '.no-data.description' | translate | async)!\"\n >\n @if (allowAddItems()) {\n <ax-button\n slot=\"actions\"\n [text]=\"i18nActions + '.add-root.title' | translate | async\"\n look=\"solid\"\n color=\"primary\"\n (onClick)=\"addRootMenuItem()\"\n >\n <i class=\"fa-light fa-plus\"></i>\n </ax-button>\n }\n </axp-state-message>\n}\n\n<!-- Main Content -->\n@else if (showContent()) {\n <!-- Toolbar -->\n @if (showToolbar()) {\n <div class=\"axp-menu-customizer__toolbar\">\n @if (allowAddItems()) {\n <ax-button\n [text]=\"i18nActions + '.add-root.title' | translate | async\"\n look=\"solid\"\n color=\"primary\"\n (onClick)=\"addRootMenuItem()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button>\n }\n\n <div class=\"axp-menu-customizer__toolbar-spacer\"></div>\n <!-- \n <ax-button\n [text]=\"i18nActions + '.collapse.title' | translate | async\"\n look=\"outline\"\n (onClick)=\"collapseAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-minus-square\"></i>\n </ax-prefix>\n </ax-button>\n\n <ax-button\n [text]=\"i18nActions + '.expand.title' | translate | async\"\n look=\"outline\"\n (onClick)=\"expandAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus-square\"></i>\n </ax-prefix>\n </ax-button> -->\n\n <ax-button\n [text]=\"i18nActions + '.reset.title' | translate | async\"\n look=\"outline\"\n color=\"danger\"\n (onClick)=\"resetCustomizations()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-rotate-left\"></i>\n </ax-prefix>\n </ax-button>\n </div>\n }\n\n <!-- Menu Tree -->\n <div class=\"axp-menu-customizer__container\">\n <div class=\"axp-menu-customizer__tree\">\n <ax-tree-view\n [(datasource)]=\"treeNodes\"\n look=\"default\"\n [nodeTemplate]=\"itemTemplate\"\n selectMode=\"none\"\n [showIcons]=\"false\"\n [showChildrenBadge]=\"false\"\n [dragBehavior]=\"dragBehavior()\"\n [dragArea]=\"dragArea()\"\n (onBeforeDrop)=\"handleBeforeDrop($event)\"\n (onOrderChange)=\"handleOrderChange($event)\"\n (onMoveChange)=\"handleMoveChange($event)\"\n />\n </div>\n </div>\n}\n\n<!-- Custom Item Template -->\n<ng-template #itemTemplate let-node=\"node\" let-level=\"level\">\n @let nodeData = node['data'];\n @let item = nodeData.menuItem;\n @let metadata = nodeData.metadata;\n @let isGroup = item.type === 'group';\n @let isBreak = item.type === 'break';\n @let isMenu = item.type === 'menu' || !item.type;\n @let canAddChild = !item.path && isMenu && allowAddItems();\n @let canToggleVisibility = item.name && metadata.isBuiltIn;\n @let canDelete = item.name && metadata.isCustom;\n @let i18nStates = '@platform-management:menu-management.states';\n\n <div\n class=\"axp-menu-customizer__item\"\n [class.axp-menu-customizer__item--hidden]=\"metadata.isHidden\"\n [class.axp-menu-customizer__item--custom]=\"metadata.isCustom\"\n [class.axp-menu-customizer__item--group]=\"isGroup\"\n >\n <!-- Icon (hidden for groups) -->\n @if (item.icon && !isGroup) {\n <i class=\"axp-menu-customizer__item-icon\" [class]=\"item.icon\"></i>\n }\n\n <!-- Content based on item type -->\n @if (isGroup) {\n <span class=\"axp-menu-customizer__item-group\">\n <i class=\"fa-light fa-layer-group\"></i>\n {{ item.text | translate | async }}\n </span>\n } @else if (isBreak) {\n <span class=\"axp-menu-customizer__item-divider\">\n <i class=\"fa-light fa-minus\"></i>\n {{ i18nStates + '.divider' | translate | async }}\n </span>\n } @else if (item.text) {\n <span class=\"axp-menu-customizer__item-text\">\n {{ item.text | translate | async }}\n </span>\n } @else if (item.path) {\n <span class=\"axp-menu-customizer__item-path\">\n <i class=\"fa-light fa-link\"></i>\n {{ item.path }}\n </span>\n }\n\n <!-- Menu Name/Key -->\n @if (item.name) {\n <code class=\"axp-menu-customizer__item-name\">{{ item.name }}</code>\n }\n\n <!-- Status Badges -->\n @if (metadata.isHidden) {\n <ax-badge [text]=\"(i18nStates + '.hidden' | translate | async)!\" color=\"danger\" />\n } @else if (metadata.isCustom) {\n <ax-badge [text]=\"(i18nStates + '.custom' | translate | async)!\" color=\"success\" />\n } @else if (metadata.isBuiltIn) {\n <ax-badge [text]=\"(i18nStates + '.built-in' | translate | async)!\" color=\"primary\" />\n }\n\n <!-- Actions Dropdown -->\n <ax-button class=\"axp-menu-customizer__item-actions\" look=\"blank\" size=\"sm\" [iconOnly]=\"true\">\n <ax-prefix>\n <i class=\"fa-light fa-ellipsis-vertical\"></i>\n </ax-prefix>\n\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n <!-- Edit (only for items with names) -->\n @if (item.name) {\n <ax-button-item\n [text]=\"('@general:actions.edit.title' | translate | async)!\"\n (onClick)=\"onAction('edit', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-edit\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Show/Hide (only for built-in items with names) -->\n @if (canToggleVisibility) {\n @if (metadata.isHidden) {\n <ax-button-item\n [text]=\"(i18nActions + '.show.title' | translate | async)!\"\n (onClick)=\"onAction('show', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-eye\"></i>\n </ax-prefix>\n </ax-button-item>\n } @else {\n <ax-button-item\n [text]=\"(i18nActions + '.hide.title' | translate | async)!\"\n (onClick)=\"onAction('hide', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-eye-slash\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n }\n\n <!-- Add Child -->\n @if (canAddChild) {\n <ax-button-item\n [text]=\"(i18nActions + '.add-child.title' | translate | async)!\"\n (onClick)=\"onAction('add-child', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Delete (only for custom items with names) -->\n @if (canDelete) {\n <ax-divider />\n <ax-button-item\n color=\"danger\"\n [text]=\"('@general:actions.delete.title' | translate | async)!\"\n (onClick)=\"onAction('delete', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-trash\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Info message for items without names -->\n @if (!item.name) {\n <ax-divider />\n <div class=\"ax-p-2 ax-text-xs ax-text-neutral-500 ax-italic\">\n {{ i18nBase + '.messages.info.no-name' | translate | async }}\n </div>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n</ng-template>\n", styles: [".axp-menu-customizer{display:flex;height:100%;min-height:0px;flex-direction:column}.axp-menu-customizer__toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;padding:1rem;border-bottom-width:1px;border-style:solid;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1));flex-shrink:0}.axp-menu-customizer__toolbar-spacer{min-width:1rem;flex:1 1 0%}.axp-menu-customizer__container{display:flex;flex-direction:column;gap:1rem;padding:1rem;min-height:0px;flex:1 1 0%;overflow:auto}.axp-menu-customizer__tree{display:flex;flex-direction:column;gap:.5rem}.axp-menu-customizer__tree ax-tree-view{flex:1 1 0%}.axp-menu-customizer__item{display:flex;flex:1 1 0%;align-items:center;gap:.75rem;border-radius:.375rem;padding:.5rem .75rem;border-width:1px;border-style:solid;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;animation-duration:.15s}.axp-menu-customizer__item:hover{--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity, 1))}.axp-menu-customizer__item--hidden{opacity:.5}.axp-menu-customizer__item--hidden .axp-menu-customizer__item-text,.axp-menu-customizer__item--hidden .axp-menu-customizer__item-icon{text-decoration-line:line-through}.axp-menu-customizer__item--custom{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-200),var(--tw-border-opacity, 1));background-color:rgba(var(--ax-sys-color-primary-50),.3)}.axp-menu-customizer__item--group{padding-top:.75rem;padding-bottom:.75rem;--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity, 1))}.axp-menu-customizer__item-icon{display:flex;align-items:center;justify-content:center;height:1.5rem;width:1.5rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-600),var(--tw-text-opacity, 1));flex-shrink:0}.axp-menu-customizer__item-text{min-width:0px;flex:1 1 0%;font-size:.875rem;line-height:1.25rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-menu-customizer__item-group{display:flex;flex:1 1 0%;align-items:center;gap:.5rem;font-size:.75rem;line-height:1rem;text-transform:uppercase;font-style:italic;--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1));letter-spacing:.025em}.axp-menu-customizer__item-group i{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-menu-customizer__item-divider,.axp-menu-customizer__item-path{display:flex;flex:1 1 0%;align-items:center;gap:.5rem;font-size:.75rem;line-height:1rem;font-style:italic;--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1));min-width:0px}.axp-menu-customizer__item-divider i,.axp-menu-customizer__item-path i{flex-shrink:0;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-menu-customizer__item-name{display:inline-flex;align-items:center;border-radius:.25rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;--tw-bg-opacity: 1;background-color:rgb(245 245 245 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1));font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:400;border-width:1px;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1));-webkit-user-select:all;user-select:all;max-width:12rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.axp-menu-customizer__item-actions{margin-left:auto;flex-shrink:0;opacity:.6;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;animation-duration:.15s}.axp-menu-customizer__item:hover .axp-menu-customizer__item-actions{opacity:1}\n"] }]
|
|
3441
3216
|
}], propDecorators: { scopeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "scopeKey", required: true }] }], showToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToolbar", required: false }] }], allowAddItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowAddItems", required: false }] }], dragBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragBehavior", required: false }] }], dragArea: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragArea", required: false }] }], saved: [{ type: i0.Output, args: ["saved"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }], tree: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXTreeViewComponent), { isSignal: true }] }] } });
|
|
3442
3217
|
|
|
3443
|
-
|
|
3444
|
-
class AXPSpreadsheetComponent {
|
|
3218
|
+
class AXPPropertyViewerComponent {
|
|
3445
3219
|
//#endregion
|
|
3446
|
-
//#region ---- Lifecycle Methods ----
|
|
3447
3220
|
constructor() {
|
|
3448
|
-
//#endregion
|
|
3449
|
-
//#region ---- Services & Dependencies ----
|
|
3450
|
-
this.translationService = inject(AXTranslationService);
|
|
3451
|
-
//#endregion
|
|
3452
|
-
//#region ---- Computed Properties for Translations ----
|
|
3453
|
-
/**
|
|
3454
|
-
* Translated column titles
|
|
3455
|
-
*/
|
|
3456
|
-
this.translatedColumnTitles = signal(new Map(), ...(ngDevMode ? [{ debugName: "translatedColumnTitles" }] : []));
|
|
3457
|
-
//#endregion
|
|
3458
3221
|
//#region ---- Inputs ----
|
|
3459
3222
|
/**
|
|
3460
|
-
*
|
|
3461
|
-
*/
|
|
3462
|
-
this.title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
3463
|
-
/**
|
|
3464
|
-
* Column definitions
|
|
3465
|
-
*/
|
|
3466
|
-
this.columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
3467
|
-
/**
|
|
3468
|
-
* Row mode: 'fixed' or 'dynamic'
|
|
3469
|
-
*/
|
|
3470
|
-
this.rowMode = input('fixed', ...(ngDevMode ? [{ debugName: "rowMode" }] : []));
|
|
3471
|
-
/**
|
|
3472
|
-
* Rows data (for fixed mode - input only)
|
|
3473
|
-
* Each row must have a 'name' property for identification
|
|
3474
|
-
*/
|
|
3475
|
-
this.rowsInput = input([], ...(ngDevMode ? [{ debugName: "rowsInput" }] : []));
|
|
3476
|
-
/**
|
|
3477
|
-
* Rows data (for dynamic mode - two-way binding)
|
|
3478
|
-
*/
|
|
3479
|
-
this.rowsModel = model([], ...(ngDevMode ? [{ debugName: "rowsModel" }] : []));
|
|
3480
|
-
/**
|
|
3481
|
-
* Whether the spreadsheet is in readonly mode
|
|
3482
|
-
*/
|
|
3483
|
-
this.readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
|
|
3484
|
-
/**
|
|
3485
|
-
* Placeholder text for empty cells (default: "–")
|
|
3486
|
-
*/
|
|
3487
|
-
this.emptyCellPlaceholder = input('–', ...(ngDevMode ? [{ debugName: "emptyCellPlaceholder" }] : []));
|
|
3488
|
-
/**
|
|
3489
|
-
* Path to property in row object to display as row header title
|
|
3490
|
-
* Example: 'name', 'title', 'user.name'
|
|
3491
|
-
*/
|
|
3492
|
-
this.rowTitlePath = input(null, ...(ngDevMode ? [{ debugName: "rowTitlePath" }] : []));
|
|
3493
|
-
/**
|
|
3494
|
-
* Path to property in row object to display as row header description
|
|
3495
|
-
* Example: 'description', 'details', 'user.description'
|
|
3496
|
-
*/
|
|
3497
|
-
this.rowDescriptionPath = input(null, ...(ngDevMode ? [{ debugName: "rowDescriptionPath" }] : []));
|
|
3498
|
-
/**
|
|
3499
|
-
* Whether to allow adding rows (dynamic mode only, default: true)
|
|
3223
|
+
* List of tabs that should be rendered inside the property viewer.
|
|
3500
3224
|
*/
|
|
3501
|
-
this.
|
|
3225
|
+
this.tabsInput = input([], ...(ngDevMode ? [{ debugName: "tabsInput" }] : []));
|
|
3502
3226
|
/**
|
|
3503
|
-
*
|
|
3504
|
-
* Can be enabled for fixed mode if needed
|
|
3227
|
+
* Determines rendering mode.
|
|
3505
3228
|
*/
|
|
3506
|
-
this.
|
|
3229
|
+
this.mode = input('simple', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
3507
3230
|
//#endregion
|
|
3508
3231
|
//#region ---- Outputs ----
|
|
3509
3232
|
/**
|
|
3510
|
-
*
|
|
3511
|
-
*/
|
|
3512
|
-
this.cellChange = output();
|
|
3513
|
-
/**
|
|
3514
|
-
* Emitted when rows are added or removed (dynamic mode only)
|
|
3515
|
-
*/
|
|
3516
|
-
this.rowChange = output();
|
|
3517
|
-
/**
|
|
3518
|
-
* Emitted when the entire spreadsheet data changes
|
|
3233
|
+
* Emits when property context changes.
|
|
3519
3234
|
*/
|
|
3520
|
-
this.
|
|
3235
|
+
this.onChanged = new EventEmitter();
|
|
3521
3236
|
//#endregion
|
|
3522
|
-
//#region ----
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3237
|
+
//#region ---- Signals ----
|
|
3238
|
+
this.currentTabIndex = signal(0, ...(ngDevMode ? [{ debugName: "currentTabIndex" }] : []));
|
|
3239
|
+
this.tabs = computed(() => {
|
|
3240
|
+
const incomingTabs = this.tabsInput() ?? [];
|
|
3241
|
+
return incomingTabs
|
|
3242
|
+
.map((tab) => ({
|
|
3243
|
+
...tab,
|
|
3244
|
+
groups: (tab.groups ?? [])
|
|
3245
|
+
.map((group) => ({
|
|
3246
|
+
...group,
|
|
3247
|
+
isCollapsed: group.isCollapsed ?? false,
|
|
3248
|
+
props: (group.props ?? []).filter((prop) => prop.visible !== false),
|
|
3249
|
+
}))
|
|
3250
|
+
.filter((group) => group.props.length > 0),
|
|
3251
|
+
}))
|
|
3252
|
+
.filter((tab) => tab.groups.length > 0);
|
|
3253
|
+
}, ...(ngDevMode ? [{ debugName: "tabs" }] : []));
|
|
3254
|
+
this.groups = computed(() => {
|
|
3255
|
+
const preparedTabs = this.tabs();
|
|
3256
|
+
if (!preparedTabs.length) {
|
|
3257
|
+
return [];
|
|
3258
|
+
}
|
|
3259
|
+
const index = Math.min(this.currentTabIndex(), preparedTabs.length - 1);
|
|
3260
|
+
if (index !== this.currentTabIndex()) {
|
|
3261
|
+
this.currentTabIndex.set(index);
|
|
3262
|
+
}
|
|
3263
|
+
return preparedTabs[index].groups.map((group) => ({
|
|
3264
|
+
...group,
|
|
3265
|
+
isCollapsed: this.groupCollapsedStates.get(group.name) ?? !!group.isCollapsed,
|
|
3266
|
+
}));
|
|
3267
|
+
}, ...(ngDevMode ? [{ debugName: "groups" }] : []));
|
|
3268
|
+
this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
3535
3269
|
/**
|
|
3536
|
-
*
|
|
3270
|
+
* Per-expression-path override for "use expression" vs "use value" when binding.enabled.
|
|
3271
|
+
* Updated when user toggles the ax-switch; otherwise derived from isExpression(valueAtPath).
|
|
3537
3272
|
*/
|
|
3538
|
-
this.
|
|
3539
|
-
/**
|
|
3540
|
-
* Cache for widget nodes to prevent re-rendering
|
|
3541
|
-
* Key: `${rowIndex}_${columnName}`, Value: AXPWidgetNode
|
|
3542
|
-
*/
|
|
3543
|
-
this.widgetNodeCache = new Map();
|
|
3544
|
-
/**
|
|
3545
|
-
* Cache for cell values to detect actual changes
|
|
3546
|
-
* Key: `${rowIndex}_${columnName}`, Value: any
|
|
3547
|
-
*/
|
|
3548
|
-
this.cellValueCache = new Map();
|
|
3273
|
+
this.expressionModeState = signal({}, ...(ngDevMode ? [{ debugName: "expressionModeState" }] : []));
|
|
3549
3274
|
//#endregion
|
|
3550
|
-
//#region ----
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
}
|
|
3561
|
-
}, ...(ngDevMode ? [{ debugName: "currentRows" }] : []));
|
|
3562
|
-
/**
|
|
3563
|
-
* Context for widgets-container (all rows as an object with rows array)
|
|
3564
|
-
* This allows widgets to access their cell via path like: rows[index].column.path
|
|
3565
|
-
*/
|
|
3566
|
-
this.spreadsheetContext = computed(() => {
|
|
3567
|
-
return {
|
|
3568
|
-
rows: this.currentRows(),
|
|
3569
|
-
};
|
|
3570
|
-
}, ...(ngDevMode ? [{ debugName: "spreadsheetContext" }] : []));
|
|
3571
|
-
/**
|
|
3572
|
-
* Get rows with IDs (ensure all rows have identifiers)
|
|
3573
|
-
*/
|
|
3574
|
-
this.rowsWithIds = computed(() => {
|
|
3575
|
-
const rows = this.currentRows();
|
|
3576
|
-
const mode = this.rowMode();
|
|
3577
|
-
const result = [];
|
|
3578
|
-
rows.forEach((row, index) => {
|
|
3579
|
-
let rowId;
|
|
3580
|
-
if (mode === 'fixed') {
|
|
3581
|
-
// Fixed mode: use 'name' property
|
|
3582
|
-
rowId = row['name'] || `row_${index}`;
|
|
3583
|
-
}
|
|
3584
|
-
else {
|
|
3585
|
-
// Dynamic mode: generate ID if not exists
|
|
3586
|
-
if (!row['_id']) {
|
|
3587
|
-
row['_id'] = this.generateRowId();
|
|
3588
|
-
}
|
|
3589
|
-
rowId = row['_id'];
|
|
3275
|
+
//#region ---- Properties ----
|
|
3276
|
+
this.groupCollapsedStates = new Map();
|
|
3277
|
+
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
3278
|
+
this.popupService = inject(AXPopupService);
|
|
3279
|
+
effect(() => {
|
|
3280
|
+
const availableTabs = this.tabs();
|
|
3281
|
+
const availableGroups = availableTabs.flatMap((tab) => tab.groups);
|
|
3282
|
+
availableGroups.forEach((group) => {
|
|
3283
|
+
if (!this.groupCollapsedStates.has(group.name) && group.isCollapsed !== undefined) {
|
|
3284
|
+
this.groupCollapsedStates.set(group.name, !!group.isCollapsed);
|
|
3590
3285
|
}
|
|
3591
|
-
// Update row ID map
|
|
3592
|
-
this.rowIdMap.set(rowId, index);
|
|
3593
|
-
result.push({ rowId, row });
|
|
3594
3286
|
});
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
this.isEmpty = computed(() => {
|
|
3601
|
-
const columns = this.columns();
|
|
3602
|
-
const rows = this.currentRows();
|
|
3603
|
-
return (!columns || columns.length === 0) && (!rows || rows.length === 0);
|
|
3604
|
-
}, ...(ngDevMode ? [{ debugName: "isEmpty" }] : []));
|
|
3605
|
-
/**
|
|
3606
|
-
* Check if columns are empty (regardless of rows)
|
|
3607
|
-
* When columns are empty, we should show a message about missing columns, not rows
|
|
3608
|
-
*/
|
|
3609
|
-
this.isColumnsEmpty = computed(() => {
|
|
3610
|
-
const columns = this.columns();
|
|
3611
|
-
return !columns || columns.length === 0;
|
|
3612
|
-
}, ...(ngDevMode ? [{ debugName: "isColumnsEmpty" }] : []));
|
|
3613
|
-
/**
|
|
3614
|
-
* Check if only rows are empty (columns exist but no rows)
|
|
3615
|
-
*/
|
|
3616
|
-
this.isRowsEmpty = computed(() => {
|
|
3617
|
-
const columns = this.columns();
|
|
3618
|
-
const rows = this.currentRows();
|
|
3619
|
-
return (columns && columns.length > 0) && (!rows || rows.length === 0);
|
|
3620
|
-
}, ...(ngDevMode ? [{ debugName: "isRowsEmpty" }] : []));
|
|
3621
|
-
// Initialize rows from input (fixed mode)
|
|
3622
|
-
this.internalRows.set(this.rowsInput());
|
|
3623
|
-
// Watch for rowsInput changes and update internalRows (fixed mode only)
|
|
3624
|
-
effect(() => {
|
|
3625
|
-
const rowsInput = this.rowsInput();
|
|
3626
|
-
const rowMode = this.rowMode();
|
|
3627
|
-
// Only update internalRows in fixed mode
|
|
3628
|
-
if (rowMode === 'fixed') {
|
|
3629
|
-
this.internalRows.set(rowsInput);
|
|
3287
|
+
if (!availableTabs.length) {
|
|
3288
|
+
this.currentTabIndex.set(0);
|
|
3289
|
+
}
|
|
3290
|
+
else if (this.currentTabIndex() >= availableTabs.length) {
|
|
3291
|
+
this.currentTabIndex.set(0);
|
|
3630
3292
|
}
|
|
3631
3293
|
});
|
|
3632
3294
|
}
|
|
3633
|
-
//#
|
|
3634
|
-
//#region ---- Cell Value Methods ----
|
|
3295
|
+
//#region ---- Public Methods ----
|
|
3635
3296
|
/**
|
|
3636
|
-
*
|
|
3297
|
+
* Replaces the current context with the provided value and emits an init event.
|
|
3637
3298
|
*/
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
}
|
|
3644
|
-
const column = this.columns().find((col) => col.name === columnName);
|
|
3645
|
-
if (!column) {
|
|
3646
|
-
return null;
|
|
3647
|
-
}
|
|
3648
|
-
return get(row, column.path, null);
|
|
3299
|
+
initializeContext(value) {
|
|
3300
|
+
untracked(() => {
|
|
3301
|
+
this.context.set(cloneDeep(value ?? {}));
|
|
3302
|
+
this.onChanged.emit({ values: this.context(), mode: 'init' });
|
|
3303
|
+
});
|
|
3649
3304
|
}
|
|
3650
3305
|
/**
|
|
3651
|
-
*
|
|
3306
|
+
* Merges the provided value into the current context and emits an update event.
|
|
3652
3307
|
*/
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3308
|
+
update(value) {
|
|
3309
|
+
untracked(() => {
|
|
3310
|
+
this.context.set(merge(cloneDeep(this.context()), value ?? {}));
|
|
3311
|
+
this.onChanged.emit({ values: this.context(), mode: 'update' });
|
|
3312
|
+
});
|
|
3658
3313
|
}
|
|
3314
|
+
//#endregion
|
|
3315
|
+
//#region ---- Event Handlers ----
|
|
3659
3316
|
/**
|
|
3660
|
-
*
|
|
3317
|
+
* Handles context changes produced by rendered widgets.
|
|
3661
3318
|
*/
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3319
|
+
handleContextChange(event) {
|
|
3320
|
+
untracked(() => {
|
|
3321
|
+
this.context.set(event.data);
|
|
3322
|
+
this.onChanged.emit({ values: this.context(), mode: event.state === 'initiated' ? 'init' : 'update' });
|
|
3323
|
+
});
|
|
3667
3324
|
}
|
|
3668
3325
|
/**
|
|
3669
|
-
*
|
|
3326
|
+
* Handles tab selection changes.
|
|
3670
3327
|
*/
|
|
3671
|
-
|
|
3672
|
-
const
|
|
3673
|
-
|
|
3674
|
-
|
|
3328
|
+
handleTabChange(event) {
|
|
3329
|
+
const index = event.index;
|
|
3330
|
+
if (this.currentTabIndex() !== index) {
|
|
3331
|
+
this.currentTabIndex.set(index);
|
|
3332
|
+
}
|
|
3675
3333
|
}
|
|
3676
3334
|
/**
|
|
3677
|
-
*
|
|
3335
|
+
* Stores collapsed state for a group.
|
|
3678
3336
|
*/
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
return editing?.rowId === rowId && editing?.columnName === columnName;
|
|
3337
|
+
handleCollapsedChange(groupName, isCollapsed) {
|
|
3338
|
+
this.groupCollapsedStates.set(groupName, isCollapsed);
|
|
3682
3339
|
}
|
|
3683
3340
|
/**
|
|
3684
|
-
*
|
|
3341
|
+
* Returns the config path used for the binding value (and expression) for a property with binding.enabled.
|
|
3685
3342
|
*/
|
|
3686
|
-
|
|
3687
|
-
|
|
3343
|
+
getExpressionPath(prop) {
|
|
3344
|
+
const basePath = prop.schema?.interface?.path ?? prop.name;
|
|
3345
|
+
return prop.binding?.optionKey ? `${basePath}.${prop.binding.optionKey}` : basePath;
|
|
3688
3346
|
}
|
|
3689
3347
|
/**
|
|
3690
|
-
*
|
|
3691
|
-
*
|
|
3692
|
-
* Uses caching to prevent unnecessary re-renders
|
|
3348
|
+
* True when the property is in "expression" mode: show only the expression editor button, not the widget.
|
|
3349
|
+
* Uses expressionModeState when set; otherwise derives from isExpression(valueAtPath).
|
|
3693
3350
|
*/
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
const
|
|
3697
|
-
const
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
// Get or create widget node
|
|
3701
|
-
let widgetNode = this.widgetNodeCache.get(cacheKey);
|
|
3702
|
-
if (!widgetNode) {
|
|
3703
|
-
// Create path: rows[index].column.path
|
|
3704
|
-
const dynamicPath = `rows.${rowIndex}.${column.path}`;
|
|
3705
|
-
// Create new widget node
|
|
3706
|
-
widgetNode = {
|
|
3707
|
-
...column.widget,
|
|
3708
|
-
path: dynamicPath,
|
|
3709
|
-
defaultValue: currentValue !== null && currentValue !== undefined ? currentValue : column.widget.defaultValue,
|
|
3710
|
-
};
|
|
3711
|
-
// Cache the widget node
|
|
3712
|
-
this.widgetNodeCache.set(cacheKey, widgetNode);
|
|
3713
|
-
this.cellValueCache.set(cacheKey, currentValue);
|
|
3714
|
-
}
|
|
3715
|
-
else {
|
|
3716
|
-
// Update path in case row index changed (shouldn't happen, but be safe)
|
|
3717
|
-
widgetNode.path = `rows.${rowIndex}.${column.path}`;
|
|
3718
|
-
// Only update defaultValue if value actually changed (to prevent re-renders)
|
|
3719
|
-
if (cachedValue !== currentValue) {
|
|
3720
|
-
widgetNode.defaultValue = currentValue !== null && currentValue !== undefined ? currentValue : column.widget.defaultValue;
|
|
3721
|
-
this.cellValueCache.set(cacheKey, currentValue);
|
|
3722
|
-
}
|
|
3351
|
+
isExpressionMode(prop) {
|
|
3352
|
+
this.expressionModeState(); // dependency for change detection
|
|
3353
|
+
const path = this.getExpressionPath(prop);
|
|
3354
|
+
const stored = this.expressionModeState()[path];
|
|
3355
|
+
if (stored !== undefined) {
|
|
3356
|
+
return stored;
|
|
3723
3357
|
}
|
|
3724
|
-
|
|
3358
|
+
const v = get(this.context(), path);
|
|
3359
|
+
return this.expressionEvaluator.isExpression(typeof v === 'string' ? v : '');
|
|
3725
3360
|
}
|
|
3726
|
-
//#endregion
|
|
3727
|
-
//#region ---- Event Handlers ----
|
|
3728
3361
|
/**
|
|
3729
|
-
*
|
|
3362
|
+
* Returns the default value when switching from expression to value mode.
|
|
3363
|
+
* Source of truth is prop.schema.defaultValue (widget.types): plain value, or function (context) => value.
|
|
3364
|
+
* A minimal dataType fallback is used only when the schema provides no default.
|
|
3730
3365
|
*/
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3366
|
+
getDefaultValueForProperty(prop) {
|
|
3367
|
+
const def = prop.schema?.defaultValue;
|
|
3368
|
+
if (typeof def === 'function') {
|
|
3369
|
+
return def(this.context());
|
|
3734
3370
|
}
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
const target = event.target;
|
|
3738
|
-
if (target.closest('.__cell-toolbar') || target.closest('ax-button')) {
|
|
3739
|
-
return;
|
|
3740
|
-
}
|
|
3371
|
+
if (def !== undefined && def !== null) {
|
|
3372
|
+
return def;
|
|
3741
3373
|
}
|
|
3742
|
-
const
|
|
3743
|
-
|
|
3744
|
-
|
|
3374
|
+
const dataType = prop.schema?.dataType ?? 'string';
|
|
3375
|
+
switch (dataType) {
|
|
3376
|
+
case 'boolean':
|
|
3377
|
+
return false;
|
|
3378
|
+
case 'number':
|
|
3379
|
+
return 0;
|
|
3380
|
+
case 'object':
|
|
3381
|
+
return {};
|
|
3382
|
+
case 'array':
|
|
3383
|
+
return [];
|
|
3384
|
+
default:
|
|
3385
|
+
return '';
|
|
3745
3386
|
}
|
|
3746
|
-
// Don't open if already editing this cell
|
|
3747
|
-
const currentEditing = this.editingCell();
|
|
3748
|
-
if (currentEditing?.rowId === rowId && currentEditing?.columnName === columnName) {
|
|
3749
|
-
return;
|
|
3750
|
-
}
|
|
3751
|
-
// Store original value for cancel functionality
|
|
3752
|
-
const row = this.getRowById(rowId);
|
|
3753
|
-
if (row) {
|
|
3754
|
-
const originalValue = get(row, column.path, null);
|
|
3755
|
-
this.originalCellValue.set(originalValue);
|
|
3756
|
-
}
|
|
3757
|
-
this.editingCell.set({ rowId, columnName });
|
|
3758
3387
|
}
|
|
3759
3388
|
/**
|
|
3760
|
-
*
|
|
3761
|
-
*
|
|
3389
|
+
* Updates the expression/value toggle state for a binding-enabled property.
|
|
3390
|
+
* When switching to value: resets the value at path to a type-appropriate default so the
|
|
3391
|
+
* widget renderer does not receive the expression string (e.g. checkbox gets false, not a string).
|
|
3392
|
+
* When switching to expression: sets the value at path to '{{ }}' so the popup opens with
|
|
3393
|
+
* a clean expression placeholder instead of the previous literal (e.g. true/false).
|
|
3762
3394
|
*/
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
}
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3395
|
+
setExpressionMode(prop, useExpression) {
|
|
3396
|
+
const path = this.getExpressionPath(prop);
|
|
3397
|
+
const currentVal = get(this.context(), path);
|
|
3398
|
+
const currentIsExpression = this.expressionEvaluator.isExpression(typeof currentVal === 'string' ? currentVal : '');
|
|
3399
|
+
this.expressionModeState.update((s) => ({ ...s, [path]: useExpression }));
|
|
3400
|
+
if (!useExpression && currentIsExpression) {
|
|
3401
|
+
const next = cloneDeep(this.context());
|
|
3402
|
+
set(next, path, this.getDefaultValueForProperty(prop));
|
|
3403
|
+
untracked(() => {
|
|
3404
|
+
this.context.set(next);
|
|
3405
|
+
this.onChanged.emit({ values: this.context(), mode: 'update' });
|
|
3406
|
+
});
|
|
3772
3407
|
}
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3408
|
+
else if (useExpression && !currentIsExpression) {
|
|
3409
|
+
const next = cloneDeep(this.context());
|
|
3410
|
+
set(next, path, '{{ }}');
|
|
3411
|
+
untracked(() => {
|
|
3412
|
+
this.context.set(next);
|
|
3413
|
+
this.onChanged.emit({ values: this.context(), mode: 'update' });
|
|
3414
|
+
});
|
|
3776
3415
|
}
|
|
3777
|
-
// Get the new value from the context (widget sets it at rows[index].column.path)
|
|
3778
|
-
const dynamicPath = `rows.${rowIndex}.${column.path}`;
|
|
3779
|
-
const newValue = get(event.data, dynamicPath);
|
|
3780
|
-
// Update the row object directly
|
|
3781
|
-
set(row, column.path, newValue);
|
|
3782
|
-
// Update rows array
|
|
3783
|
-
this.updateRows();
|
|
3784
|
-
// Get rowId for events
|
|
3785
|
-
const rowId = this.rowMode() === 'fixed' ? row['name'] : row['_id'];
|
|
3786
|
-
// Emit events
|
|
3787
|
-
this.cellChange.emit({
|
|
3788
|
-
rowId: rowId || `row_${rowIndex}`,
|
|
3789
|
-
columnName,
|
|
3790
|
-
value: newValue,
|
|
3791
|
-
row: { ...row },
|
|
3792
|
-
});
|
|
3793
|
-
this.spreadsheetChange.emit([...this.currentRows()]);
|
|
3794
|
-
// Don't close edit mode automatically - let user finish editing
|
|
3795
|
-
// Edit mode will close on blur or click outside
|
|
3796
3416
|
}
|
|
3797
3417
|
/**
|
|
3798
|
-
*
|
|
3799
|
-
*
|
|
3418
|
+
* Opens the binding/expression code editor for a property with binding.enabled.
|
|
3419
|
+
* Ensures the value passed to the popup is always a string to avoid code-editor crashes.
|
|
3800
3420
|
*/
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
const
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
}
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
}
|
|
3818
|
-
// Get the new value from event.data
|
|
3819
|
-
const newValue = get(event.data, path);
|
|
3820
|
-
// Update the row object (sync with context)
|
|
3821
|
-
const rows = this.currentRows();
|
|
3822
|
-
const row = rows[rowIndex];
|
|
3823
|
-
if (row) {
|
|
3824
|
-
// The context should already have the updated value, but sync row object to be sure
|
|
3825
|
-
set(row, columnPath, newValue);
|
|
3826
|
-
// Update cache (widget node will update defaultValue on next getCellWidgetNode call)
|
|
3827
|
-
const cacheKey = `${rowIndex}_${column.name}`;
|
|
3828
|
-
this.cellValueCache.set(cacheKey, newValue);
|
|
3829
|
-
// Don't delete widget node cache - just update defaultValue on next access
|
|
3830
|
-
// This prevents re-rendering while still reflecting the new value
|
|
3831
|
-
this.updateRows();
|
|
3832
|
-
// Get rowId for events
|
|
3833
|
-
const rowId = this.rowMode() === 'fixed' ? row['name'] : row['_id'];
|
|
3834
|
-
// Emit events
|
|
3835
|
-
this.cellChange.emit({
|
|
3836
|
-
rowId: rowId || `row_${rowIndex}`,
|
|
3837
|
-
columnName: column.name,
|
|
3838
|
-
value: newValue,
|
|
3839
|
-
row: { ...row },
|
|
3421
|
+
async openBindingEditor(prop) {
|
|
3422
|
+
const expressionPath = this.getExpressionPath(prop);
|
|
3423
|
+
const raw = get(this.context(), expressionPath);
|
|
3424
|
+
const currentValue = typeof raw === 'string' ? raw : '';
|
|
3425
|
+
const { AXPBindingExpressionEditorPopupComponent } = await import('./acorex-platform-layout-components-binding-expression-editor-popup.component-Cb6Lk4Ch.mjs');
|
|
3426
|
+
const result = await this.popupService.open(AXPBindingExpressionEditorPopupComponent, {
|
|
3427
|
+
title: '@general:widgets.triggers.edit-binding-expression',
|
|
3428
|
+
size: 'lg',
|
|
3429
|
+
data: { initialValue: signal(currentValue) },
|
|
3430
|
+
});
|
|
3431
|
+
if (result?.data?.value !== undefined) {
|
|
3432
|
+
const next = cloneDeep(this.context());
|
|
3433
|
+
set(next, expressionPath, result.data.value);
|
|
3434
|
+
untracked(() => {
|
|
3435
|
+
this.context.set(next);
|
|
3436
|
+
this.onChanged.emit({ values: this.context(), mode: 'update' });
|
|
3840
3437
|
});
|
|
3841
|
-
this.spreadsheetChange.emit([...this.currentRows()]);
|
|
3842
3438
|
}
|
|
3843
3439
|
}
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3440
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPPropertyViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3441
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPPropertyViewerComponent, isStandalone: true, selector: "axp-property-viewer", inputs: { tabsInput: { classPropertyName: "tabsInput", publicName: "tabsInput", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onChanged: "onChanged" }, ngImport: i0, template: "<axp-widgets-container [context]=\"context()\" (onContextChanged)=\"handleContextChange($event)\">\n <!-- #region Shared property row template (used in both advanced and simple modes) -->\n <ng-template #propertyRow let-prop=\"prop\" let-translateTitle=\"translateTitle\">\n <div class=\"ax-flex ax-flex-col ax-gap-2 ax-py-2\">\n <!-- Property header: title + value/expression toggle (when binding.enabled) -->\n <div class=\"ax-flex ax-items-center ax-gap-2 ax-w-full\">\n @if (prop.showLabel !== false) {\n @if (translateTitle) {\n <span class=\"ax-font-semibold ax-flex-1 ax-min-w-0\">{{ prop.title | translate | async }}</span>\n } @else {\n <span class=\"ax-font-semibold ax-flex-1 ax-min-w-0\">{{ prop.title }}</span>\n }\n }\n @if (prop.binding?.enabled) {\n <div class=\"ax-flex ax-gap-1 ax-shrink-0 ax-xs\">\n <ax-button [toggleable]=\"true\" [selected]=\"isExpressionMode(prop)\" look=\"twotone\"\n [color]=\"isExpressionMode(prop) ? 'primary' : 'default'\" class=\"ax-shrink-0\"\n [title]=\"(isExpressionMode(prop) ? '@general:terms.common.expression' : '@general:terms.common.value') | translate | async\"\n (selectedChange)=\"setExpressionMode(prop, $event)\">\n @if (isExpressionMode(prop)) {\n <ax-icon icon=\"fa-light fa-code\"></ax-icon>\n } @else {\n <ax-icon icon=\"fa-light fa-keyboard\"></ax-icon>\n }\n </ax-button>\n </div>\n }\n </div>\n <!-- Property content: Open Editor button (expression mode) or widget renderer (value mode) -->\n @if (prop.binding?.enabled && isExpressionMode(prop)) {\n <ax-button look=\"twotone\" color=\"primary\" size=\"sm\" class=\"ax-w-full\"\n [text]=\"'@general:widgets.triggers.open-editor' | translate | async\" (onClick)=\"openBindingEditor(prop)\"\n [title]=\"'@general:widgets.triggers.edit-binding-expression' | translate | async\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-code\"></ax-icon>\n </ax-prefix>\n </ax-button>\n } @else if (prop.schema.interface) {\n <ng-container axp-widget-renderer [node]=\"prop.schema.interface\" [mode]=\"'edit'\">\n </ng-container>\n }\n </div>\n </ng-template>\n <!-- #endregion -->\n\n <!-- #region Advanced mode: tabs + accordion groups -->\n @if (mode() === 'advanced') {\n <div class=\"ax-flex ax-flex-col\">\n @if (tabs().length > 1) {\n <div class=\"ax-pb-2\">\n <ax-tabs look=\"default\" (onActiveTabChanged)=\"handleTabChange($event)\" [look]=\"'with-line'\">\n @for (tab of tabs(); track $index) {\n <ax-tab-item [text]=\"tab.title\" [key]=\"$index.toString()\" [active]=\"currentTabIndex() === $index\">\n </ax-tab-item>\n }\n </ax-tabs>\n </div>\n }\n <div class=\"ax-flex-1 ax-overflow-auto\">\n <ax-accordion-group [accordion]=\"false\" [look]=\"'flat'\">\n @for (group of groups(); track $index) {\n <ax-accordion-item class=\"!ax-mb-0\" [caption]=\"group.title\" [isCollapsed]=\"group.isCollapsed\"\n (isCollapsedChange)=\"handleCollapsedChange(group.name, $event)\">\n <div class=\"ax-flex ax-flex-col\">\n @for (p of group.props; track $index) {\n <ng-container *ngTemplateOutlet=\"propertyRow; context: { prop: p, translateTitle: false }\">\n </ng-container>\n }\n </div>\n </ax-accordion-item>\n }\n </ax-accordion-group>\n </div>\n </div>\n }\n <!-- #endregion -->\n\n <!-- #region Simple mode: flat list of properties with padding -->\n @else {\n <div class=\"ax-flex ax-flex-col ax-p-4 ax-gap-4\">\n @for (group of groups(); track $index) {\n @for (p of group.props; track $index) {\n <ng-container *ngTemplateOutlet=\"propertyRow; context: { prop: p, translateTitle: true }\">\n </ng-container>\n }\n }\n </div>\n }\n <!-- #endregion -->\n</axp-widgets-container>", styles: ["axp-property-viewer ax-accordion-item .ax-accordion-header{font-weight:600!important;border-bottom-width:1px!important;background-color:rgb(var(--ax-sys-color-lighter-surface))!important;color:rgb(var(--ax-sys-color-on-lighter-surface))!important;border-color:rgb(var(--ax-sys-color-border-lighter-surface))!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: AXAccordionModule }, { kind: "component", type: i2$7.AXAccordionItemComponent, selector: "ax-accordion-item", inputs: ["isCollapsed", "icon", "caption", "isLoading", "headerTemplate", "look", "disabled"], outputs: ["isCollapsedChange", "isLoadingChange", "onClick"] }, { kind: "component", type: i2$7.AXAccordionGroupComponent, selector: "ax-accordion-group", inputs: ["accordion", "activeIndex", "look", "collapsedOnItemClick"], outputs: ["activeIndexChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i5$3.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i5$3.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i6$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i6$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
3442
|
+
}
|
|
3443
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPPropertyViewerComponent, decorators: [{
|
|
3444
|
+
type: Component,
|
|
3445
|
+
args: [{ selector: 'axp-property-viewer', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [
|
|
3446
|
+
CommonModule,
|
|
3447
|
+
AXAccordionModule,
|
|
3448
|
+
AXButtonModule,
|
|
3449
|
+
AXButtonGroupModule,
|
|
3450
|
+
AXDecoratorModule,
|
|
3451
|
+
AXTabsModule,
|
|
3452
|
+
AXPWidgetCoreModule,
|
|
3453
|
+
AXTranslationModule,
|
|
3454
|
+
], template: "<axp-widgets-container [context]=\"context()\" (onContextChanged)=\"handleContextChange($event)\">\n <!-- #region Shared property row template (used in both advanced and simple modes) -->\n <ng-template #propertyRow let-prop=\"prop\" let-translateTitle=\"translateTitle\">\n <div class=\"ax-flex ax-flex-col ax-gap-2 ax-py-2\">\n <!-- Property header: title + value/expression toggle (when binding.enabled) -->\n <div class=\"ax-flex ax-items-center ax-gap-2 ax-w-full\">\n @if (prop.showLabel !== false) {\n @if (translateTitle) {\n <span class=\"ax-font-semibold ax-flex-1 ax-min-w-0\">{{ prop.title | translate | async }}</span>\n } @else {\n <span class=\"ax-font-semibold ax-flex-1 ax-min-w-0\">{{ prop.title }}</span>\n }\n }\n @if (prop.binding?.enabled) {\n <div class=\"ax-flex ax-gap-1 ax-shrink-0 ax-xs\">\n <ax-button [toggleable]=\"true\" [selected]=\"isExpressionMode(prop)\" look=\"twotone\"\n [color]=\"isExpressionMode(prop) ? 'primary' : 'default'\" class=\"ax-shrink-0\"\n [title]=\"(isExpressionMode(prop) ? '@general:terms.common.expression' : '@general:terms.common.value') | translate | async\"\n (selectedChange)=\"setExpressionMode(prop, $event)\">\n @if (isExpressionMode(prop)) {\n <ax-icon icon=\"fa-light fa-code\"></ax-icon>\n } @else {\n <ax-icon icon=\"fa-light fa-keyboard\"></ax-icon>\n }\n </ax-button>\n </div>\n }\n </div>\n <!-- Property content: Open Editor button (expression mode) or widget renderer (value mode) -->\n @if (prop.binding?.enabled && isExpressionMode(prop)) {\n <ax-button look=\"twotone\" color=\"primary\" size=\"sm\" class=\"ax-w-full\"\n [text]=\"'@general:widgets.triggers.open-editor' | translate | async\" (onClick)=\"openBindingEditor(prop)\"\n [title]=\"'@general:widgets.triggers.edit-binding-expression' | translate | async\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-code\"></ax-icon>\n </ax-prefix>\n </ax-button>\n } @else if (prop.schema.interface) {\n <ng-container axp-widget-renderer [node]=\"prop.schema.interface\" [mode]=\"'edit'\">\n </ng-container>\n }\n </div>\n </ng-template>\n <!-- #endregion -->\n\n <!-- #region Advanced mode: tabs + accordion groups -->\n @if (mode() === 'advanced') {\n <div class=\"ax-flex ax-flex-col\">\n @if (tabs().length > 1) {\n <div class=\"ax-pb-2\">\n <ax-tabs look=\"default\" (onActiveTabChanged)=\"handleTabChange($event)\" [look]=\"'with-line'\">\n @for (tab of tabs(); track $index) {\n <ax-tab-item [text]=\"tab.title\" [key]=\"$index.toString()\" [active]=\"currentTabIndex() === $index\">\n </ax-tab-item>\n }\n </ax-tabs>\n </div>\n }\n <div class=\"ax-flex-1 ax-overflow-auto\">\n <ax-accordion-group [accordion]=\"false\" [look]=\"'flat'\">\n @for (group of groups(); track $index) {\n <ax-accordion-item class=\"!ax-mb-0\" [caption]=\"group.title\" [isCollapsed]=\"group.isCollapsed\"\n (isCollapsedChange)=\"handleCollapsedChange(group.name, $event)\">\n <div class=\"ax-flex ax-flex-col\">\n @for (p of group.props; track $index) {\n <ng-container *ngTemplateOutlet=\"propertyRow; context: { prop: p, translateTitle: false }\">\n </ng-container>\n }\n </div>\n </ax-accordion-item>\n }\n </ax-accordion-group>\n </div>\n </div>\n }\n <!-- #endregion -->\n\n <!-- #region Simple mode: flat list of properties with padding -->\n @else {\n <div class=\"ax-flex ax-flex-col ax-p-4 ax-gap-4\">\n @for (group of groups(); track $index) {\n @for (p of group.props; track $index) {\n <ng-container *ngTemplateOutlet=\"propertyRow; context: { prop: p, translateTitle: true }\">\n </ng-container>\n }\n }\n </div>\n }\n <!-- #endregion -->\n</axp-widgets-container>", styles: ["axp-property-viewer ax-accordion-item .ax-accordion-header{font-weight:600!important;border-bottom-width:1px!important;background-color:rgb(var(--ax-sys-color-lighter-surface))!important;color:rgb(var(--ax-sys-color-on-lighter-surface))!important;border-color:rgb(var(--ax-sys-color-border-lighter-surface))!important}\n"] }]
|
|
3455
|
+
}], ctorParameters: () => [], propDecorators: { tabsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabsInput", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], onChanged: [{
|
|
3456
|
+
type: Output
|
|
3457
|
+
}] } });
|
|
3458
|
+
|
|
3459
|
+
class AXPPropertyViewerPopupComponent extends AXBasePageComponent {
|
|
3460
|
+
//#endregion
|
|
3461
|
+
constructor() {
|
|
3462
|
+
super();
|
|
3463
|
+
//#region ---- Inputs ----
|
|
3464
|
+
this.tabs = input.required(...(ngDevMode ? [{ debugName: "tabs" }] : []));
|
|
3465
|
+
this.mode = input('simple', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
3466
|
+
this.context = input({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
3467
|
+
//#endregion
|
|
3468
|
+
//#region ---- Properties ----
|
|
3469
|
+
this.propertyViewer = viewChild(AXPPropertyViewerComponent, ...(ngDevMode ? [{ debugName: "propertyViewer" }] : []));
|
|
3470
|
+
this.currentValues = signal({}, ...(ngDevMode ? [{ debugName: "currentValues" }] : []));
|
|
3471
|
+
this.currentMode = 'init';
|
|
3472
|
+
effect(() => {
|
|
3473
|
+
const viewer = this.propertyViewer();
|
|
3474
|
+
if (!viewer) {
|
|
3475
|
+
return;
|
|
3860
3476
|
}
|
|
3861
|
-
|
|
3477
|
+
viewer.initializeContext(this.context() ?? {});
|
|
3478
|
+
});
|
|
3862
3479
|
}
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
if (event.key === 'Escape' && this.editingCell()) {
|
|
3868
|
-
event.preventDefault();
|
|
3869
|
-
event.stopPropagation();
|
|
3870
|
-
this.cancelCellEdit();
|
|
3871
|
-
}
|
|
3480
|
+
//#region ---- Event Handlers ----
|
|
3481
|
+
handlePropertyChanged(event) {
|
|
3482
|
+
this.currentValues.set(event.values ?? {});
|
|
3483
|
+
this.currentMode = event.mode;
|
|
3872
3484
|
}
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
*/
|
|
3876
|
-
commitCellEdit() {
|
|
3877
|
-
const editing = this.editingCell();
|
|
3878
|
-
if (!editing) {
|
|
3879
|
-
return;
|
|
3880
|
-
}
|
|
3881
|
-
// Changes are already saved via handleSpreadsheetContextChange
|
|
3882
|
-
// Close the editor (same as escape, but keeps changes)
|
|
3883
|
-
this.editingCell.set(null);
|
|
3884
|
-
this.originalCellValue.set(null);
|
|
3485
|
+
handleCloseClick() {
|
|
3486
|
+
this.close();
|
|
3885
3487
|
}
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
if (!editing) {
|
|
3892
|
-
return;
|
|
3893
|
-
}
|
|
3894
|
-
const row = this.getRowById(editing.rowId);
|
|
3895
|
-
const column = this.columns().find((col) => col.name === editing.columnName);
|
|
3896
|
-
const originalValue = this.originalCellValue();
|
|
3897
|
-
if (row && column) {
|
|
3898
|
-
// Restore original value in row
|
|
3899
|
-
set(row, column.path, originalValue);
|
|
3900
|
-
// Clear cache for this cell so widget re-renders with original value
|
|
3901
|
-
const rowsWithIds = this.rowsWithIds();
|
|
3902
|
-
const rowIndex = rowsWithIds.findIndex((item) => item.rowId === editing.rowId);
|
|
3903
|
-
if (rowIndex !== -1) {
|
|
3904
|
-
const cacheKey = `${rowIndex}_${editing.columnName}`;
|
|
3905
|
-
this.cellValueCache.set(cacheKey, originalValue);
|
|
3906
|
-
this.widgetNodeCache.delete(cacheKey);
|
|
3907
|
-
}
|
|
3908
|
-
this.updateRows();
|
|
3909
|
-
}
|
|
3910
|
-
// Close the editor (same as escape)
|
|
3911
|
-
this.editingCell.set(null);
|
|
3912
|
-
this.originalCellValue.set(null);
|
|
3488
|
+
handleApplyClick() {
|
|
3489
|
+
this.close({
|
|
3490
|
+
values: this.currentValues(),
|
|
3491
|
+
mode: this.currentMode,
|
|
3492
|
+
});
|
|
3913
3493
|
}
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3494
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPPropertyViewerPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3495
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.16", type: AXPPropertyViewerPopupComponent, isStandalone: true, selector: "axp-property-viewer-popup", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "propertyViewer", first: true, predicate: AXPPropertyViewerComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
3496
|
+
<div class="ax-flex ax-flex-col ax-h-full ax-overflow-hidden">
|
|
3497
|
+
<axp-property-viewer
|
|
3498
|
+
[tabsInput]="tabs()"
|
|
3499
|
+
[mode]="mode()"
|
|
3500
|
+
(onChanged)="handlePropertyChanged($event)"
|
|
3501
|
+
></axp-property-viewer>
|
|
3502
|
+
</div>
|
|
3503
|
+
|
|
3504
|
+
<ax-footer>
|
|
3505
|
+
<ax-suffix>
|
|
3506
|
+
<ax-button
|
|
3507
|
+
look="solid"
|
|
3508
|
+
[text]="'@general:actions.close.title' | translate | async"
|
|
3509
|
+
(onClick)="handleCloseClick()"
|
|
3510
|
+
></ax-button>
|
|
3511
|
+
<ax-button
|
|
3512
|
+
look="solid"
|
|
3513
|
+
color="primary"
|
|
3514
|
+
[text]="'@general:actions.apply.title' | translate | async"
|
|
3515
|
+
(onClick)="handleApplyClick()"
|
|
3516
|
+
></ax-button>
|
|
3517
|
+
</ax-suffix>
|
|
3518
|
+
</ax-footer>
|
|
3519
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPPropertyViewerComponent, selector: "axp-property-viewer", inputs: ["tabsInput", "mode"], outputs: ["onChanged"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3520
|
+
}
|
|
3521
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPPropertyViewerPopupComponent, decorators: [{
|
|
3522
|
+
type: Component,
|
|
3523
|
+
args: [{
|
|
3524
|
+
selector: 'axp-property-viewer-popup',
|
|
3525
|
+
template: `
|
|
3526
|
+
<div class="ax-flex ax-flex-col ax-h-full ax-overflow-hidden">
|
|
3527
|
+
<axp-property-viewer
|
|
3528
|
+
[tabsInput]="tabs()"
|
|
3529
|
+
[mode]="mode()"
|
|
3530
|
+
(onChanged)="handlePropertyChanged($event)"
|
|
3531
|
+
></axp-property-viewer>
|
|
3532
|
+
</div>
|
|
3533
|
+
|
|
3534
|
+
<ax-footer>
|
|
3535
|
+
<ax-suffix>
|
|
3536
|
+
<ax-button
|
|
3537
|
+
look="solid"
|
|
3538
|
+
[text]="'@general:actions.close.title' | translate | async"
|
|
3539
|
+
(onClick)="handleCloseClick()"
|
|
3540
|
+
></ax-button>
|
|
3541
|
+
<ax-button
|
|
3542
|
+
look="solid"
|
|
3543
|
+
color="primary"
|
|
3544
|
+
[text]="'@general:actions.apply.title' | translate | async"
|
|
3545
|
+
(onClick)="handleApplyClick()"
|
|
3546
|
+
></ax-button>
|
|
3547
|
+
</ax-suffix>
|
|
3548
|
+
</ax-footer>
|
|
3549
|
+
`,
|
|
3550
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3551
|
+
imports: [CommonModule, AXButtonModule, AXDecoratorModule, AXTranslationModule, AXPPropertyViewerComponent],
|
|
3552
|
+
}]
|
|
3553
|
+
}], ctorParameters: () => [], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: true }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], propertyViewer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPPropertyViewerComponent), { isSignal: true }] }] } });
|
|
3554
|
+
|
|
3555
|
+
var propertyViewerPopup_component = /*#__PURE__*/Object.freeze({
|
|
3556
|
+
__proto__: null,
|
|
3557
|
+
AXPPropertyViewerPopupComponent: AXPPropertyViewerPopupComponent
|
|
3558
|
+
});
|
|
3559
|
+
|
|
3560
|
+
class AXPPropertyViewerService {
|
|
3561
|
+
constructor() {
|
|
3562
|
+
//#region ---- Services & Dependencies ----
|
|
3563
|
+
this.popupService = inject(AXPopupService);
|
|
3927
3564
|
}
|
|
3565
|
+
//#endregion
|
|
3566
|
+
//#region ---- Public Methods ----
|
|
3928
3567
|
/**
|
|
3929
|
-
*
|
|
3568
|
+
* Open property viewer popup with predefined tabs and context.
|
|
3930
3569
|
*/
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
if (column.widget.defaultValue !== undefined && column.widget.defaultValue !== null) {
|
|
3942
|
-
set(newRow, column.path, column.widget.defaultValue);
|
|
3943
|
-
}
|
|
3944
|
-
});
|
|
3945
|
-
const currentRows = this.rowsModel();
|
|
3946
|
-
const updatedRows = [...currentRows, newRow];
|
|
3947
|
-
this.rowsModel.set(updatedRows);
|
|
3948
|
-
this.rowChange.emit({
|
|
3949
|
-
type: 'add',
|
|
3950
|
-
rowId: newRow['_id'],
|
|
3951
|
-
row: { ...newRow },
|
|
3952
|
-
rows: updatedRows,
|
|
3570
|
+
async open(config) {
|
|
3571
|
+
const { AXPPropertyViewerPopupComponent } = await Promise.resolve().then(function () { return propertyViewerPopup_component; });
|
|
3572
|
+
const result = await this.popupService.open(AXPPropertyViewerPopupComponent, {
|
|
3573
|
+
title: config.title,
|
|
3574
|
+
size: config.size || 'md',
|
|
3575
|
+
data: {
|
|
3576
|
+
tabs: signal(config.tabs),
|
|
3577
|
+
mode: signal(config.mode || 'simple'),
|
|
3578
|
+
context: signal(config.context ?? {}),
|
|
3579
|
+
},
|
|
3953
3580
|
});
|
|
3954
|
-
|
|
3581
|
+
return result.data || null;
|
|
3955
3582
|
}
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
}
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
this.rowChange.emit({
|
|
3983
|
-
type: 'remove',
|
|
3984
|
-
rowId,
|
|
3985
|
-
row: { ...removedRow },
|
|
3986
|
-
rows: updatedRows,
|
|
3987
|
-
});
|
|
3988
|
-
this.spreadsheetChange.emit(updatedRows);
|
|
3989
|
-
}
|
|
3990
|
-
else {
|
|
3991
|
-
// Fixed mode: update internalRows and emit events
|
|
3992
|
-
const updatedRows = currentRows.filter((_, index) => index !== rowIndex);
|
|
3993
|
-
this.internalRows.set(updatedRows);
|
|
3994
|
-
this.rowChange.emit({
|
|
3995
|
-
type: 'remove',
|
|
3996
|
-
rowId,
|
|
3997
|
-
row: { ...removedRow },
|
|
3998
|
-
rows: updatedRows,
|
|
3583
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPPropertyViewerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3584
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPPropertyViewerService, providedIn: 'root' }); }
|
|
3585
|
+
}
|
|
3586
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPPropertyViewerService, decorators: [{
|
|
3587
|
+
type: Injectable,
|
|
3588
|
+
args: [{
|
|
3589
|
+
providedIn: 'root',
|
|
3590
|
+
}]
|
|
3591
|
+
}] });
|
|
3592
|
+
|
|
3593
|
+
class AXPQuerySortsComponent {
|
|
3594
|
+
constructor() {
|
|
3595
|
+
this.sortDefinitions = model([], ...(ngDevMode ? [{ debugName: "sortDefinitions" }] : []));
|
|
3596
|
+
this.sortQueries = signal([], ...(ngDevMode ? [{ debugName: "sortQueries", equal: isEqual }] : [{
|
|
3597
|
+
equal: isEqual,
|
|
3598
|
+
}]));
|
|
3599
|
+
this.initialSortQueries = input([], ...(ngDevMode ? [{ debugName: "initialSortQueries" }] : []));
|
|
3600
|
+
this.sortQueriesChange = output();
|
|
3601
|
+
// Recompute merged sort queries whenever inputs change
|
|
3602
|
+
effect(() => {
|
|
3603
|
+
const initialQueries = this.initialSortQueries();
|
|
3604
|
+
const definitions = this.sortDefinitions();
|
|
3605
|
+
const existingQueriesMap = new Map(initialQueries.map((q) => [q.name, q]));
|
|
3606
|
+
const mergedQueries = definitions.map((def) => {
|
|
3607
|
+
const existingQuery = existingQueriesMap.get(def.name);
|
|
3608
|
+
return existingQuery ? { ...def, dir: existingQuery.dir } : { ...def };
|
|
3999
3609
|
});
|
|
4000
|
-
this.
|
|
4001
|
-
}
|
|
3610
|
+
this.sortQueries.set(mergedQueries);
|
|
3611
|
+
});
|
|
3612
|
+
effect(() => {
|
|
3613
|
+
this.sortQueriesChange.emit(this.sortQueries().filter((q) => q.dir !== undefined));
|
|
3614
|
+
});
|
|
4002
3615
|
}
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
3616
|
+
drop(event) {
|
|
3617
|
+
const sd = this.sortDefinitions();
|
|
3618
|
+
moveItemInArray(sd, event.previousIndex, event.currentIndex);
|
|
3619
|
+
this.sortDefinitions.set([...sd]);
|
|
3620
|
+
// Reorder sortQueries based on new sortDefinitions order
|
|
3621
|
+
const sq = this.sortQueries();
|
|
3622
|
+
moveItemInArray(sq, event.previousIndex, event.currentIndex);
|
|
3623
|
+
this.sortQueries.set([...sq]);
|
|
4010
3624
|
}
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
*/
|
|
4014
|
-
updateRows() {
|
|
4015
|
-
if (this.rowMode() === 'dynamic') {
|
|
4016
|
-
// For dynamic mode, rowsModel is already updated (two-way binding)
|
|
4017
|
-
// Just trigger change detection
|
|
4018
|
-
this.rowsModel.set([...this.rowsModel()]);
|
|
4019
|
-
}
|
|
4020
|
-
else {
|
|
4021
|
-
// For fixed mode, update internal state
|
|
4022
|
-
this.internalRows.set([...this.internalRows()]);
|
|
4023
|
-
}
|
|
3625
|
+
getSortDirection(item) {
|
|
3626
|
+
return this.sortQueries().find((i) => i.name === item.name)?.dir;
|
|
4024
3627
|
}
|
|
4025
|
-
|
|
4026
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPSpreadsheetComponent, isStandalone: true, selector: "axp-spreadsheet", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rowMode: { classPropertyName: "rowMode", publicName: "rowMode", isSignal: true, isRequired: false, transformFunction: null }, rowsInput: { classPropertyName: "rowsInput", publicName: "rowsInput", isSignal: true, isRequired: false, transformFunction: null }, rowsModel: { classPropertyName: "rowsModel", publicName: "rowsModel", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, emptyCellPlaceholder: { classPropertyName: "emptyCellPlaceholder", publicName: "emptyCellPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, rowTitlePath: { classPropertyName: "rowTitlePath", publicName: "rowTitlePath", isSignal: true, isRequired: false, transformFunction: null }, rowDescriptionPath: { classPropertyName: "rowDescriptionPath", publicName: "rowDescriptionPath", isSignal: true, isRequired: false, transformFunction: null }, allowAddRows: { classPropertyName: "allowAddRows", publicName: "allowAddRows", isSignal: true, isRequired: false, transformFunction: null }, allowRemoveRows: { classPropertyName: "allowRemoveRows", publicName: "allowRemoveRows", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowsModel: "rowsModelChange", cellChange: "cellChange", rowChange: "rowChange", spreadsheetChange: "spreadsheetChange" }, host: { listeners: { "document:keydown": "handleKeyDown($event)" }, classAttribute: "axp-spreadsheet" }, ngImport: i0, template: "<!--\n #region ---- Spreadsheet Component Template ----\n-->\n<div class=\"__spreadsheet-container\" (click)=\"handleClickOutside($event)\">\n @if (isColumnsEmpty()) {\n <!-- Empty State: Columns are empty (regardless of rows) -->\n <div class=\"__empty-state\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-table-columns\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty-columns.title' | translate | async }}</div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty-columns.description' | translate | async }}\n </div>\n </div>\n } @else if (isEmpty()) {\n <!-- Empty State: Both columns and rows are empty -->\n <div class=\"__empty-state\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-table\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty.title' | translate | async }}</div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty.description' | translate | async }}</div>\n </div>\n } @else if (isRowsEmpty()) {\n <!-- Empty State: Only rows are empty - Show columns -->\n <div class=\"__table-wrapper\">\n <table class=\"__table\">\n <!-- Header Row -->\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <!-- Corner cell (title) -->\n <th class=\"__corner-cell\">\n @if (title()) {\n <div class=\"__corner-title\">{{ title() | translate | async }}</div>\n }\n @if (rowMode() === 'dynamic' && allowAddRows() && !readonly()) {\n <div class=\"__corner-actions\">\n <ax-button look=\"blank\" color=\"primary\" (onClick)=\"handleAddRow()\"\n [attr.aria-label]=\"'Add Row'\">\n <ax-icon icon=\"far fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </th>\n\n <!-- Column headers -->\n @for (column of columns(); track column.name) {\n <th class=\"__column-header\" [style.width]=\"column.width\">\n <div class=\"__header-content\">\n <div class=\"__header-title\">{{ column.title | translate | async }}</div>\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <!-- Empty State Row -->\n <tbody class=\"__tbody\">\n <tr class=\"__row __row--empty\">\n <td class=\"__row-header\" [attr.colspan]=\"columns().length + 1\">\n <div class=\"__empty-state-inline\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-list\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty-rows.title' | translate | async\n }}\n </div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty-rows.description' |\n translate |\n async }}</div>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n } @else {\n <!-- Full Spreadsheet: Both columns and rows are available -->\n <div class=\"__table-wrapper\">\n <table class=\"__table\">\n <!-- Header Row -->\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <!-- Corner cell (title) -->\n <th class=\"__corner-cell\">\n @if (title()) {\n <div class=\"__corner-title\">{{ title() | translate | async }}</div>\n }\n @if (rowMode() === 'dynamic' && allowAddRows() && !readonly()) {\n <div class=\"__corner-actions\">\n <ax-button look=\"blank\" color=\"primary\" (onClick)=\"handleAddRow()\"\n [attr.aria-label]=\"'Add Row'\">\n <ax-icon icon=\"far fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </th>\n\n <!-- Column headers -->\n @for (column of columns(); track column.name) {\n <th class=\"__column-header\" [style.width]=\"column.width\">\n <div class=\"__header-content\">\n <div class=\"__header-title\">{{ column.title | translate | async }}</div>\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <!-- Body Rows -->\n <tbody class=\"__tbody\">\n <axp-widgets-container [context]=\"spreadsheetContext()\"\n (onContextChanged)=\"handleSpreadsheetContextChange($event)\">\n @for (rowItem of rowsWithIds(); track rowItem.rowId; let rowIndex = $index) {\n <tr class=\"__row\" [class.__row--odd]=\"rowIndex % 2 === 1\">\n <!-- Row header -->\n <td class=\"__row-header\">\n <div class=\"__header-content\">\n @if (rowTitlePath()) {\n <div class=\"__header-title\">{{ getRowTitle(rowItem.row, rowTitlePath()!) }}</div>\n }\n @if (rowDescriptionPath()) {\n <div class=\"__header-description\">{{ getRowDescription(rowItem.row,\n rowDescriptionPath()!) }}</div>\n }\n </div>\n @if (allowRemoveRows() && !readonly()) {\n <div class=\"__header-actions ax-xs ax-opacity-30 hover:ax-opacity-100\">\n <ax-button look=\"blank\" color=\"danger\"\n (onClick)=\"handleRemoveRow(rowItem.rowId, $event)\" [attr.aria-label]=\"'Remove Row'\">\n <ax-icon icon=\"far fa-times\"></ax-icon>\n </ax-button>\n </div>\n }\n </td>\n\n <!-- Spreadsheet cells -->\n @for (column of columns(); track column.name) {\n <td class=\"__cell\" [class.__cell--editing]=\"isCellEditing(rowItem.rowId, column.name)\"\n [class.__cell--readonly]=\"isColumnReadonly(column)\"\n (click)=\"$event.stopPropagation(); handleCellClick(rowItem.rowId, column.name, $event)\">\n @if (isCellEditing(rowItem.rowId, column.name) && !isColumnReadonly(column)) {\n <!-- Edit mode: Show widget in edit mode -->\n <div class=\"__cell-editor\" (blur)=\"handleCellBlur(rowItem.rowId, column.name)\"\n tabindex=\"-1\">\n <ng-container axp-widget-renderer [node]=\"getCellWidgetNode(column, rowIndex)\"\n [mode]=\"'edit'\"></ng-container>\n </div>\n <!-- Floating toolbar for commit/cancel -->\n <div class=\"__cell-toolbar ax-xs\" (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\" (focusin)=\"$event.stopPropagation()\">\n <ax-button look=\"blank\" color=\"success\" (onClick)=\"commitCellEdit()\"\n [attr.aria-label]=\"'Commit'\">\n <ax-icon icon=\"far fa-check\"></ax-icon>\n </ax-button>\n <ax-button look=\"blank\" color=\"danger\" (onClick)=\"cancelCellEdit()\"\n [attr.aria-label]=\"'Cancel'\">\n <ax-icon icon=\"far fa-times\"></ax-icon>\n </ax-button>\n </div>\n } @else {\n <!-- View mode: Show widget in view mode or placeholder -->\n <div class=\"__cell-value\">\n @if (getCellValue(rowIndex, column.name) !== null &&\n getCellValue(rowIndex, column.name) !== undefined) {\n <ng-container axp-widget-renderer [node]=\"getCellWidgetNode(column, rowIndex)\"\n [mode]=\"'view'\"></ng-container>\n } @else {\n <span class=\"__cell-placeholder\">{{ emptyCellPlaceholder() }}</span>\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </axp-widgets-container>\n </tbody>\n </table>\n </div>\n }\n</div>\n<!--\n #endregion\n-->", styles: [".axp-spreadsheet{display:flex;height:100%;width:100%;flex-direction:column}.axp-spreadsheet .__spreadsheet-container{position:relative;flex:1 1 0%;overflow:hidden;border-radius:.375rem;border-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-spreadsheet .__empty-state{display:flex;min-height:200px;flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center}.axp-spreadsheet .__empty-state .__empty-icon{margin-bottom:1rem}.axp-spreadsheet .__empty-state .__empty-icon i{font-size:2.25rem;line-height:2.5rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state .__empty-title{margin-bottom:.5rem;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(38 38 38 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state .__empty-description{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1.5rem;text-align:center}.axp-spreadsheet .__empty-state-inline .__empty-icon{margin-bottom:.75rem}.axp-spreadsheet .__empty-state-inline .__empty-icon i{font-size:1.5rem;line-height:2rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline .__empty-title{margin-bottom:.25rem;font-size:1rem;line-height:1.5rem;font-weight:600;--tw-text-opacity: 1;color:rgb(38 38 38 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline .__empty-description{font-size:.75rem;line-height:1rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__table-wrapper{height:100%;width:100%;overflow-x:auto;overflow-y:auto;-webkit-overflow-scrolling:touch}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar{height:8px;width:8px}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-track{--tw-bg-opacity: 1;background-color:rgb(245 245 245 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-thumb{border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgb(163 163 163 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(115 115 115 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table{min-width:100%;border-collapse:separate;--tw-border-spacing-x: 0px;--tw-border-spacing-y: 0px;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.axp-spreadsheet .__table .__thead{position:sticky;top:0;z-index:2}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell{position:relative;position:sticky;inset-inline-start:0px;width:200px;min-width:200px;border-width:1px;border-bottom-width:1px;padding:.5rem .75rem;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:3}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell .__corner-title{text-align:center;font-size:.875rem;line-height:1.25rem;font-weight:600}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell .__corner-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}@media (max-width: 768px){.axp-spreadsheet .__table .__thead .__header-row .__corner-cell{width:200px;min-width:200px;padding:.375rem .5rem}}.axp-spreadsheet .__table .__thead .__header-row .__column-header{position:sticky;top:0;width:200px;min-width:200px;white-space:nowrap;border-bottom-width:1px;padding:.5rem .75rem;text-align:center;font-weight:600;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:2}.axp-spreadsheet .__table .__thead .__header-row .__column-header.__column-header--empty{width:300px;min-width:300px;white-space:normal}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content{display:flex;flex-direction:column;gap:.25rem}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-title{font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-description{white-space:normal;overflow-wrap:break-word;font-size:.75rem;line-height:1rem;font-weight:400;opacity:.75}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}@media (max-width: 768px){.axp-spreadsheet .__table .__thead .__header-row .__column-header{width:120px;min-width:120px;padding:.375rem .5rem}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-title,.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-description{font-size:.75rem;line-height:1rem}}.axp-spreadsheet .__table .__tbody .__row.__row--empty .__row-header{text-align:center}.axp-spreadsheet .__table .__tbody .__row .__row-header{position:relative;position:sticky;inset-inline-start:0px;width:200px;min-width:200px;border-width:1px;border-bottom-width:1px;padding:.5rem .75rem;vertical-align:top;font-weight:600;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:2}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content{display:flex;flex-direction:column;gap:.25rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-title{font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-description{font-size:.75rem;line-height:1rem;font-weight:400;opacity:.75}@media (max-width: 768px){.axp-spreadsheet .__table .__tbody .__row .__row-header{width:200px;min-width:200px;padding:.375rem .5rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-title,.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-description{font-size:.75rem;line-height:1rem}}.axp-spreadsheet .__table .__tbody .__row .__cell{position:relative;min-height:40px;width:200px;min-width:200px;cursor:pointer;border-bottom-width:1px;padding:.5rem .75rem;text-align:center;vertical-align:middle}.axp-spreadsheet .__table .__tbody .__row .__cell:before{content:\"\";pointer-events:none;position:absolute;inset:0;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1));--tw-bg-opacity: .05;opacity:0;transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);animation-duration:.15s;animation-timing-function:cubic-bezier(.4,0,.2,1)}.axp-spreadsheet .__table .__tbody .__row .__cell:hover:not(.__cell--readonly):not(.__cell--editing):before{opacity:1}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--readonly{cursor:default}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--readonly:hover:before{opacity:0}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--empty{cursor:default}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--empty:hover:before{opacity:0}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing{position:relative;border-width:2px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1));background-color:rgba(var(--ax-sys-color-primary-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .1;padding:1px}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing .__cell-editor{width:100%;padding:.5rem .75rem}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing .__cell-toolbar{position:absolute;bottom:-35px;inset-inline-end:0px;display:flex;gap:.125rem;white-space:nowrap;border-radius:.375rem;border-width:1px;padding:.25rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:100}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-value{display:flex;min-height:1.25rem;align-items:center;justify-content:center;overflow-wrap:break-word;padding:.125rem;font-size:.875rem;line-height:1.25rem}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-placeholder{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-editor{display:flex;width:100%;align-items:center;justify-content:center}@media (max-width: 768px){.axp-spreadsheet .__table .__tbody .__row .__cell{width:120px;min-width:120px;padding:.375rem .5rem}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-value{font-size:.75rem;line-height:1rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i6$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i6$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
3628
|
+
changeItemSort(item) {
|
|
3629
|
+
const itemDirection = this.getSortDirection(item);
|
|
3630
|
+
const newDirection = itemDirection === 'asc' ? 'desc' : itemDirection === 'desc' ? undefined : 'asc';
|
|
3631
|
+
this.sortQueries.update((prev) => {
|
|
3632
|
+
return prev.map((field) => {
|
|
3633
|
+
if (field.name === item.name) {
|
|
3634
|
+
return { ...field, dir: newDirection };
|
|
3635
|
+
}
|
|
3636
|
+
return field;
|
|
3637
|
+
});
|
|
3638
|
+
});
|
|
3639
|
+
}
|
|
3640
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPQuerySortsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3641
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPQuerySortsComponent, isStandalone: true, selector: "axp-query-sorts", inputs: { sortDefinitions: { classPropertyName: "sortDefinitions", publicName: "sortDefinitions", isSignal: true, isRequired: false, transformFunction: null }, initialSortQueries: { classPropertyName: "initialSortQueries", publicName: "initialSortQueries", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortDefinitions: "sortDefinitionsChange", sortQueriesChange: "sortQueriesChange" }, ngImport: i0, template: "<div class=\"ax-flex ax-flex-col ax-justify-center ax-gap-4 ax-select-none\">\n <div class=\"ax-flex ax-flex-col ax-gap-4 ax-select-none\" cdkDropList (cdkDropListDropped)=\"drop($event)\">\n <div class=\"ax-flex ax-flex-col ax-gap-3 ax-w-full ax-sorted-list ax-max-h-[calc(100vh-280px)] ax-overflow-auto\">\n @for (item of sortDefinitions(); track item.name) {\n <div class=\"ax-flex ax-py-1 ax-items-center ax-justify-between\" cdkDrag cdkDragBoundary=\".ax-sorted-list\">\n <div class=\"ax-flex ax-items-center ax-gap-3\" cdkDragHandle>\n <ax-icon class=\"fa-solid fa-grip-dots-vertical ax-cursor-move\"></ax-icon>\n <p class=\"ax-font-medium ax-text-sm\">{{ item.title | translate | async }}</p>\n </div>\n <ax-button [color]=\"'blank'\" class=\"ax-sm\" (click)=\"changeItemSort(item)\">\n <ax-icon\n [class.ax-text-primary]=\"getSortDirection(item) === 'asc'\"\n class=\"fa-solid fa-arrow-up-long ax-text-neutral-400\"\n ></ax-icon>\n <ax-icon\n [class.ax-text-primary]=\"getSortDirection(item) === 'desc'\"\n class=\"fa-solid fa-arrow-down-long ax-text-neutral-400\"\n ></ax-icon>\n </ax-button>\n </div>\n }\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
4027
3642
|
}
|
|
4028
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type:
|
|
3643
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPQuerySortsComponent, decorators: [{
|
|
4029
3644
|
type: Component,
|
|
4030
|
-
args: [{ selector: 'axp-
|
|
4031
|
-
|
|
4032
|
-
|
|
3645
|
+
args: [{ selector: 'axp-query-sorts', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [
|
|
3646
|
+
CdkDropList,
|
|
3647
|
+
CdkDrag,
|
|
3648
|
+
CdkDragHandle,
|
|
3649
|
+
AXTabsModule,
|
|
4033
3650
|
AXTranslationModule,
|
|
4034
|
-
|
|
3651
|
+
CommonModule,
|
|
4035
3652
|
AXDecoratorModule,
|
|
4036
|
-
|
|
4037
|
-
],
|
|
4038
|
-
|
|
4039
|
-
}, template: "<!--\n #region ---- Spreadsheet Component Template ----\n-->\n<div class=\"__spreadsheet-container\" (click)=\"handleClickOutside($event)\">\n @if (isColumnsEmpty()) {\n <!-- Empty State: Columns are empty (regardless of rows) -->\n <div class=\"__empty-state\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-table-columns\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty-columns.title' | translate | async }}</div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty-columns.description' | translate | async }}\n </div>\n </div>\n } @else if (isEmpty()) {\n <!-- Empty State: Both columns and rows are empty -->\n <div class=\"__empty-state\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-table\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty.title' | translate | async }}</div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty.description' | translate | async }}</div>\n </div>\n } @else if (isRowsEmpty()) {\n <!-- Empty State: Only rows are empty - Show columns -->\n <div class=\"__table-wrapper\">\n <table class=\"__table\">\n <!-- Header Row -->\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <!-- Corner cell (title) -->\n <th class=\"__corner-cell\">\n @if (title()) {\n <div class=\"__corner-title\">{{ title() | translate | async }}</div>\n }\n @if (rowMode() === 'dynamic' && allowAddRows() && !readonly()) {\n <div class=\"__corner-actions\">\n <ax-button look=\"blank\" color=\"primary\" (onClick)=\"handleAddRow()\"\n [attr.aria-label]=\"'Add Row'\">\n <ax-icon icon=\"far fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </th>\n\n <!-- Column headers -->\n @for (column of columns(); track column.name) {\n <th class=\"__column-header\" [style.width]=\"column.width\">\n <div class=\"__header-content\">\n <div class=\"__header-title\">{{ column.title | translate | async }}</div>\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <!-- Empty State Row -->\n <tbody class=\"__tbody\">\n <tr class=\"__row __row--empty\">\n <td class=\"__row-header\" [attr.colspan]=\"columns().length + 1\">\n <div class=\"__empty-state-inline\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-list\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty-rows.title' | translate | async\n }}\n </div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty-rows.description' |\n translate |\n async }}</div>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n } @else {\n <!-- Full Spreadsheet: Both columns and rows are available -->\n <div class=\"__table-wrapper\">\n <table class=\"__table\">\n <!-- Header Row -->\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <!-- Corner cell (title) -->\n <th class=\"__corner-cell\">\n @if (title()) {\n <div class=\"__corner-title\">{{ title() | translate | async }}</div>\n }\n @if (rowMode() === 'dynamic' && allowAddRows() && !readonly()) {\n <div class=\"__corner-actions\">\n <ax-button look=\"blank\" color=\"primary\" (onClick)=\"handleAddRow()\"\n [attr.aria-label]=\"'Add Row'\">\n <ax-icon icon=\"far fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </th>\n\n <!-- Column headers -->\n @for (column of columns(); track column.name) {\n <th class=\"__column-header\" [style.width]=\"column.width\">\n <div class=\"__header-content\">\n <div class=\"__header-title\">{{ column.title | translate | async }}</div>\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <!-- Body Rows -->\n <tbody class=\"__tbody\">\n <axp-widgets-container [context]=\"spreadsheetContext()\"\n (onContextChanged)=\"handleSpreadsheetContextChange($event)\">\n @for (rowItem of rowsWithIds(); track rowItem.rowId; let rowIndex = $index) {\n <tr class=\"__row\" [class.__row--odd]=\"rowIndex % 2 === 1\">\n <!-- Row header -->\n <td class=\"__row-header\">\n <div class=\"__header-content\">\n @if (rowTitlePath()) {\n <div class=\"__header-title\">{{ getRowTitle(rowItem.row, rowTitlePath()!) }}</div>\n }\n @if (rowDescriptionPath()) {\n <div class=\"__header-description\">{{ getRowDescription(rowItem.row,\n rowDescriptionPath()!) }}</div>\n }\n </div>\n @if (allowRemoveRows() && !readonly()) {\n <div class=\"__header-actions ax-xs ax-opacity-30 hover:ax-opacity-100\">\n <ax-button look=\"blank\" color=\"danger\"\n (onClick)=\"handleRemoveRow(rowItem.rowId, $event)\" [attr.aria-label]=\"'Remove Row'\">\n <ax-icon icon=\"far fa-times\"></ax-icon>\n </ax-button>\n </div>\n }\n </td>\n\n <!-- Spreadsheet cells -->\n @for (column of columns(); track column.name) {\n <td class=\"__cell\" [class.__cell--editing]=\"isCellEditing(rowItem.rowId, column.name)\"\n [class.__cell--readonly]=\"isColumnReadonly(column)\"\n (click)=\"$event.stopPropagation(); handleCellClick(rowItem.rowId, column.name, $event)\">\n @if (isCellEditing(rowItem.rowId, column.name) && !isColumnReadonly(column)) {\n <!-- Edit mode: Show widget in edit mode -->\n <div class=\"__cell-editor\" (blur)=\"handleCellBlur(rowItem.rowId, column.name)\"\n tabindex=\"-1\">\n <ng-container axp-widget-renderer [node]=\"getCellWidgetNode(column, rowIndex)\"\n [mode]=\"'edit'\"></ng-container>\n </div>\n <!-- Floating toolbar for commit/cancel -->\n <div class=\"__cell-toolbar ax-xs\" (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\" (focusin)=\"$event.stopPropagation()\">\n <ax-button look=\"blank\" color=\"success\" (onClick)=\"commitCellEdit()\"\n [attr.aria-label]=\"'Commit'\">\n <ax-icon icon=\"far fa-check\"></ax-icon>\n </ax-button>\n <ax-button look=\"blank\" color=\"danger\" (onClick)=\"cancelCellEdit()\"\n [attr.aria-label]=\"'Cancel'\">\n <ax-icon icon=\"far fa-times\"></ax-icon>\n </ax-button>\n </div>\n } @else {\n <!-- View mode: Show widget in view mode or placeholder -->\n <div class=\"__cell-value\">\n @if (getCellValue(rowIndex, column.name) !== null &&\n getCellValue(rowIndex, column.name) !== undefined) {\n <ng-container axp-widget-renderer [node]=\"getCellWidgetNode(column, rowIndex)\"\n [mode]=\"'view'\"></ng-container>\n } @else {\n <span class=\"__cell-placeholder\">{{ emptyCellPlaceholder() }}</span>\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </axp-widgets-container>\n </tbody>\n </table>\n </div>\n }\n</div>\n<!--\n #endregion\n-->", styles: [".axp-spreadsheet{display:flex;height:100%;width:100%;flex-direction:column}.axp-spreadsheet .__spreadsheet-container{position:relative;flex:1 1 0%;overflow:hidden;border-radius:.375rem;border-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-spreadsheet .__empty-state{display:flex;min-height:200px;flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center}.axp-spreadsheet .__empty-state .__empty-icon{margin-bottom:1rem}.axp-spreadsheet .__empty-state .__empty-icon i{font-size:2.25rem;line-height:2.5rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state .__empty-title{margin-bottom:.5rem;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(38 38 38 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state .__empty-description{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1.5rem;text-align:center}.axp-spreadsheet .__empty-state-inline .__empty-icon{margin-bottom:.75rem}.axp-spreadsheet .__empty-state-inline .__empty-icon i{font-size:1.5rem;line-height:2rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline .__empty-title{margin-bottom:.25rem;font-size:1rem;line-height:1.5rem;font-weight:600;--tw-text-opacity: 1;color:rgb(38 38 38 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline .__empty-description{font-size:.75rem;line-height:1rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__table-wrapper{height:100%;width:100%;overflow-x:auto;overflow-y:auto;-webkit-overflow-scrolling:touch}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar{height:8px;width:8px}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-track{--tw-bg-opacity: 1;background-color:rgb(245 245 245 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-thumb{border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgb(163 163 163 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(115 115 115 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table{min-width:100%;border-collapse:separate;--tw-border-spacing-x: 0px;--tw-border-spacing-y: 0px;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.axp-spreadsheet .__table .__thead{position:sticky;top:0;z-index:2}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell{position:relative;position:sticky;inset-inline-start:0px;width:200px;min-width:200px;border-width:1px;border-bottom-width:1px;padding:.5rem .75rem;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:3}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell .__corner-title{text-align:center;font-size:.875rem;line-height:1.25rem;font-weight:600}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell .__corner-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}@media (max-width: 768px){.axp-spreadsheet .__table .__thead .__header-row .__corner-cell{width:200px;min-width:200px;padding:.375rem .5rem}}.axp-spreadsheet .__table .__thead .__header-row .__column-header{position:sticky;top:0;width:200px;min-width:200px;white-space:nowrap;border-bottom-width:1px;padding:.5rem .75rem;text-align:center;font-weight:600;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:2}.axp-spreadsheet .__table .__thead .__header-row .__column-header.__column-header--empty{width:300px;min-width:300px;white-space:normal}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content{display:flex;flex-direction:column;gap:.25rem}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-title{font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-description{white-space:normal;overflow-wrap:break-word;font-size:.75rem;line-height:1rem;font-weight:400;opacity:.75}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}@media (max-width: 768px){.axp-spreadsheet .__table .__thead .__header-row .__column-header{width:120px;min-width:120px;padding:.375rem .5rem}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-title,.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-description{font-size:.75rem;line-height:1rem}}.axp-spreadsheet .__table .__tbody .__row.__row--empty .__row-header{text-align:center}.axp-spreadsheet .__table .__tbody .__row .__row-header{position:relative;position:sticky;inset-inline-start:0px;width:200px;min-width:200px;border-width:1px;border-bottom-width:1px;padding:.5rem .75rem;vertical-align:top;font-weight:600;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:2}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content{display:flex;flex-direction:column;gap:.25rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-title{font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-description{font-size:.75rem;line-height:1rem;font-weight:400;opacity:.75}@media (max-width: 768px){.axp-spreadsheet .__table .__tbody .__row .__row-header{width:200px;min-width:200px;padding:.375rem .5rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-title,.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-description{font-size:.75rem;line-height:1rem}}.axp-spreadsheet .__table .__tbody .__row .__cell{position:relative;min-height:40px;width:200px;min-width:200px;cursor:pointer;border-bottom-width:1px;padding:.5rem .75rem;text-align:center;vertical-align:middle}.axp-spreadsheet .__table .__tbody .__row .__cell:before{content:\"\";pointer-events:none;position:absolute;inset:0;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1));--tw-bg-opacity: .05;opacity:0;transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);animation-duration:.15s;animation-timing-function:cubic-bezier(.4,0,.2,1)}.axp-spreadsheet .__table .__tbody .__row .__cell:hover:not(.__cell--readonly):not(.__cell--editing):before{opacity:1}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--readonly{cursor:default}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--readonly:hover:before{opacity:0}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--empty{cursor:default}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--empty:hover:before{opacity:0}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing{position:relative;border-width:2px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1));background-color:rgba(var(--ax-sys-color-primary-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .1;padding:1px}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing .__cell-editor{width:100%;padding:.5rem .75rem}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing .__cell-toolbar{position:absolute;bottom:-35px;inset-inline-end:0px;display:flex;gap:.125rem;white-space:nowrap;border-radius:.375rem;border-width:1px;padding:.25rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:100}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-value{display:flex;min-height:1.25rem;align-items:center;justify-content:center;overflow-wrap:break-word;padding:.125rem;font-size:.875rem;line-height:1.25rem}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-placeholder{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-editor{display:flex;width:100%;align-items:center;justify-content:center}@media (max-width: 768px){.axp-spreadsheet .__table .__tbody .__row .__cell{width:120px;min-width:120px;padding:.375rem .5rem}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-value{font-size:.75rem;line-height:1rem}}\n"] }]
|
|
4040
|
-
}], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rowMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowMode", required: false }] }], rowsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsInput", required: false }] }], rowsModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsModel", required: false }] }, { type: i0.Output, args: ["rowsModelChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], emptyCellPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyCellPlaceholder", required: false }] }], rowTitlePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowTitlePath", required: false }] }], rowDescriptionPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowDescriptionPath", required: false }] }], allowAddRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowAddRows", required: false }] }], allowRemoveRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowRemoveRows", required: false }] }], cellChange: [{ type: i0.Output, args: ["cellChange"] }], rowChange: [{ type: i0.Output, args: ["rowChange"] }], spreadsheetChange: [{ type: i0.Output, args: ["spreadsheetChange"] }], handleKeyDown: [{
|
|
4041
|
-
type: HostListener,
|
|
4042
|
-
args: ['document:keydown', ['$event']]
|
|
4043
|
-
}] } });
|
|
4044
|
-
|
|
4045
|
-
//#endregion
|
|
3653
|
+
AXButtonModule,
|
|
3654
|
+
], template: "<div class=\"ax-flex ax-flex-col ax-justify-center ax-gap-4 ax-select-none\">\n <div class=\"ax-flex ax-flex-col ax-gap-4 ax-select-none\" cdkDropList (cdkDropListDropped)=\"drop($event)\">\n <div class=\"ax-flex ax-flex-col ax-gap-3 ax-w-full ax-sorted-list ax-max-h-[calc(100vh-280px)] ax-overflow-auto\">\n @for (item of sortDefinitions(); track item.name) {\n <div class=\"ax-flex ax-py-1 ax-items-center ax-justify-between\" cdkDrag cdkDragBoundary=\".ax-sorted-list\">\n <div class=\"ax-flex ax-items-center ax-gap-3\" cdkDragHandle>\n <ax-icon class=\"fa-solid fa-grip-dots-vertical ax-cursor-move\"></ax-icon>\n <p class=\"ax-font-medium ax-text-sm\">{{ item.title | translate | async }}</p>\n </div>\n <ax-button [color]=\"'blank'\" class=\"ax-sm\" (click)=\"changeItemSort(item)\">\n <ax-icon\n [class.ax-text-primary]=\"getSortDirection(item) === 'asc'\"\n class=\"fa-solid fa-arrow-up-long ax-text-neutral-400\"\n ></ax-icon>\n <ax-icon\n [class.ax-text-primary]=\"getSortDirection(item) === 'desc'\"\n class=\"fa-solid fa-arrow-down-long ax-text-neutral-400\"\n ></ax-icon>\n </ax-button>\n </div>\n }\n </div>\n </div>\n</div>\n" }]
|
|
3655
|
+
}], ctorParameters: () => [], propDecorators: { sortDefinitions: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortDefinitions", required: false }] }, { type: i0.Output, args: ["sortDefinitionsChange"] }], initialSortQueries: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSortQueries", required: false }] }], sortQueriesChange: [{ type: i0.Output, args: ["sortQueriesChange"] }] } });
|
|
4046
3656
|
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
this.platform = inject(AXPlatform);
|
|
4050
|
-
}
|
|
4051
|
-
ngOnInit() {
|
|
4052
|
-
this.setLogoType();
|
|
4053
|
-
this.platform.themeMode$.subscribe(() => {
|
|
4054
|
-
this.setLogoTheme();
|
|
4055
|
-
});
|
|
4056
|
-
}
|
|
4057
|
-
ngOnChanges() {
|
|
4058
|
-
this.setLogoTheme();
|
|
4059
|
-
this.setLogoType();
|
|
4060
|
-
}
|
|
4061
|
-
setLogoType() {
|
|
4062
|
-
switch (true) {
|
|
4063
|
-
case this.source instanceof AXPImageUrlLogoConfig:
|
|
4064
|
-
this.logoType = 'url';
|
|
4065
|
-
break;
|
|
4066
|
-
case this.source instanceof AXPComponentLogoConfig:
|
|
4067
|
-
this.logoType = 'component';
|
|
4068
|
-
break;
|
|
4069
|
-
case this.source instanceof AXPIconLogoConfig:
|
|
4070
|
-
this.logoType = 'icon';
|
|
4071
|
-
break;
|
|
4072
|
-
default:
|
|
4073
|
-
break;
|
|
4074
|
-
}
|
|
4075
|
-
}
|
|
4076
|
-
setLogoTheme() {
|
|
4077
|
-
if (this.source && this.source.dark && this.source.light) {
|
|
4078
|
-
this.source = this.platform.isDark() ? this.source.dark : this.source.light;
|
|
4079
|
-
}
|
|
4080
|
-
}
|
|
4081
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4082
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPLogoComponent, isStandalone: true, selector: "axp-logo", inputs: { source: "source" }, host: { classAttribute: "ax-flex ax-justify-center" }, usesOnChanges: true, ngImport: i0, template: "@switch (logoType) { \n @case ('url') {\n <ax-image [width]=\"source.width\" [height]=\"source.height\" [src]=\"source.url\"></ax-image>\n } \n @case ('component') {\n <ng-container *ngComponentOutlet=\"source.component\"></ng-container>\n } \n @case ('icon') {\n <i [class]=\"source.icon\" [style.color]=\"source.color\"></i>\n } \n}\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i2$6.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXDecoratorModule }] }); }
|
|
4083
|
-
}
|
|
4084
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPLogoComponent, decorators: [{
|
|
4085
|
-
type: Component,
|
|
4086
|
-
args: [{ selector: 'axp-logo', imports: [CommonModule, AXImageModule, AXDecoratorModule], host: { class: 'ax-flex ax-justify-center' }, template: "@switch (logoType) { \n @case ('url') {\n <ax-image [width]=\"source.width\" [height]=\"source.height\" [src]=\"source.url\"></ax-image>\n } \n @case ('component') {\n <ng-container *ngComponentOutlet=\"source.component\"></ng-container>\n } \n @case ('icon') {\n <i [class]=\"source.icon\" [style.color]=\"source.color\"></i>\n } \n}\n\n" }]
|
|
4087
|
-
}], propDecorators: { source: [{
|
|
4088
|
-
type: Input
|
|
4089
|
-
}] } });
|
|
4090
|
-
|
|
4091
|
-
class AXPPropertyViewerComponent {
|
|
3657
|
+
//#region ---- Component Definition ----
|
|
3658
|
+
class AXPSpreadsheetComponent {
|
|
4092
3659
|
//#endregion
|
|
3660
|
+
//#region ---- Lifecycle Methods ----
|
|
4093
3661
|
constructor() {
|
|
3662
|
+
//#endregion
|
|
3663
|
+
//#region ---- Services & Dependencies ----
|
|
3664
|
+
this.translationService = inject(AXTranslationService);
|
|
3665
|
+
//#endregion
|
|
3666
|
+
//#region ---- Computed Properties for Translations ----
|
|
3667
|
+
/**
|
|
3668
|
+
* Translated column titles
|
|
3669
|
+
*/
|
|
3670
|
+
this.translatedColumnTitles = signal(new Map(), ...(ngDevMode ? [{ debugName: "translatedColumnTitles" }] : []));
|
|
3671
|
+
//#endregion
|
|
4094
3672
|
//#region ---- Inputs ----
|
|
4095
3673
|
/**
|
|
4096
|
-
*
|
|
3674
|
+
* Title for the spreadsheet (displayed in corner cell)
|
|
4097
3675
|
*/
|
|
4098
|
-
this.
|
|
3676
|
+
this.title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
4099
3677
|
/**
|
|
4100
|
-
*
|
|
3678
|
+
* Column definitions
|
|
4101
3679
|
*/
|
|
4102
|
-
this.
|
|
3680
|
+
this.columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
3681
|
+
/**
|
|
3682
|
+
* Row mode: 'fixed' or 'dynamic'
|
|
3683
|
+
*/
|
|
3684
|
+
this.rowMode = input('fixed', ...(ngDevMode ? [{ debugName: "rowMode" }] : []));
|
|
3685
|
+
/**
|
|
3686
|
+
* Rows data (for fixed mode - input only)
|
|
3687
|
+
* Each row must have a 'name' property for identification
|
|
3688
|
+
*/
|
|
3689
|
+
this.rowsInput = input([], ...(ngDevMode ? [{ debugName: "rowsInput" }] : []));
|
|
3690
|
+
/**
|
|
3691
|
+
* Rows data (for dynamic mode - two-way binding)
|
|
3692
|
+
*/
|
|
3693
|
+
this.rowsModel = model([], ...(ngDevMode ? [{ debugName: "rowsModel" }] : []));
|
|
3694
|
+
/**
|
|
3695
|
+
* Whether the spreadsheet is in readonly mode
|
|
3696
|
+
*/
|
|
3697
|
+
this.readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
|
|
3698
|
+
/**
|
|
3699
|
+
* Placeholder text for empty cells (default: "–")
|
|
3700
|
+
*/
|
|
3701
|
+
this.emptyCellPlaceholder = input('–', ...(ngDevMode ? [{ debugName: "emptyCellPlaceholder" }] : []));
|
|
3702
|
+
/**
|
|
3703
|
+
* Path to property in row object to display as row header title
|
|
3704
|
+
* Example: 'name', 'title', 'user.name'
|
|
3705
|
+
*/
|
|
3706
|
+
this.rowTitlePath = input(null, ...(ngDevMode ? [{ debugName: "rowTitlePath" }] : []));
|
|
3707
|
+
/**
|
|
3708
|
+
* Path to property in row object to display as row header description
|
|
3709
|
+
* Example: 'description', 'details', 'user.description'
|
|
3710
|
+
*/
|
|
3711
|
+
this.rowDescriptionPath = input(null, ...(ngDevMode ? [{ debugName: "rowDescriptionPath" }] : []));
|
|
3712
|
+
/**
|
|
3713
|
+
* Whether to allow adding rows (dynamic mode only, default: true)
|
|
3714
|
+
*/
|
|
3715
|
+
this.allowAddRows = input(true, ...(ngDevMode ? [{ debugName: "allowAddRows" }] : []));
|
|
3716
|
+
/**
|
|
3717
|
+
* Whether to allow removing rows (default: true for dynamic mode, false for fixed mode)
|
|
3718
|
+
* Can be enabled for fixed mode if needed
|
|
3719
|
+
*/
|
|
3720
|
+
this.allowRemoveRows = input(true, ...(ngDevMode ? [{ debugName: "allowRemoveRows" }] : []));
|
|
4103
3721
|
//#endregion
|
|
4104
3722
|
//#region ---- Outputs ----
|
|
4105
3723
|
/**
|
|
4106
|
-
*
|
|
3724
|
+
* Emitted when a single cell value changes
|
|
4107
3725
|
*/
|
|
4108
|
-
this.
|
|
3726
|
+
this.cellChange = output();
|
|
3727
|
+
/**
|
|
3728
|
+
* Emitted when rows are added or removed (dynamic mode only)
|
|
3729
|
+
*/
|
|
3730
|
+
this.rowChange = output();
|
|
3731
|
+
/**
|
|
3732
|
+
* Emitted when the entire spreadsheet data changes
|
|
3733
|
+
*/
|
|
3734
|
+
this.spreadsheetChange = output();
|
|
4109
3735
|
//#endregion
|
|
4110
|
-
//#region ----
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
3736
|
+
//#region ---- Class Properties ----
|
|
3737
|
+
/**
|
|
3738
|
+
* Currently editing cell: { rowId, columnName } | null
|
|
3739
|
+
*/
|
|
3740
|
+
this.editingCell = signal(null, ...(ngDevMode ? [{ debugName: "editingCell" }] : []));
|
|
3741
|
+
/**
|
|
3742
|
+
* Original value when entering edit mode (for cancel functionality)
|
|
3743
|
+
*/
|
|
3744
|
+
this.originalCellValue = signal(null, ...(ngDevMode ? [{ debugName: "originalCellValue" }] : []));
|
|
3745
|
+
/**
|
|
3746
|
+
* Internal rows state (for fixed mode)
|
|
3747
|
+
*/
|
|
3748
|
+
this.internalRows = signal([], ...(ngDevMode ? [{ debugName: "internalRows" }] : []));
|
|
3749
|
+
/**
|
|
3750
|
+
* Row ID mapping: rowId -> row index (for tracking)
|
|
3751
|
+
*/
|
|
3752
|
+
this.rowIdMap = new Map();
|
|
3753
|
+
/**
|
|
3754
|
+
* Cache for widget nodes to prevent re-rendering
|
|
3755
|
+
* Key: `${rowIndex}_${columnName}`, Value: AXPWidgetNode
|
|
3756
|
+
*/
|
|
3757
|
+
this.widgetNodeCache = new Map();
|
|
3758
|
+
/**
|
|
3759
|
+
* Cache for cell values to detect actual changes
|
|
3760
|
+
* Key: `${rowIndex}_${columnName}`, Value: any
|
|
3761
|
+
*/
|
|
3762
|
+
this.cellValueCache = new Map();
|
|
3763
|
+
//#endregion
|
|
3764
|
+
//#region ---- Computed Properties ----
|
|
3765
|
+
/**
|
|
3766
|
+
* Get current rows based on mode
|
|
3767
|
+
*/
|
|
3768
|
+
this.currentRows = computed(() => {
|
|
3769
|
+
if (this.rowMode() === 'dynamic') {
|
|
3770
|
+
return this.rowsModel();
|
|
4131
3771
|
}
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
this.currentTabIndex.set(index);
|
|
3772
|
+
else {
|
|
3773
|
+
return this.internalRows();
|
|
4135
3774
|
}
|
|
4136
|
-
|
|
4137
|
-
...group,
|
|
4138
|
-
isCollapsed: this.groupCollapsedStates.get(group.name) ?? !!group.isCollapsed,
|
|
4139
|
-
}));
|
|
4140
|
-
}, ...(ngDevMode ? [{ debugName: "groups" }] : []));
|
|
4141
|
-
this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
3775
|
+
}, ...(ngDevMode ? [{ debugName: "currentRows" }] : []));
|
|
4142
3776
|
/**
|
|
4143
|
-
*
|
|
4144
|
-
*
|
|
3777
|
+
* Context for widgets-container (all rows as an object with rows array)
|
|
3778
|
+
* This allows widgets to access their cell via path like: rows[index].column.path
|
|
4145
3779
|
*/
|
|
4146
|
-
this.
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
3780
|
+
this.spreadsheetContext = computed(() => {
|
|
3781
|
+
return {
|
|
3782
|
+
rows: this.currentRows(),
|
|
3783
|
+
};
|
|
3784
|
+
}, ...(ngDevMode ? [{ debugName: "spreadsheetContext" }] : []));
|
|
3785
|
+
/**
|
|
3786
|
+
* Get rows with IDs (ensure all rows have identifiers)
|
|
3787
|
+
*/
|
|
3788
|
+
this.rowsWithIds = computed(() => {
|
|
3789
|
+
const rows = this.currentRows();
|
|
3790
|
+
const mode = this.rowMode();
|
|
3791
|
+
const result = [];
|
|
3792
|
+
rows.forEach((row, index) => {
|
|
3793
|
+
let rowId;
|
|
3794
|
+
if (mode === 'fixed') {
|
|
3795
|
+
// Fixed mode: use 'name' property
|
|
3796
|
+
rowId = row['name'] || `row_${index}`;
|
|
3797
|
+
}
|
|
3798
|
+
else {
|
|
3799
|
+
// Dynamic mode: generate ID if not exists
|
|
3800
|
+
if (!row['_id']) {
|
|
3801
|
+
row['_id'] = this.generateRowId();
|
|
3802
|
+
}
|
|
3803
|
+
rowId = row['_id'];
|
|
4158
3804
|
}
|
|
3805
|
+
// Update row ID map
|
|
3806
|
+
this.rowIdMap.set(rowId, index);
|
|
3807
|
+
result.push({ rowId, row });
|
|
4159
3808
|
});
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
this.
|
|
4184
|
-
|
|
4185
|
-
});
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
3809
|
+
return result;
|
|
3810
|
+
}, ...(ngDevMode ? [{ debugName: "rowsWithIds" }] : []));
|
|
3811
|
+
/**
|
|
3812
|
+
* Check if spreadsheet is completely empty (both columns and rows)
|
|
3813
|
+
*/
|
|
3814
|
+
this.isEmpty = computed(() => {
|
|
3815
|
+
const columns = this.columns();
|
|
3816
|
+
const rows = this.currentRows();
|
|
3817
|
+
return (!columns || columns.length === 0) && (!rows || rows.length === 0);
|
|
3818
|
+
}, ...(ngDevMode ? [{ debugName: "isEmpty" }] : []));
|
|
3819
|
+
/**
|
|
3820
|
+
* Check if columns are empty (regardless of rows)
|
|
3821
|
+
* When columns are empty, we should show a message about missing columns, not rows
|
|
3822
|
+
*/
|
|
3823
|
+
this.isColumnsEmpty = computed(() => {
|
|
3824
|
+
const columns = this.columns();
|
|
3825
|
+
return !columns || columns.length === 0;
|
|
3826
|
+
}, ...(ngDevMode ? [{ debugName: "isColumnsEmpty" }] : []));
|
|
3827
|
+
/**
|
|
3828
|
+
* Check if only rows are empty (columns exist but no rows)
|
|
3829
|
+
*/
|
|
3830
|
+
this.isRowsEmpty = computed(() => {
|
|
3831
|
+
const columns = this.columns();
|
|
3832
|
+
const rows = this.currentRows();
|
|
3833
|
+
return (columns && columns.length > 0) && (!rows || rows.length === 0);
|
|
3834
|
+
}, ...(ngDevMode ? [{ debugName: "isRowsEmpty" }] : []));
|
|
3835
|
+
// Initialize rows from input (fixed mode)
|
|
3836
|
+
this.internalRows.set(this.rowsInput());
|
|
3837
|
+
// Watch for rowsInput changes and update internalRows (fixed mode only)
|
|
3838
|
+
effect(() => {
|
|
3839
|
+
const rowsInput = this.rowsInput();
|
|
3840
|
+
const rowMode = this.rowMode();
|
|
3841
|
+
// Only update internalRows in fixed mode
|
|
3842
|
+
if (rowMode === 'fixed') {
|
|
3843
|
+
this.internalRows.set(rowsInput);
|
|
3844
|
+
}
|
|
3845
|
+
});
|
|
3846
|
+
}
|
|
3847
|
+
//#endregion
|
|
3848
|
+
//#region ---- Cell Value Methods ----
|
|
4189
3849
|
/**
|
|
4190
|
-
*
|
|
3850
|
+
* Get the value for a specific cell by row index
|
|
4191
3851
|
*/
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
3852
|
+
getCellValue(rowIndex, columnName) {
|
|
3853
|
+
const rows = this.currentRows();
|
|
3854
|
+
const row = rows[rowIndex];
|
|
3855
|
+
if (!row) {
|
|
3856
|
+
return null;
|
|
3857
|
+
}
|
|
3858
|
+
const column = this.columns().find((col) => col.name === columnName);
|
|
3859
|
+
if (!column) {
|
|
3860
|
+
return null;
|
|
3861
|
+
}
|
|
3862
|
+
return get(row, column.path, null);
|
|
4197
3863
|
}
|
|
4198
3864
|
/**
|
|
4199
|
-
*
|
|
3865
|
+
* Get row title from row object using rowTitlePath
|
|
4200
3866
|
*/
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
this.currentTabIndex.set(index);
|
|
3867
|
+
getRowTitle(row, path) {
|
|
3868
|
+
if (!row || !path) {
|
|
3869
|
+
return '';
|
|
4205
3870
|
}
|
|
3871
|
+
return get(row, path, '') || '';
|
|
4206
3872
|
}
|
|
4207
3873
|
/**
|
|
4208
|
-
*
|
|
3874
|
+
* Get row description from row object using rowDescriptionPath
|
|
4209
3875
|
*/
|
|
4210
|
-
|
|
4211
|
-
|
|
3876
|
+
getRowDescription(row, path) {
|
|
3877
|
+
if (!row || !path) {
|
|
3878
|
+
return '';
|
|
3879
|
+
}
|
|
3880
|
+
return get(row, path, '') || '';
|
|
4212
3881
|
}
|
|
4213
3882
|
/**
|
|
4214
|
-
*
|
|
3883
|
+
* Get row by ID
|
|
4215
3884
|
*/
|
|
4216
|
-
|
|
4217
|
-
const
|
|
4218
|
-
|
|
3885
|
+
getRowById(rowId) {
|
|
3886
|
+
const rowsWithIds = this.rowsWithIds();
|
|
3887
|
+
const found = rowsWithIds.find((item) => item.rowId === rowId);
|
|
3888
|
+
return found ? found.row : null;
|
|
4219
3889
|
}
|
|
4220
3890
|
/**
|
|
4221
|
-
*
|
|
4222
|
-
* Uses expressionModeState when set; otherwise derives from isExpression(valueAtPath).
|
|
3891
|
+
* Check if a cell is currently being edited
|
|
4223
3892
|
*/
|
|
4224
|
-
|
|
4225
|
-
this.
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
3893
|
+
isCellEditing(rowId, columnName) {
|
|
3894
|
+
const editing = this.editingCell();
|
|
3895
|
+
return editing?.rowId === rowId && editing?.columnName === columnName;
|
|
3896
|
+
}
|
|
3897
|
+
/**
|
|
3898
|
+
* Check if a column is readonly
|
|
3899
|
+
*/
|
|
3900
|
+
isColumnReadonly(column) {
|
|
3901
|
+
return this.readonly() || column.readonly === true;
|
|
3902
|
+
}
|
|
3903
|
+
/**
|
|
3904
|
+
* Get widget node for a cell with dynamic path based on row index
|
|
3905
|
+
* Path format: rows[rowIndex].column.path
|
|
3906
|
+
* Uses caching to prevent unnecessary re-renders
|
|
3907
|
+
*/
|
|
3908
|
+
getCellWidgetNode(column, rowIndex) {
|
|
3909
|
+
const cacheKey = `${rowIndex}_${column.name}`;
|
|
3910
|
+
const rows = this.currentRows();
|
|
3911
|
+
const row = rows[rowIndex];
|
|
3912
|
+
const currentValue = row ? get(row, column.path, null) : null;
|
|
3913
|
+
const cachedValue = this.cellValueCache.get(cacheKey);
|
|
3914
|
+
// Get or create widget node
|
|
3915
|
+
let widgetNode = this.widgetNodeCache.get(cacheKey);
|
|
3916
|
+
if (!widgetNode) {
|
|
3917
|
+
// Create path: rows[index].column.path
|
|
3918
|
+
const dynamicPath = `rows.${rowIndex}.${column.path}`;
|
|
3919
|
+
// Create new widget node
|
|
3920
|
+
widgetNode = {
|
|
3921
|
+
...column.widget,
|
|
3922
|
+
path: dynamicPath,
|
|
3923
|
+
defaultValue: currentValue !== null && currentValue !== undefined ? currentValue : column.widget.defaultValue,
|
|
3924
|
+
};
|
|
3925
|
+
// Cache the widget node
|
|
3926
|
+
this.widgetNodeCache.set(cacheKey, widgetNode);
|
|
3927
|
+
this.cellValueCache.set(cacheKey, currentValue);
|
|
4230
3928
|
}
|
|
4231
|
-
|
|
4232
|
-
|
|
3929
|
+
else {
|
|
3930
|
+
// Update path in case row index changed (shouldn't happen, but be safe)
|
|
3931
|
+
widgetNode.path = `rows.${rowIndex}.${column.path}`;
|
|
3932
|
+
// Only update defaultValue if value actually changed (to prevent re-renders)
|
|
3933
|
+
if (cachedValue !== currentValue) {
|
|
3934
|
+
widgetNode.defaultValue = currentValue !== null && currentValue !== undefined ? currentValue : column.widget.defaultValue;
|
|
3935
|
+
this.cellValueCache.set(cacheKey, currentValue);
|
|
3936
|
+
}
|
|
3937
|
+
}
|
|
3938
|
+
return widgetNode;
|
|
4233
3939
|
}
|
|
3940
|
+
//#endregion
|
|
3941
|
+
//#region ---- Event Handlers ----
|
|
4234
3942
|
/**
|
|
4235
|
-
*
|
|
4236
|
-
* Source of truth is prop.schema.defaultValue (widget.types): plain value, or function (context) => value.
|
|
4237
|
-
* A minimal dataType fallback is used only when the schema provides no default.
|
|
3943
|
+
* Handle cell click to start editing
|
|
4238
3944
|
*/
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
return def(this.context());
|
|
3945
|
+
handleCellClick(rowId, columnName, event) {
|
|
3946
|
+
if (this.readonly()) {
|
|
3947
|
+
return;
|
|
4243
3948
|
}
|
|
4244
|
-
|
|
4245
|
-
|
|
3949
|
+
// Don't open editor if clicking on toolbar or buttons
|
|
3950
|
+
if (event) {
|
|
3951
|
+
const target = event.target;
|
|
3952
|
+
if (target.closest('.__cell-toolbar') || target.closest('ax-button')) {
|
|
3953
|
+
return;
|
|
3954
|
+
}
|
|
4246
3955
|
}
|
|
4247
|
-
const
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
3956
|
+
const column = this.columns().find((col) => col.name === columnName);
|
|
3957
|
+
if (!column || this.isColumnReadonly(column)) {
|
|
3958
|
+
return;
|
|
3959
|
+
}
|
|
3960
|
+
// Don't open if already editing this cell
|
|
3961
|
+
const currentEditing = this.editingCell();
|
|
3962
|
+
if (currentEditing?.rowId === rowId && currentEditing?.columnName === columnName) {
|
|
3963
|
+
return;
|
|
3964
|
+
}
|
|
3965
|
+
// Store original value for cancel functionality
|
|
3966
|
+
const row = this.getRowById(rowId);
|
|
3967
|
+
if (row) {
|
|
3968
|
+
const originalValue = get(row, column.path, null);
|
|
3969
|
+
this.originalCellValue.set(originalValue);
|
|
4259
3970
|
}
|
|
3971
|
+
this.editingCell.set({ rowId, columnName });
|
|
4260
3972
|
}
|
|
4261
3973
|
/**
|
|
4262
|
-
*
|
|
4263
|
-
*
|
|
4264
|
-
* widget renderer does not receive the expression string (e.g. checkbox gets false, not a string).
|
|
4265
|
-
* When switching to expression: sets the value at path to '{{ }}' so the popup opens with
|
|
4266
|
-
* a clean expression placeholder instead of the previous literal (e.g. true/false).
|
|
3974
|
+
* Handle cell value change from widget
|
|
3975
|
+
* The widget sets the value at path like rows[index].column.path
|
|
4267
3976
|
*/
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
this.expressionModeState.update((s) => ({ ...s, [path]: useExpression }));
|
|
4273
|
-
if (!useExpression && currentIsExpression) {
|
|
4274
|
-
const next = cloneDeep(this.context());
|
|
4275
|
-
set(next, path, this.getDefaultValueForProperty(prop));
|
|
4276
|
-
untracked(() => {
|
|
4277
|
-
this.context.set(next);
|
|
4278
|
-
this.onChanged.emit({ values: this.context(), mode: 'update' });
|
|
4279
|
-
});
|
|
3977
|
+
handleCellValueChange(rowIndex, columnName, event) {
|
|
3978
|
+
// Only process if context has changed (not just initiated)
|
|
3979
|
+
if (event.state !== 'changed') {
|
|
3980
|
+
return;
|
|
4280
3981
|
}
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
3982
|
+
const rows = this.currentRows();
|
|
3983
|
+
const row = rows[rowIndex];
|
|
3984
|
+
if (!row) {
|
|
3985
|
+
return;
|
|
3986
|
+
}
|
|
3987
|
+
const column = this.columns().find((col) => col.name === columnName);
|
|
3988
|
+
if (!column) {
|
|
3989
|
+
return;
|
|
4288
3990
|
}
|
|
3991
|
+
// Get the new value from the context (widget sets it at rows[index].column.path)
|
|
3992
|
+
const dynamicPath = `rows.${rowIndex}.${column.path}`;
|
|
3993
|
+
const newValue = get(event.data, dynamicPath);
|
|
3994
|
+
// Update the row object directly
|
|
3995
|
+
set(row, column.path, newValue);
|
|
3996
|
+
// Update rows array
|
|
3997
|
+
this.updateRows();
|
|
3998
|
+
// Get rowId for events
|
|
3999
|
+
const rowId = this.rowMode() === 'fixed' ? row['name'] : row['_id'];
|
|
4000
|
+
// Emit events
|
|
4001
|
+
this.cellChange.emit({
|
|
4002
|
+
rowId: rowId || `row_${rowIndex}`,
|
|
4003
|
+
columnName,
|
|
4004
|
+
value: newValue,
|
|
4005
|
+
row: { ...row },
|
|
4006
|
+
});
|
|
4007
|
+
this.spreadsheetChange.emit([...this.currentRows()]);
|
|
4008
|
+
// Don't close edit mode automatically - let user finish editing
|
|
4009
|
+
// Edit mode will close on blur or click outside
|
|
4289
4010
|
}
|
|
4290
4011
|
/**
|
|
4291
|
-
*
|
|
4292
|
-
*
|
|
4012
|
+
* Handle spreadsheet context change from widgets-container
|
|
4013
|
+
* This is called when any widget in the spreadsheet changes
|
|
4293
4014
|
*/
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
const
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
}
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4015
|
+
handleSpreadsheetContextChange(event) {
|
|
4016
|
+
if (event.state !== 'changed') {
|
|
4017
|
+
return;
|
|
4018
|
+
}
|
|
4019
|
+
// Extract row index and column from the path (format: rows[index].column.path)
|
|
4020
|
+
const path = event.path || '';
|
|
4021
|
+
const pathMatch = path.match(/^rows\.(\d+)\.(.+)$/);
|
|
4022
|
+
if (!pathMatch) {
|
|
4023
|
+
return;
|
|
4024
|
+
}
|
|
4025
|
+
const rowIndex = parseInt(pathMatch[1], 10);
|
|
4026
|
+
const columnPath = pathMatch[2];
|
|
4027
|
+
// Find the column by path
|
|
4028
|
+
const column = this.columns().find((col) => col.path === columnPath);
|
|
4029
|
+
if (!column) {
|
|
4030
|
+
return;
|
|
4031
|
+
}
|
|
4032
|
+
// Get the new value from event.data
|
|
4033
|
+
const newValue = get(event.data, path);
|
|
4034
|
+
// Update the row object (sync with context)
|
|
4035
|
+
const rows = this.currentRows();
|
|
4036
|
+
const row = rows[rowIndex];
|
|
4037
|
+
if (row) {
|
|
4038
|
+
// The context should already have the updated value, but sync row object to be sure
|
|
4039
|
+
set(row, columnPath, newValue);
|
|
4040
|
+
// Update cache (widget node will update defaultValue on next getCellWidgetNode call)
|
|
4041
|
+
const cacheKey = `${rowIndex}_${column.name}`;
|
|
4042
|
+
this.cellValueCache.set(cacheKey, newValue);
|
|
4043
|
+
// Don't delete widget node cache - just update defaultValue on next access
|
|
4044
|
+
// This prevents re-rendering while still reflecting the new value
|
|
4045
|
+
this.updateRows();
|
|
4046
|
+
// Get rowId for events
|
|
4047
|
+
const rowId = this.rowMode() === 'fixed' ? row['name'] : row['_id'];
|
|
4048
|
+
// Emit events
|
|
4049
|
+
this.cellChange.emit({
|
|
4050
|
+
rowId: rowId || `row_${rowIndex}`,
|
|
4051
|
+
columnName: column.name,
|
|
4052
|
+
value: newValue,
|
|
4053
|
+
row: { ...row },
|
|
4310
4054
|
});
|
|
4055
|
+
this.spreadsheetChange.emit([...this.currentRows()]);
|
|
4311
4056
|
}
|
|
4312
4057
|
}
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
class AXPPropertyViewerPopupComponent extends AXBasePageComponent {
|
|
4333
|
-
//#endregion
|
|
4334
|
-
constructor() {
|
|
4335
|
-
super();
|
|
4336
|
-
//#region ---- Inputs ----
|
|
4337
|
-
this.tabs = input.required(...(ngDevMode ? [{ debugName: "tabs" }] : []));
|
|
4338
|
-
this.mode = input('simple', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
4339
|
-
this.context = input({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
4340
|
-
//#endregion
|
|
4341
|
-
//#region ---- Properties ----
|
|
4342
|
-
this.propertyViewer = viewChild(AXPPropertyViewerComponent, ...(ngDevMode ? [{ debugName: "propertyViewer" }] : []));
|
|
4343
|
-
this.currentValues = signal({}, ...(ngDevMode ? [{ debugName: "currentValues" }] : []));
|
|
4344
|
-
this.currentMode = 'init';
|
|
4345
|
-
effect(() => {
|
|
4346
|
-
const viewer = this.propertyViewer();
|
|
4347
|
-
if (!viewer) {
|
|
4348
|
-
return;
|
|
4349
|
-
}
|
|
4350
|
-
viewer.initializeContext(this.context() ?? {});
|
|
4351
|
-
});
|
|
4352
|
-
}
|
|
4353
|
-
//#region ---- Event Handlers ----
|
|
4354
|
-
handlePropertyChanged(event) {
|
|
4355
|
-
this.currentValues.set(event.values ?? {});
|
|
4356
|
-
this.currentMode = event.mode;
|
|
4357
|
-
}
|
|
4358
|
-
handleCloseClick() {
|
|
4359
|
-
this.close();
|
|
4360
|
-
}
|
|
4361
|
-
handleApplyClick() {
|
|
4362
|
-
this.close({
|
|
4363
|
-
values: this.currentValues(),
|
|
4364
|
-
mode: this.currentMode,
|
|
4365
|
-
});
|
|
4366
|
-
}
|
|
4367
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPPropertyViewerPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4368
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.16", type: AXPPropertyViewerPopupComponent, isStandalone: true, selector: "axp-property-viewer-popup", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "propertyViewer", first: true, predicate: AXPPropertyViewerComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
4369
|
-
<div class="ax-flex ax-flex-col ax-h-full ax-overflow-hidden">
|
|
4370
|
-
<axp-property-viewer
|
|
4371
|
-
[tabsInput]="tabs()"
|
|
4372
|
-
[mode]="mode()"
|
|
4373
|
-
(onChanged)="handlePropertyChanged($event)"
|
|
4374
|
-
></axp-property-viewer>
|
|
4375
|
-
</div>
|
|
4376
|
-
|
|
4377
|
-
<ax-footer>
|
|
4378
|
-
<ax-suffix>
|
|
4379
|
-
<ax-button
|
|
4380
|
-
look="solid"
|
|
4381
|
-
[text]="'@general:actions.close.title' | translate | async"
|
|
4382
|
-
(onClick)="handleCloseClick()"
|
|
4383
|
-
></ax-button>
|
|
4384
|
-
<ax-button
|
|
4385
|
-
look="solid"
|
|
4386
|
-
color="primary"
|
|
4387
|
-
[text]="'@general:actions.apply.title' | translate | async"
|
|
4388
|
-
(onClick)="handleApplyClick()"
|
|
4389
|
-
></ax-button>
|
|
4390
|
-
</ax-suffix>
|
|
4391
|
-
</ax-footer>
|
|
4392
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPPropertyViewerComponent, selector: "axp-property-viewer", inputs: ["tabsInput", "mode"], outputs: ["onChanged"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4393
|
-
}
|
|
4394
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPPropertyViewerPopupComponent, decorators: [{
|
|
4395
|
-
type: Component,
|
|
4396
|
-
args: [{
|
|
4397
|
-
selector: 'axp-property-viewer-popup',
|
|
4398
|
-
template: `
|
|
4399
|
-
<div class="ax-flex ax-flex-col ax-h-full ax-overflow-hidden">
|
|
4400
|
-
<axp-property-viewer
|
|
4401
|
-
[tabsInput]="tabs()"
|
|
4402
|
-
[mode]="mode()"
|
|
4403
|
-
(onChanged)="handlePropertyChanged($event)"
|
|
4404
|
-
></axp-property-viewer>
|
|
4405
|
-
</div>
|
|
4406
|
-
|
|
4407
|
-
<ax-footer>
|
|
4408
|
-
<ax-suffix>
|
|
4409
|
-
<ax-button
|
|
4410
|
-
look="solid"
|
|
4411
|
-
[text]="'@general:actions.close.title' | translate | async"
|
|
4412
|
-
(onClick)="handleCloseClick()"
|
|
4413
|
-
></ax-button>
|
|
4414
|
-
<ax-button
|
|
4415
|
-
look="solid"
|
|
4416
|
-
color="primary"
|
|
4417
|
-
[text]="'@general:actions.apply.title' | translate | async"
|
|
4418
|
-
(onClick)="handleApplyClick()"
|
|
4419
|
-
></ax-button>
|
|
4420
|
-
</ax-suffix>
|
|
4421
|
-
</ax-footer>
|
|
4422
|
-
`,
|
|
4423
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
4424
|
-
imports: [CommonModule, AXButtonModule, AXDecoratorModule, AXTranslationModule, AXPPropertyViewerComponent],
|
|
4425
|
-
}]
|
|
4426
|
-
}], ctorParameters: () => [], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: true }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], propertyViewer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPPropertyViewerComponent), { isSignal: true }] }] } });
|
|
4427
|
-
|
|
4428
|
-
var propertyViewerPopup_component = /*#__PURE__*/Object.freeze({
|
|
4429
|
-
__proto__: null,
|
|
4430
|
-
AXPPropertyViewerPopupComponent: AXPPropertyViewerPopupComponent
|
|
4431
|
-
});
|
|
4432
|
-
|
|
4433
|
-
class AXPPropertyViewerService {
|
|
4434
|
-
constructor() {
|
|
4435
|
-
//#region ---- Services & Dependencies ----
|
|
4436
|
-
this.popupService = inject(AXPopupService);
|
|
4058
|
+
/**
|
|
4059
|
+
* Handle blur event to stop editing (when user clicks away from cell)
|
|
4060
|
+
*/
|
|
4061
|
+
handleCellBlur(rowId, columnName) {
|
|
4062
|
+
// Small delay to allow click events to process first
|
|
4063
|
+
setTimeout(() => {
|
|
4064
|
+
const editing = this.editingCell();
|
|
4065
|
+
if (editing?.rowId === rowId && editing?.columnName === columnName) {
|
|
4066
|
+
// Don't close if clicking on the toolbar or buttons
|
|
4067
|
+
const activeElement = document.activeElement;
|
|
4068
|
+
const toolbarElement = activeElement?.closest('.__cell-toolbar');
|
|
4069
|
+
const buttonElement = activeElement?.closest('ax-button');
|
|
4070
|
+
// Only auto-commit if not clicking on toolbar or buttons
|
|
4071
|
+
if (!toolbarElement && !buttonElement) {
|
|
4072
|
+
this.commitCellEdit();
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
}, 150);
|
|
4437
4076
|
}
|
|
4438
|
-
//#endregion
|
|
4439
|
-
//#region ---- Public Methods ----
|
|
4440
4077
|
/**
|
|
4441
|
-
*
|
|
4078
|
+
* Handle Escape key to cancel editing
|
|
4442
4079
|
*/
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
tabs: signal(config.tabs),
|
|
4450
|
-
mode: signal(config.mode || 'simple'),
|
|
4451
|
-
context: signal(config.context ?? {}),
|
|
4452
|
-
},
|
|
4453
|
-
});
|
|
4454
|
-
return result.data || null;
|
|
4080
|
+
handleKeyDown(event) {
|
|
4081
|
+
if (event.key === 'Escape' && this.editingCell()) {
|
|
4082
|
+
event.preventDefault();
|
|
4083
|
+
event.stopPropagation();
|
|
4084
|
+
this.cancelCellEdit();
|
|
4085
|
+
}
|
|
4455
4086
|
}
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
this
|
|
4087
|
+
/**
|
|
4088
|
+
* Commit cell edit (save changes and close editing mode)
|
|
4089
|
+
*/
|
|
4090
|
+
commitCellEdit() {
|
|
4091
|
+
const editing = this.editingCell();
|
|
4092
|
+
if (!editing) {
|
|
4093
|
+
return;
|
|
4094
|
+
}
|
|
4095
|
+
// Changes are already saved via handleSpreadsheetContextChange
|
|
4096
|
+
// Close the editor (same as escape, but keeps changes)
|
|
4097
|
+
this.editingCell.set(null);
|
|
4098
|
+
this.originalCellValue.set(null);
|
|
4099
|
+
}
|
|
4100
|
+
/**
|
|
4101
|
+
* Cancel cell edit (discard changes and close editing mode - same as escape)
|
|
4102
|
+
*/
|
|
4103
|
+
cancelCellEdit() {
|
|
4104
|
+
const editing = this.editingCell();
|
|
4105
|
+
if (!editing) {
|
|
4106
|
+
return;
|
|
4107
|
+
}
|
|
4108
|
+
const row = this.getRowById(editing.rowId);
|
|
4109
|
+
const column = this.columns().find((col) => col.name === editing.columnName);
|
|
4110
|
+
const originalValue = this.originalCellValue();
|
|
4111
|
+
if (row && column) {
|
|
4112
|
+
// Restore original value in row
|
|
4113
|
+
set(row, column.path, originalValue);
|
|
4114
|
+
// Clear cache for this cell so widget re-renders with original value
|
|
4115
|
+
const rowsWithIds = this.rowsWithIds();
|
|
4116
|
+
const rowIndex = rowsWithIds.findIndex((item) => item.rowId === editing.rowId);
|
|
4117
|
+
if (rowIndex !== -1) {
|
|
4118
|
+
const cacheKey = `${rowIndex}_${editing.columnName}`;
|
|
4119
|
+
this.cellValueCache.set(cacheKey, originalValue);
|
|
4120
|
+
this.widgetNodeCache.delete(cacheKey);
|
|
4121
|
+
}
|
|
4122
|
+
this.updateRows();
|
|
4123
|
+
}
|
|
4124
|
+
// Close the editor (same as escape)
|
|
4125
|
+
this.editingCell.set(null);
|
|
4126
|
+
this.originalCellValue.set(null);
|
|
4127
|
+
}
|
|
4128
|
+
/**
|
|
4129
|
+
* Handle click outside to stop editing
|
|
4130
|
+
*/
|
|
4131
|
+
handleClickOutside(event) {
|
|
4132
|
+
const target = event.target;
|
|
4133
|
+
// Don't close if clicking inside a widget or its elements
|
|
4134
|
+
if (target.closest('[axp-widget-renderer]') ||
|
|
4135
|
+
target.closest('.ax-dropdown') ||
|
|
4136
|
+
target.closest('.ax-popup') ||
|
|
4137
|
+
target.closest('.__cell-editor')) {
|
|
4138
|
+
return;
|
|
4139
|
+
}
|
|
4140
|
+
this.editingCell.set(null);
|
|
4141
|
+
}
|
|
4142
|
+
/**
|
|
4143
|
+
* Handle add row (dynamic mode only)
|
|
4144
|
+
*/
|
|
4145
|
+
handleAddRow() {
|
|
4146
|
+
if (this.rowMode() !== 'dynamic' || !this.allowAddRows() || this.readonly()) {
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
const columns = this.columns();
|
|
4150
|
+
const newRow = {
|
|
4151
|
+
_id: this.generateRowId(),
|
|
4152
|
+
};
|
|
4153
|
+
// Initialize with default values from widgets
|
|
4154
|
+
columns.forEach((column) => {
|
|
4155
|
+
if (column.widget.defaultValue !== undefined && column.widget.defaultValue !== null) {
|
|
4156
|
+
set(newRow, column.path, column.widget.defaultValue);
|
|
4157
|
+
}
|
|
4484
4158
|
});
|
|
4485
|
-
|
|
4486
|
-
|
|
4159
|
+
const currentRows = this.rowsModel();
|
|
4160
|
+
const updatedRows = [...currentRows, newRow];
|
|
4161
|
+
this.rowsModel.set(updatedRows);
|
|
4162
|
+
this.rowChange.emit({
|
|
4163
|
+
type: 'add',
|
|
4164
|
+
rowId: newRow['_id'],
|
|
4165
|
+
row: { ...newRow },
|
|
4166
|
+
rows: updatedRows,
|
|
4487
4167
|
});
|
|
4168
|
+
this.spreadsheetChange.emit(updatedRows);
|
|
4488
4169
|
}
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
this.
|
|
4170
|
+
/**
|
|
4171
|
+
* Handle remove row (works for both fixed and dynamic modes)
|
|
4172
|
+
*/
|
|
4173
|
+
handleRemoveRow(rowId, _event) {
|
|
4174
|
+
if (!this.allowRemoveRows() || this.readonly()) {
|
|
4175
|
+
return;
|
|
4176
|
+
}
|
|
4177
|
+
const currentRows = this.currentRows();
|
|
4178
|
+
let rowIndex = -1;
|
|
4179
|
+
let removedRow;
|
|
4180
|
+
if (this.rowMode() === 'fixed') {
|
|
4181
|
+
// Fixed mode: find by 'name' property
|
|
4182
|
+
rowIndex = currentRows.findIndex((row) => row['name'] === rowId);
|
|
4183
|
+
}
|
|
4184
|
+
else {
|
|
4185
|
+
// Dynamic mode: find by '_id' property
|
|
4186
|
+
rowIndex = currentRows.findIndex((row) => row['_id'] === rowId);
|
|
4187
|
+
}
|
|
4188
|
+
if (rowIndex === -1) {
|
|
4189
|
+
return;
|
|
4190
|
+
}
|
|
4191
|
+
removedRow = currentRows[rowIndex];
|
|
4192
|
+
if (this.rowMode() === 'dynamic') {
|
|
4193
|
+
// Dynamic mode: update rowsModel
|
|
4194
|
+
const updatedRows = currentRows.filter((_, index) => index !== rowIndex);
|
|
4195
|
+
this.rowsModel.set(updatedRows);
|
|
4196
|
+
this.rowChange.emit({
|
|
4197
|
+
type: 'remove',
|
|
4198
|
+
rowId,
|
|
4199
|
+
row: { ...removedRow },
|
|
4200
|
+
rows: updatedRows,
|
|
4201
|
+
});
|
|
4202
|
+
this.spreadsheetChange.emit(updatedRows);
|
|
4203
|
+
}
|
|
4204
|
+
else {
|
|
4205
|
+
// Fixed mode: update internalRows and emit events
|
|
4206
|
+
const updatedRows = currentRows.filter((_, index) => index !== rowIndex);
|
|
4207
|
+
this.internalRows.set(updatedRows);
|
|
4208
|
+
this.rowChange.emit({
|
|
4209
|
+
type: 'remove',
|
|
4210
|
+
rowId,
|
|
4211
|
+
row: { ...removedRow },
|
|
4212
|
+
rows: updatedRows,
|
|
4213
|
+
});
|
|
4214
|
+
this.spreadsheetChange.emit(updatedRows);
|
|
4215
|
+
}
|
|
4497
4216
|
}
|
|
4498
|
-
|
|
4499
|
-
|
|
4217
|
+
//#endregion
|
|
4218
|
+
//#region ---- Utility Methods ----
|
|
4219
|
+
/**
|
|
4220
|
+
* Generate unique row ID for dynamic mode
|
|
4221
|
+
*/
|
|
4222
|
+
generateRowId() {
|
|
4223
|
+
return `row_${AXPDataGenerator.uuid()}`;
|
|
4500
4224
|
}
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4225
|
+
/**
|
|
4226
|
+
* Update rows array (sync internal state)
|
|
4227
|
+
*/
|
|
4228
|
+
updateRows() {
|
|
4229
|
+
if (this.rowMode() === 'dynamic') {
|
|
4230
|
+
// For dynamic mode, rowsModel is already updated (two-way binding)
|
|
4231
|
+
// Just trigger change detection
|
|
4232
|
+
this.rowsModel.set([...this.rowsModel()]);
|
|
4233
|
+
}
|
|
4234
|
+
else {
|
|
4235
|
+
// For fixed mode, update internal state
|
|
4236
|
+
this.internalRows.set([...this.internalRows()]);
|
|
4237
|
+
}
|
|
4512
4238
|
}
|
|
4513
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type:
|
|
4514
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPQuerySortsComponent, isStandalone: true, selector: "axp-query-sorts", inputs: { sortDefinitions: { classPropertyName: "sortDefinitions", publicName: "sortDefinitions", isSignal: true, isRequired: false, transformFunction: null }, initialSortQueries: { classPropertyName: "initialSortQueries", publicName: "initialSortQueries", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortDefinitions: "sortDefinitionsChange", sortQueriesChange: "sortQueriesChange" }, ngImport: i0, template: "<div class=\"ax-flex ax-flex-col ax-justify-center ax-gap-4 ax-select-none\">\n <div class=\"ax-flex ax-flex-col ax-gap-4 ax-select-none\" cdkDropList (cdkDropListDropped)=\"drop($event)\">\n <div class=\"ax-flex ax-flex-col ax-gap-3 ax-w-full ax-sorted-list ax-max-h-[calc(100vh-280px)] ax-overflow-auto\">\n @for (item of sortDefinitions(); track item.name) {\n <div class=\"ax-flex ax-py-1 ax-items-center ax-justify-between\" cdkDrag cdkDragBoundary=\".ax-sorted-list\">\n <div class=\"ax-flex ax-items-center ax-gap-3\" cdkDragHandle>\n <ax-icon class=\"fa-solid fa-grip-dots-vertical ax-cursor-move\"></ax-icon>\n <p class=\"ax-font-medium ax-text-sm\">{{ item.title | translate | async }}</p>\n </div>\n <ax-button [color]=\"'blank'\" class=\"ax-sm\" (click)=\"changeItemSort(item)\">\n <ax-icon\n [class.ax-text-primary]=\"getSortDirection(item) === 'asc'\"\n class=\"fa-solid fa-arrow-up-long ax-text-neutral-400\"\n ></ax-icon>\n <ax-icon\n [class.ax-text-primary]=\"getSortDirection(item) === 'desc'\"\n class=\"fa-solid fa-arrow-down-long ax-text-neutral-400\"\n ></ax-icon>\n </ax-button>\n </div>\n }\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
4239
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPSpreadsheetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4240
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPSpreadsheetComponent, isStandalone: true, selector: "axp-spreadsheet", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rowMode: { classPropertyName: "rowMode", publicName: "rowMode", isSignal: true, isRequired: false, transformFunction: null }, rowsInput: { classPropertyName: "rowsInput", publicName: "rowsInput", isSignal: true, isRequired: false, transformFunction: null }, rowsModel: { classPropertyName: "rowsModel", publicName: "rowsModel", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, emptyCellPlaceholder: { classPropertyName: "emptyCellPlaceholder", publicName: "emptyCellPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, rowTitlePath: { classPropertyName: "rowTitlePath", publicName: "rowTitlePath", isSignal: true, isRequired: false, transformFunction: null }, rowDescriptionPath: { classPropertyName: "rowDescriptionPath", publicName: "rowDescriptionPath", isSignal: true, isRequired: false, transformFunction: null }, allowAddRows: { classPropertyName: "allowAddRows", publicName: "allowAddRows", isSignal: true, isRequired: false, transformFunction: null }, allowRemoveRows: { classPropertyName: "allowRemoveRows", publicName: "allowRemoveRows", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowsModel: "rowsModelChange", cellChange: "cellChange", rowChange: "rowChange", spreadsheetChange: "spreadsheetChange" }, host: { listeners: { "document:keydown": "handleKeyDown($event)" }, classAttribute: "axp-spreadsheet" }, ngImport: i0, template: "<!--\n #region ---- Spreadsheet Component Template ----\n-->\n<div class=\"__spreadsheet-container\" (click)=\"handleClickOutside($event)\">\n @if (isColumnsEmpty()) {\n <!-- Empty State: Columns are empty (regardless of rows) -->\n <div class=\"__empty-state\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-table-columns\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty-columns.title' | translate | async }}</div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty-columns.description' | translate | async }}\n </div>\n </div>\n } @else if (isEmpty()) {\n <!-- Empty State: Both columns and rows are empty -->\n <div class=\"__empty-state\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-table\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty.title' | translate | async }}</div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty.description' | translate | async }}</div>\n </div>\n } @else if (isRowsEmpty()) {\n <!-- Empty State: Only rows are empty - Show columns -->\n <div class=\"__table-wrapper\">\n <table class=\"__table\">\n <!-- Header Row -->\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <!-- Corner cell (title) -->\n <th class=\"__corner-cell\">\n @if (title()) {\n <div class=\"__corner-title\">{{ title() | translate | async }}</div>\n }\n @if (rowMode() === 'dynamic' && allowAddRows() && !readonly()) {\n <div class=\"__corner-actions\">\n <ax-button look=\"blank\" color=\"primary\" (onClick)=\"handleAddRow()\"\n [attr.aria-label]=\"'Add Row'\">\n <ax-icon icon=\"far fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </th>\n\n <!-- Column headers -->\n @for (column of columns(); track column.name) {\n <th class=\"__column-header\" [style.width]=\"column.width\">\n <div class=\"__header-content\">\n <div class=\"__header-title\">{{ column.title | translate | async }}</div>\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <!-- Empty State Row -->\n <tbody class=\"__tbody\">\n <tr class=\"__row __row--empty\">\n <td class=\"__row-header\" [attr.colspan]=\"columns().length + 1\">\n <div class=\"__empty-state-inline\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-list\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty-rows.title' | translate | async\n }}\n </div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty-rows.description' |\n translate |\n async }}</div>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n } @else {\n <!-- Full Spreadsheet: Both columns and rows are available -->\n <div class=\"__table-wrapper\">\n <table class=\"__table\">\n <!-- Header Row -->\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <!-- Corner cell (title) -->\n <th class=\"__corner-cell\">\n @if (title()) {\n <div class=\"__corner-title\">{{ title() | translate | async }}</div>\n }\n @if (rowMode() === 'dynamic' && allowAddRows() && !readonly()) {\n <div class=\"__corner-actions\">\n <ax-button look=\"blank\" color=\"primary\" (onClick)=\"handleAddRow()\"\n [attr.aria-label]=\"'Add Row'\">\n <ax-icon icon=\"far fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </th>\n\n <!-- Column headers -->\n @for (column of columns(); track column.name) {\n <th class=\"__column-header\" [style.width]=\"column.width\">\n <div class=\"__header-content\">\n <div class=\"__header-title\">{{ column.title | translate | async }}</div>\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <!-- Body Rows -->\n <tbody class=\"__tbody\">\n <axp-widgets-container [context]=\"spreadsheetContext()\"\n (onContextChanged)=\"handleSpreadsheetContextChange($event)\">\n @for (rowItem of rowsWithIds(); track rowItem.rowId; let rowIndex = $index) {\n <tr class=\"__row\" [class.__row--odd]=\"rowIndex % 2 === 1\">\n <!-- Row header -->\n <td class=\"__row-header\">\n <div class=\"__header-content\">\n @if (rowTitlePath()) {\n <div class=\"__header-title\">{{ getRowTitle(rowItem.row, rowTitlePath()!) }}</div>\n }\n @if (rowDescriptionPath()) {\n <div class=\"__header-description\">{{ getRowDescription(rowItem.row,\n rowDescriptionPath()!) }}</div>\n }\n </div>\n @if (allowRemoveRows() && !readonly()) {\n <div class=\"__header-actions ax-xs ax-opacity-30 hover:ax-opacity-100\">\n <ax-button look=\"blank\" color=\"danger\"\n (onClick)=\"handleRemoveRow(rowItem.rowId, $event)\" [attr.aria-label]=\"'Remove Row'\">\n <ax-icon icon=\"far fa-times\"></ax-icon>\n </ax-button>\n </div>\n }\n </td>\n\n <!-- Spreadsheet cells -->\n @for (column of columns(); track column.name) {\n <td class=\"__cell\" [class.__cell--editing]=\"isCellEditing(rowItem.rowId, column.name)\"\n [class.__cell--readonly]=\"isColumnReadonly(column)\"\n (click)=\"$event.stopPropagation(); handleCellClick(rowItem.rowId, column.name, $event)\">\n @if (isCellEditing(rowItem.rowId, column.name) && !isColumnReadonly(column)) {\n <!-- Edit mode: Show widget in edit mode -->\n <div class=\"__cell-editor\" (blur)=\"handleCellBlur(rowItem.rowId, column.name)\"\n tabindex=\"-1\">\n <ng-container axp-widget-renderer [node]=\"getCellWidgetNode(column, rowIndex)\"\n [mode]=\"'edit'\"></ng-container>\n </div>\n <!-- Floating toolbar for commit/cancel -->\n <div class=\"__cell-toolbar ax-xs\" (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\" (focusin)=\"$event.stopPropagation()\">\n <ax-button look=\"blank\" color=\"success\" (onClick)=\"commitCellEdit()\"\n [attr.aria-label]=\"'Commit'\">\n <ax-icon icon=\"far fa-check\"></ax-icon>\n </ax-button>\n <ax-button look=\"blank\" color=\"danger\" (onClick)=\"cancelCellEdit()\"\n [attr.aria-label]=\"'Cancel'\">\n <ax-icon icon=\"far fa-times\"></ax-icon>\n </ax-button>\n </div>\n } @else {\n <!-- View mode: Show widget in view mode or placeholder -->\n <div class=\"__cell-value\">\n @if (getCellValue(rowIndex, column.name) !== null &&\n getCellValue(rowIndex, column.name) !== undefined) {\n <ng-container axp-widget-renderer [node]=\"getCellWidgetNode(column, rowIndex)\"\n [mode]=\"'view'\"></ng-container>\n } @else {\n <span class=\"__cell-placeholder\">{{ emptyCellPlaceholder() }}</span>\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </axp-widgets-container>\n </tbody>\n </table>\n </div>\n }\n</div>\n<!--\n #endregion\n-->", styles: [".axp-spreadsheet{display:flex;height:100%;width:100%;flex-direction:column}.axp-spreadsheet .__spreadsheet-container{position:relative;flex:1 1 0%;overflow:hidden;border-radius:.375rem;border-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-spreadsheet .__empty-state{display:flex;min-height:200px;flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center}.axp-spreadsheet .__empty-state .__empty-icon{margin-bottom:1rem}.axp-spreadsheet .__empty-state .__empty-icon i{font-size:2.25rem;line-height:2.5rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state .__empty-title{margin-bottom:.5rem;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(38 38 38 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state .__empty-description{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1.5rem;text-align:center}.axp-spreadsheet .__empty-state-inline .__empty-icon{margin-bottom:.75rem}.axp-spreadsheet .__empty-state-inline .__empty-icon i{font-size:1.5rem;line-height:2rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline .__empty-title{margin-bottom:.25rem;font-size:1rem;line-height:1.5rem;font-weight:600;--tw-text-opacity: 1;color:rgb(38 38 38 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline .__empty-description{font-size:.75rem;line-height:1rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__table-wrapper{height:100%;width:100%;overflow-x:auto;overflow-y:auto;-webkit-overflow-scrolling:touch}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar{height:8px;width:8px}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-track{--tw-bg-opacity: 1;background-color:rgb(245 245 245 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-thumb{border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgb(163 163 163 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(115 115 115 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table{min-width:100%;border-collapse:separate;--tw-border-spacing-x: 0px;--tw-border-spacing-y: 0px;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.axp-spreadsheet .__table .__thead{position:sticky;top:0;z-index:2}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell{position:relative;position:sticky;inset-inline-start:0px;width:200px;min-width:200px;border-width:1px;border-bottom-width:1px;padding:.5rem .75rem;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:3}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell .__corner-title{text-align:center;font-size:.875rem;line-height:1.25rem;font-weight:600}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell .__corner-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}@media (max-width: 768px){.axp-spreadsheet .__table .__thead .__header-row .__corner-cell{width:200px;min-width:200px;padding:.375rem .5rem}}.axp-spreadsheet .__table .__thead .__header-row .__column-header{position:sticky;top:0;width:200px;min-width:200px;white-space:nowrap;border-bottom-width:1px;padding:.5rem .75rem;text-align:center;font-weight:600;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:2}.axp-spreadsheet .__table .__thead .__header-row .__column-header.__column-header--empty{width:300px;min-width:300px;white-space:normal}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content{display:flex;flex-direction:column;gap:.25rem}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-title{font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-description{white-space:normal;overflow-wrap:break-word;font-size:.75rem;line-height:1rem;font-weight:400;opacity:.75}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}@media (max-width: 768px){.axp-spreadsheet .__table .__thead .__header-row .__column-header{width:120px;min-width:120px;padding:.375rem .5rem}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-title,.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-description{font-size:.75rem;line-height:1rem}}.axp-spreadsheet .__table .__tbody .__row.__row--empty .__row-header{text-align:center}.axp-spreadsheet .__table .__tbody .__row .__row-header{position:relative;position:sticky;inset-inline-start:0px;width:200px;min-width:200px;border-width:1px;border-bottom-width:1px;padding:.5rem .75rem;vertical-align:top;font-weight:600;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:2}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content{display:flex;flex-direction:column;gap:.25rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-title{font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-description{font-size:.75rem;line-height:1rem;font-weight:400;opacity:.75}@media (max-width: 768px){.axp-spreadsheet .__table .__tbody .__row .__row-header{width:200px;min-width:200px;padding:.375rem .5rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-title,.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-description{font-size:.75rem;line-height:1rem}}.axp-spreadsheet .__table .__tbody .__row .__cell{position:relative;min-height:40px;width:200px;min-width:200px;cursor:pointer;border-bottom-width:1px;padding:.5rem .75rem;text-align:center;vertical-align:middle}.axp-spreadsheet .__table .__tbody .__row .__cell:before{content:\"\";pointer-events:none;position:absolute;inset:0;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1));--tw-bg-opacity: .05;opacity:0;transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);animation-duration:.15s;animation-timing-function:cubic-bezier(.4,0,.2,1)}.axp-spreadsheet .__table .__tbody .__row .__cell:hover:not(.__cell--readonly):not(.__cell--editing):before{opacity:1}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--readonly{cursor:default}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--readonly:hover:before{opacity:0}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--empty{cursor:default}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--empty:hover:before{opacity:0}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing{position:relative;border-width:2px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1));background-color:rgba(var(--ax-sys-color-primary-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .1;padding:1px}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing .__cell-editor{width:100%;padding:.5rem .75rem}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing .__cell-toolbar{position:absolute;bottom:-35px;inset-inline-end:0px;display:flex;gap:.125rem;white-space:nowrap;border-radius:.375rem;border-width:1px;padding:.25rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:100}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-value{display:flex;min-height:1.25rem;align-items:center;justify-content:center;overflow-wrap:break-word;padding:.125rem;font-size:.875rem;line-height:1.25rem}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-placeholder{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-editor{display:flex;width:100%;align-items:center;justify-content:center}@media (max-width: 768px){.axp-spreadsheet .__table .__tbody .__row .__cell{width:120px;min-width:120px;padding:.375rem .5rem}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-value{font-size:.75rem;line-height:1rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i6$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i6$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
4515
4241
|
}
|
|
4516
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type:
|
|
4242
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPSpreadsheetComponent, decorators: [{
|
|
4517
4243
|
type: Component,
|
|
4518
|
-
args: [{ selector: 'axp-
|
|
4519
|
-
CdkDropList,
|
|
4520
|
-
CdkDrag,
|
|
4521
|
-
CdkDragHandle,
|
|
4522
|
-
AXTabsModule,
|
|
4523
|
-
AXTranslationModule,
|
|
4244
|
+
args: [{ selector: 'axp-spreadsheet', standalone: true, imports: [
|
|
4524
4245
|
CommonModule,
|
|
4525
|
-
|
|
4246
|
+
FormsModule,
|
|
4247
|
+
AXTranslationModule,
|
|
4526
4248
|
AXButtonModule,
|
|
4527
|
-
|
|
4528
|
-
|
|
4249
|
+
AXDecoratorModule,
|
|
4250
|
+
AXPWidgetCoreModule,
|
|
4251
|
+
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
4252
|
+
class: 'axp-spreadsheet',
|
|
4253
|
+
}, template: "<!--\n #region ---- Spreadsheet Component Template ----\n-->\n<div class=\"__spreadsheet-container\" (click)=\"handleClickOutside($event)\">\n @if (isColumnsEmpty()) {\n <!-- Empty State: Columns are empty (regardless of rows) -->\n <div class=\"__empty-state\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-table-columns\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty-columns.title' | translate | async }}</div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty-columns.description' | translate | async }}\n </div>\n </div>\n } @else if (isEmpty()) {\n <!-- Empty State: Both columns and rows are empty -->\n <div class=\"__empty-state\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-table\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty.title' | translate | async }}</div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty.description' | translate | async }}</div>\n </div>\n } @else if (isRowsEmpty()) {\n <!-- Empty State: Only rows are empty - Show columns -->\n <div class=\"__table-wrapper\">\n <table class=\"__table\">\n <!-- Header Row -->\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <!-- Corner cell (title) -->\n <th class=\"__corner-cell\">\n @if (title()) {\n <div class=\"__corner-title\">{{ title() | translate | async }}</div>\n }\n @if (rowMode() === 'dynamic' && allowAddRows() && !readonly()) {\n <div class=\"__corner-actions\">\n <ax-button look=\"blank\" color=\"primary\" (onClick)=\"handleAddRow()\"\n [attr.aria-label]=\"'Add Row'\">\n <ax-icon icon=\"far fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </th>\n\n <!-- Column headers -->\n @for (column of columns(); track column.name) {\n <th class=\"__column-header\" [style.width]=\"column.width\">\n <div class=\"__header-content\">\n <div class=\"__header-title\">{{ column.title | translate | async }}</div>\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <!-- Empty State Row -->\n <tbody class=\"__tbody\">\n <tr class=\"__row __row--empty\">\n <td class=\"__row-header\" [attr.colspan]=\"columns().length + 1\">\n <div class=\"__empty-state-inline\">\n <div class=\"__empty-icon\">\n <i class=\"fa-light fa-list\"></i>\n </div>\n <div class=\"__empty-title\">{{ '@general:state-message.empty-rows.title' | translate | async\n }}\n </div>\n <div class=\"__empty-description\">{{ '@general:state-message.empty-rows.description' |\n translate |\n async }}</div>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n } @else {\n <!-- Full Spreadsheet: Both columns and rows are available -->\n <div class=\"__table-wrapper\">\n <table class=\"__table\">\n <!-- Header Row -->\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <!-- Corner cell (title) -->\n <th class=\"__corner-cell\">\n @if (title()) {\n <div class=\"__corner-title\">{{ title() | translate | async }}</div>\n }\n @if (rowMode() === 'dynamic' && allowAddRows() && !readonly()) {\n <div class=\"__corner-actions\">\n <ax-button look=\"blank\" color=\"primary\" (onClick)=\"handleAddRow()\"\n [attr.aria-label]=\"'Add Row'\">\n <ax-icon icon=\"far fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </th>\n\n <!-- Column headers -->\n @for (column of columns(); track column.name) {\n <th class=\"__column-header\" [style.width]=\"column.width\">\n <div class=\"__header-content\">\n <div class=\"__header-title\">{{ column.title | translate | async }}</div>\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <!-- Body Rows -->\n <tbody class=\"__tbody\">\n <axp-widgets-container [context]=\"spreadsheetContext()\"\n (onContextChanged)=\"handleSpreadsheetContextChange($event)\">\n @for (rowItem of rowsWithIds(); track rowItem.rowId; let rowIndex = $index) {\n <tr class=\"__row\" [class.__row--odd]=\"rowIndex % 2 === 1\">\n <!-- Row header -->\n <td class=\"__row-header\">\n <div class=\"__header-content\">\n @if (rowTitlePath()) {\n <div class=\"__header-title\">{{ getRowTitle(rowItem.row, rowTitlePath()!) }}</div>\n }\n @if (rowDescriptionPath()) {\n <div class=\"__header-description\">{{ getRowDescription(rowItem.row,\n rowDescriptionPath()!) }}</div>\n }\n </div>\n @if (allowRemoveRows() && !readonly()) {\n <div class=\"__header-actions ax-xs ax-opacity-30 hover:ax-opacity-100\">\n <ax-button look=\"blank\" color=\"danger\"\n (onClick)=\"handleRemoveRow(rowItem.rowId, $event)\" [attr.aria-label]=\"'Remove Row'\">\n <ax-icon icon=\"far fa-times\"></ax-icon>\n </ax-button>\n </div>\n }\n </td>\n\n <!-- Spreadsheet cells -->\n @for (column of columns(); track column.name) {\n <td class=\"__cell\" [class.__cell--editing]=\"isCellEditing(rowItem.rowId, column.name)\"\n [class.__cell--readonly]=\"isColumnReadonly(column)\"\n (click)=\"$event.stopPropagation(); handleCellClick(rowItem.rowId, column.name, $event)\">\n @if (isCellEditing(rowItem.rowId, column.name) && !isColumnReadonly(column)) {\n <!-- Edit mode: Show widget in edit mode -->\n <div class=\"__cell-editor\" (blur)=\"handleCellBlur(rowItem.rowId, column.name)\"\n tabindex=\"-1\">\n <ng-container axp-widget-renderer [node]=\"getCellWidgetNode(column, rowIndex)\"\n [mode]=\"'edit'\"></ng-container>\n </div>\n <!-- Floating toolbar for commit/cancel -->\n <div class=\"__cell-toolbar ax-xs\" (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation()\"\n (mouseup)=\"$event.stopPropagation()\" (focusin)=\"$event.stopPropagation()\">\n <ax-button look=\"blank\" color=\"success\" (onClick)=\"commitCellEdit()\"\n [attr.aria-label]=\"'Commit'\">\n <ax-icon icon=\"far fa-check\"></ax-icon>\n </ax-button>\n <ax-button look=\"blank\" color=\"danger\" (onClick)=\"cancelCellEdit()\"\n [attr.aria-label]=\"'Cancel'\">\n <ax-icon icon=\"far fa-times\"></ax-icon>\n </ax-button>\n </div>\n } @else {\n <!-- View mode: Show widget in view mode or placeholder -->\n <div class=\"__cell-value\">\n @if (getCellValue(rowIndex, column.name) !== null &&\n getCellValue(rowIndex, column.name) !== undefined) {\n <ng-container axp-widget-renderer [node]=\"getCellWidgetNode(column, rowIndex)\"\n [mode]=\"'view'\"></ng-container>\n } @else {\n <span class=\"__cell-placeholder\">{{ emptyCellPlaceholder() }}</span>\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </axp-widgets-container>\n </tbody>\n </table>\n </div>\n }\n</div>\n<!--\n #endregion\n-->", styles: [".axp-spreadsheet{display:flex;height:100%;width:100%;flex-direction:column}.axp-spreadsheet .__spreadsheet-container{position:relative;flex:1 1 0%;overflow:hidden;border-radius:.375rem;border-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-spreadsheet .__empty-state{display:flex;min-height:200px;flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center}.axp-spreadsheet .__empty-state .__empty-icon{margin-bottom:1rem}.axp-spreadsheet .__empty-state .__empty-icon i{font-size:2.25rem;line-height:2.5rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state .__empty-title{margin-bottom:.5rem;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(38 38 38 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state .__empty-description{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1.5rem;text-align:center}.axp-spreadsheet .__empty-state-inline .__empty-icon{margin-bottom:.75rem}.axp-spreadsheet .__empty-state-inline .__empty-icon i{font-size:1.5rem;line-height:2rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline .__empty-title{margin-bottom:.25rem;font-size:1rem;line-height:1.5rem;font-weight:600;--tw-text-opacity: 1;color:rgb(38 38 38 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__empty-state-inline .__empty-description{font-size:.75rem;line-height:1rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__table-wrapper{height:100%;width:100%;overflow-x:auto;overflow-y:auto;-webkit-overflow-scrolling:touch}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar{height:8px;width:8px}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-track{--tw-bg-opacity: 1;background-color:rgb(245 245 245 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-thumb{border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgb(163 163 163 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table-wrapper::-webkit-scrollbar-thumb:hover{--tw-bg-opacity: 1;background-color:rgb(115 115 115 / var(--tw-bg-opacity, 1))}.axp-spreadsheet .__table{min-width:100%;border-collapse:separate;--tw-border-spacing-x: 0px;--tw-border-spacing-y: 0px;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.axp-spreadsheet .__table .__thead{position:sticky;top:0;z-index:2}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell{position:relative;position:sticky;inset-inline-start:0px;width:200px;min-width:200px;border-width:1px;border-bottom-width:1px;padding:.5rem .75rem;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:3}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell .__corner-title{text-align:center;font-size:.875rem;line-height:1.25rem;font-weight:600}.axp-spreadsheet .__table .__thead .__header-row .__corner-cell .__corner-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}@media (max-width: 768px){.axp-spreadsheet .__table .__thead .__header-row .__corner-cell{width:200px;min-width:200px;padding:.375rem .5rem}}.axp-spreadsheet .__table .__thead .__header-row .__column-header{position:sticky;top:0;width:200px;min-width:200px;white-space:nowrap;border-bottom-width:1px;padding:.5rem .75rem;text-align:center;font-weight:600;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:2}.axp-spreadsheet .__table .__thead .__header-row .__column-header.__column-header--empty{width:300px;min-width:300px;white-space:normal}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content{display:flex;flex-direction:column;gap:.25rem}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-title{font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-description{white-space:normal;overflow-wrap:break-word;font-size:.75rem;line-height:1rem;font-weight:400;opacity:.75}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}@media (max-width: 768px){.axp-spreadsheet .__table .__thead .__header-row .__column-header{width:120px;min-width:120px;padding:.375rem .5rem}.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-title,.axp-spreadsheet .__table .__thead .__header-row .__column-header .__header-content .__header-description{font-size:.75rem;line-height:1rem}}.axp-spreadsheet .__table .__tbody .__row.__row--empty .__row-header{text-align:center}.axp-spreadsheet .__table .__tbody .__row .__row-header{position:relative;position:sticky;inset-inline-start:0px;width:200px;min-width:200px;border-width:1px;border-bottom-width:1px;padding:.5rem .75rem;vertical-align:top;font-weight:600;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:2}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-actions{position:absolute;top:.25rem;inset-inline-end:.25rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content{display:flex;flex-direction:column;gap:.25rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-title{font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-description{font-size:.75rem;line-height:1rem;font-weight:400;opacity:.75}@media (max-width: 768px){.axp-spreadsheet .__table .__tbody .__row .__row-header{width:200px;min-width:200px;padding:.375rem .5rem}.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-title,.axp-spreadsheet .__table .__tbody .__row .__row-header .__header-content .__header-description{font-size:.75rem;line-height:1rem}}.axp-spreadsheet .__table .__tbody .__row .__cell{position:relative;min-height:40px;width:200px;min-width:200px;cursor:pointer;border-bottom-width:1px;padding:.5rem .75rem;text-align:center;vertical-align:middle}.axp-spreadsheet .__table .__tbody .__row .__cell:before{content:\"\";pointer-events:none;position:absolute;inset:0;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1));--tw-bg-opacity: .05;opacity:0;transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1);animation-duration:.15s;animation-timing-function:cubic-bezier(.4,0,.2,1)}.axp-spreadsheet .__table .__tbody .__row .__cell:hover:not(.__cell--readonly):not(.__cell--editing):before{opacity:1}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--readonly{cursor:default}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--readonly:hover:before{opacity:0}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--empty{cursor:default}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--empty:hover:before{opacity:0}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing{position:relative;border-width:2px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1));background-color:rgba(var(--ax-sys-color-primary-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .1;padding:1px}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing .__cell-editor{width:100%;padding:.5rem .75rem}.axp-spreadsheet .__table .__tbody .__row .__cell.__cell--editing .__cell-toolbar{position:absolute;bottom:-35px;inset-inline-end:0px;display:flex;gap:.125rem;white-space:nowrap;border-radius:.375rem;border-width:1px;padding:.25rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));z-index:100}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-value{display:flex;min-height:1.25rem;align-items:center;justify-content:center;overflow-wrap:break-word;padding:.125rem;font-size:.875rem;line-height:1.25rem}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-placeholder{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-editor{display:flex;width:100%;align-items:center;justify-content:center}@media (max-width: 768px){.axp-spreadsheet .__table .__tbody .__row .__cell{width:120px;min-width:120px;padding:.375rem .5rem}.axp-spreadsheet .__table .__tbody .__row .__cell .__cell-value{font-size:.75rem;line-height:1rem}}\n"] }]
|
|
4254
|
+
}], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rowMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowMode", required: false }] }], rowsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsInput", required: false }] }], rowsModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsModel", required: false }] }, { type: i0.Output, args: ["rowsModelChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], emptyCellPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyCellPlaceholder", required: false }] }], rowTitlePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowTitlePath", required: false }] }], rowDescriptionPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowDescriptionPath", required: false }] }], allowAddRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowAddRows", required: false }] }], allowRemoveRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowRemoveRows", required: false }] }], cellChange: [{ type: i0.Output, args: ["cellChange"] }], rowChange: [{ type: i0.Output, args: ["rowChange"] }], spreadsheetChange: [{ type: i0.Output, args: ["spreadsheetChange"] }], handleKeyDown: [{
|
|
4255
|
+
type: HostListener,
|
|
4256
|
+
args: ['document:keydown', ['$event']]
|
|
4257
|
+
}] } });
|
|
4258
|
+
|
|
4259
|
+
//#endregion
|
|
4529
4260
|
|
|
4530
4261
|
//#region ---- Imports ----
|
|
4531
4262
|
//#endregion
|
|
@@ -6282,5 +6013,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6282
6013
|
* Generated bundle index. Do not edit.
|
|
6283
6014
|
*/
|
|
6284
6015
|
|
|
6285
|
-
export { AXPActivityLogComponent, AXPCategoryTreeComponent, AXPColorPalettePickerComponent, AXPColumnItemListComponent, AXPCompareViewComponent,
|
|
6016
|
+
export { AXPActivityLogComponent, AXPCategoryTreeComponent, AXPColorPalettePickerComponent, AXPColumnItemListComponent, AXPCompareViewComponent, AXPDataSelectorComponent, AXPDataSelectorService, AXPDragDropListComponent, AXPImageEditorPopupComponent, AXPImageEditorService, AXPLogoComponent, AXPMenuBadgeHelper, AXPMenuCustomizerComponent, AXPMenuCustomizerService, AXPPropertyViewerComponent, AXPPropertyViewerPopupComponent, AXPPropertyViewerService, AXPQueryColumnsComponent, AXPQueryFiltersComponent, AXPQuerySortsComponent, AXPQueryViewsComponent, AXPSpreadsheetComponent, AXPStateMessageComponent, AXPStopwatchComponent, AXPTableColumnsEditorComponent, AXPTableColumnsEditorPopupComponent, AXPTableColumnsEditorService, AXPTableDataEditorComponent, AXPTableDataEditorPopupComponent, AXPTableDataEditorService, AXPTaskBadgeDirective, AXPTaskBadgeProvider, AXPTaskBadgeService, AXPTemplateViewerComponent, AXPTemplateViewerService, AXPThemeLayoutActionsComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutContainerComponent, AXPThemeLayoutEndSideComponent, AXPThemeLayoutFooterComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutListComponent, AXPThemeLayoutListItemComponent, AXPThemeLayoutListItemsGroupComponent, AXPThemeLayoutPageHeaderComponent, AXPThemeLayoutPagePrimaryActionsComponent, AXPThemeLayoutPageSecondaryActionsComponent, AXPThemeLayoutSectionComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutToolbarComponent, AXPUserAvatarComponent, AXPUserAvatarService, AXPWidgetFieldConfiguratorComponent, AXPWidgetItemComponent, AXPWidgetPropertyViewerComponent, AXPWidgetPropertyViewerPopupComponent, AXPWidgetPropertyViewerService, AXP_MENU_CUSTOMIZER_SERVICE, AXP_TASK_BADGE_PROVIDERS, AXP_USER_AVATAR_PROVIDER, buildTableColumnsEditorLayout };
|
|
6286
6017
|
//# sourceMappingURL=acorex-platform-layout-components.mjs.map
|