@acorex/platform 21.0.0-next.70 → 21.0.0-next.72
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/fesm2022/acorex-platform-auth.mjs +10 -2
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/{acorex-platform-common-common-settings.provider-Bi1RYif5.mjs → acorex-platform-common-common-settings.provider-Ytey9uhY.mjs} +15 -1
- package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +3798 -1674
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +1362 -97
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +446 -44
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +149 -109
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +199 -126
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-entity-attachments-page.component-D8iQnT-R.mjs → acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs} +6 -1
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-entity.mjs +823 -594
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +845 -218
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +122 -33
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-BcpRkpJp.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs} +2 -2
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-BcpRkpJp.mjs.map → acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-DQtK4lxl.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs} +2 -2
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-DQtK4lxl.mjs.map → acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs.map} +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +312 -676
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default-error-401.component-B1nsdpTY.mjs +48 -0
- package/fesm2022/acorex-platform-themes-default-error-401.component-B1nsdpTY.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-D4UvRe8u.mjs +42 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-D4UvRe8u.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +89 -46
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-shared.mjs +50 -30
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-auth.d.ts +2 -0
- package/types/acorex-platform-common.d.ts +899 -256
- package/types/acorex-platform-core.d.ts +394 -60
- package/types/acorex-platform-layout-builder.d.ts +78 -13
- package/types/acorex-platform-layout-components.d.ts +30 -24
- package/types/acorex-platform-layout-entity.d.ts +93 -44
- package/types/acorex-platform-layout-views.d.ts +162 -42
- package/types/acorex-platform-layout-widget-core.d.ts +60 -33
- package/types/acorex-platform-layout-widgets.d.ts +48 -20
- package/types/acorex-platform-themes-default.d.ts +38 -8
- package/types/acorex-platform-themes-shared.d.ts +6 -0
- package/types/acorex-platform-workflow.d.ts +1 -1
- package/fesm2022/acorex-platform-common-common-settings.provider-Bi1RYif5.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-D8iQnT-R.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs +0 -31
- package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs +0 -25
- package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs.map +0 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import * as i5 from '@angular/common';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { CommonModule, DOCUMENT } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { Injectable, inject, input, model, signal, computed, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, Output } from '@angular/core';
|
|
4
|
+
import { Injectable, inject, input, model, signal, computed, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, ElementRef, DestroyRef, Output } from '@angular/core';
|
|
5
5
|
import { provideCommandSetups, AXPCommandService } from '@acorex/platform/runtime';
|
|
6
6
|
import { AXPopupService } from '@acorex/components/popup';
|
|
7
7
|
import * as i4 from '@acorex/platform/core';
|
|
8
|
-
import { AXPHookService, AXPExpressionEvaluatorService, AXPComponentSlotModule, AXPContextStore } from '@acorex/platform/core';
|
|
8
|
+
import { normalizeKeyboardShortcuts, AXPHookService, findOverlayContainerAncestor, getNestedVisibleOverlayPanes, getTopVisibleOverlayContainer, AXPExpressionEvaluatorService, AXPComponentSlotModule, AXPContextStore } from '@acorex/platform/core';
|
|
9
9
|
import * as i1 from '@acorex/platform/layout/widget-core';
|
|
10
10
|
import { AXPWidgetSerializationHelper, AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule, AXPWidgetRegistryService } from '@acorex/platform/layout/widget-core';
|
|
11
11
|
import { cloneDeep, isNil, set, isEqual, merge } from 'lodash-es';
|
|
12
12
|
import * as i2 from '@acorex/components/form';
|
|
13
13
|
import { AXFormComponent, AXFormModule } from '@acorex/components/form';
|
|
14
14
|
import { Subject, debounceTime, distinctUntilChanged, startWith } from 'rxjs';
|
|
15
|
+
import { AXOverlayService } from '@acorex/cdk/overlay';
|
|
15
16
|
import * as i1$1 from '@acorex/components/button';
|
|
16
17
|
import { AXButtonModule } from '@acorex/components/button';
|
|
17
18
|
import * as i2$1 from '@acorex/components/decorators';
|
|
@@ -20,9 +21,156 @@ import * as i3 from '@acorex/components/loading';
|
|
|
20
21
|
import { AXLoadingModule } from '@acorex/components/loading';
|
|
21
22
|
import { AXBasePageComponent } from '@acorex/components/page';
|
|
22
23
|
import * as i6 from '@acorex/core/translation';
|
|
23
|
-
import {
|
|
24
|
+
import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
|
|
25
|
+
import { AXPUnsavedChangesConfirmService } from '@acorex/platform/common';
|
|
24
26
|
import { AXP_ENTITY_DEFINITION_CRUD_SERVICE } from '@acorex/platform/domain';
|
|
25
27
|
|
|
28
|
+
//#region ---- Dialog Action Shortcut Utilities ----
|
|
29
|
+
const DEFAULT_CANCEL_DIALOG_ACTION_SHORTCUTS = ['Esc'];
|
|
30
|
+
const DEFAULT_SUBMIT_DIALOG_ACTION_SHORTCUTS = ['Enter', 'ctrl+s'];
|
|
31
|
+
const PRIMARY_DIALOG_ACTION_COMMANDS = new Set(['submit', 'create', 'entity-form-done']);
|
|
32
|
+
/**
|
|
33
|
+
* Parses a shortcut string such as `Enter`, `Escape`, or `ctrl+shift+s`.
|
|
34
|
+
*/
|
|
35
|
+
function parseDialogActionShortcut(shortcut) {
|
|
36
|
+
const parts = shortcut
|
|
37
|
+
.trim()
|
|
38
|
+
.toLowerCase()
|
|
39
|
+
.split('+')
|
|
40
|
+
.map((part) => part.trim())
|
|
41
|
+
.filter(Boolean);
|
|
42
|
+
const key = normalizeShortcutToken(parts.pop() ?? '');
|
|
43
|
+
return {
|
|
44
|
+
ctrl: parts.includes('ctrl') || parts.includes('control'),
|
|
45
|
+
shift: parts.includes('shift'),
|
|
46
|
+
alt: parts.includes('alt') || parts.includes('option'),
|
|
47
|
+
meta: parts.includes('meta') || parts.includes('cmd') || parts.includes('command'),
|
|
48
|
+
key,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns true when the keyboard event matches the given shortcut definition.
|
|
53
|
+
*/
|
|
54
|
+
function matchesDialogActionShortcut(event, shortcut) {
|
|
55
|
+
const parsed = parseDialogActionShortcut(shortcut);
|
|
56
|
+
if (parsed.ctrl !== event.ctrlKey) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (parsed.shift !== event.shiftKey) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (parsed.alt !== event.altKey) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if (parsed.meta !== event.metaKey) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return normalizeShortcutKey(event) === normalizeShortcutToken(parsed.key);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolves footer action shortcuts: defaults when omitted, merge when extras are provided, none when `[]`.
|
|
72
|
+
*/
|
|
73
|
+
function resolveDialogActionShortcuts(defaults, overrides) {
|
|
74
|
+
if (overrides !== undefined) {
|
|
75
|
+
if (overrides.length === 0) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
return flattenDialogActionShortcutChords([...defaults, ...overrides]);
|
|
79
|
+
}
|
|
80
|
+
return flattenDialogActionShortcutChords(defaults);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Applies built-in footer shortcuts when actions are declared without `shortcuts`
|
|
84
|
+
* (e.g. workflow `show-layout-popup` raw action config).
|
|
85
|
+
*/
|
|
86
|
+
function resolveConfiguredFooterActionShortcuts(command, explicit) {
|
|
87
|
+
if (explicit !== undefined) {
|
|
88
|
+
return resolveDialogActionShortcuts([], explicit);
|
|
89
|
+
}
|
|
90
|
+
if (command === 'cancel') {
|
|
91
|
+
return resolveDialogActionShortcuts(DEFAULT_CANCEL_DIALOG_ACTION_SHORTCUTS, undefined);
|
|
92
|
+
}
|
|
93
|
+
if (command && PRIMARY_DIALOG_ACTION_COMMANDS.has(command)) {
|
|
94
|
+
return resolveDialogActionShortcuts(DEFAULT_SUBMIT_DIALOG_ACTION_SHORTCUTS, undefined);
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
function flattenDialogActionShortcutChords(shortcuts) {
|
|
99
|
+
const chords = normalizeKeyboardShortcuts(shortcuts).flatMap((shortcut) => shortcut.keys);
|
|
100
|
+
const deduped = dedupeDialogActionShortcuts(chords);
|
|
101
|
+
return deduped.length ? deduped : undefined;
|
|
102
|
+
}
|
|
103
|
+
function dedupeDialogActionShortcuts(shortcuts) {
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
const result = [];
|
|
106
|
+
for (const shortcut of shortcuts) {
|
|
107
|
+
const token = normalizeShortcutToken(shortcut);
|
|
108
|
+
if (!token || seen.has(token)) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
seen.add(token);
|
|
112
|
+
result.push(shortcut.trim());
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
function normalizeShortcutToken(key) {
|
|
117
|
+
const normalized = key.trim().toLowerCase();
|
|
118
|
+
if (normalized === 'esc') {
|
|
119
|
+
return 'escape';
|
|
120
|
+
}
|
|
121
|
+
return normalized;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Whether a shortcut should fire given the current focus target.
|
|
125
|
+
* Enter without modifiers is suppressed in multiline / rich-text fields.
|
|
126
|
+
*/
|
|
127
|
+
function shouldTriggerDialogActionShortcut(event, shortcut) {
|
|
128
|
+
const parsed = parseDialogActionShortcut(shortcut);
|
|
129
|
+
const isPlainEnter = parsed.key === 'enter' && !parsed.ctrl && !parsed.shift && !parsed.alt && !parsed.meta;
|
|
130
|
+
if (!isPlainEnter) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
return !isKeyboardTargetMultilineEditable(event.target);
|
|
134
|
+
}
|
|
135
|
+
function normalizeShortcutKey(event) {
|
|
136
|
+
if (event.key === 'Enter') {
|
|
137
|
+
return 'enter';
|
|
138
|
+
}
|
|
139
|
+
if (event.key === 'Escape') {
|
|
140
|
+
return 'escape';
|
|
141
|
+
}
|
|
142
|
+
if (event.key === ' ') {
|
|
143
|
+
return 'space';
|
|
144
|
+
}
|
|
145
|
+
if (event.key.length === 1) {
|
|
146
|
+
return event.key.toLowerCase();
|
|
147
|
+
}
|
|
148
|
+
const codeMatch = event.code.match(/^Key([A-Z])$/);
|
|
149
|
+
if (codeMatch) {
|
|
150
|
+
return codeMatch[1].toLowerCase();
|
|
151
|
+
}
|
|
152
|
+
const digitMatch = event.code.match(/^Digit([0-9])$/);
|
|
153
|
+
if (digitMatch) {
|
|
154
|
+
return digitMatch[1];
|
|
155
|
+
}
|
|
156
|
+
return event.key.toLowerCase();
|
|
157
|
+
}
|
|
158
|
+
function isKeyboardTargetMultilineEditable(target) {
|
|
159
|
+
if (!(target instanceof HTMLElement)) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
if (target.isContentEditable) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
const textarea = target.closest('textarea');
|
|
166
|
+
if (textarea && !textarea.readOnly && !textarea.disabled) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
const richText = target.closest('[contenteditable="true"]');
|
|
170
|
+
return richText instanceof HTMLElement;
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
|
|
26
174
|
/** Fallback {@link AXPDialogRef} when the popup is dismissed without a footer action (e.g. header close). */
|
|
27
175
|
function createDismissedDialogRef(context = () => ({})) {
|
|
28
176
|
return {
|
|
@@ -347,6 +495,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
347
495
|
}]
|
|
348
496
|
}] });
|
|
349
497
|
|
|
498
|
+
//#region ---- Dialog Close Confirmation Utilities ----
|
|
499
|
+
function normalizeDialogCloseConfirmation(value) {
|
|
500
|
+
if (value === undefined || value === false) {
|
|
501
|
+
return undefined;
|
|
502
|
+
}
|
|
503
|
+
if (value === true) {
|
|
504
|
+
return { enabled: true };
|
|
505
|
+
}
|
|
506
|
+
if (value.enabled === false) {
|
|
507
|
+
return undefined;
|
|
508
|
+
}
|
|
509
|
+
return { enabled: true, ...value };
|
|
510
|
+
}
|
|
511
|
+
//#endregion
|
|
512
|
+
|
|
350
513
|
//#region ---- Inheritance Utilities ----
|
|
351
514
|
/**
|
|
352
515
|
* Resolves inherited properties from context and local values
|
|
@@ -1636,6 +1799,9 @@ class DialogContainerBuilder {
|
|
|
1636
1799
|
this.dialogState.dialogOptions.onAction = handler;
|
|
1637
1800
|
return this;
|
|
1638
1801
|
}
|
|
1802
|
+
confirmCloseWhenDirty(options) {
|
|
1803
|
+
return this.setOptions({ confirmCloseWhenDirty: options ?? true });
|
|
1804
|
+
}
|
|
1639
1805
|
addCustomAction(action) {
|
|
1640
1806
|
// Add to actions based on position
|
|
1641
1807
|
const position = action.position || 'suffix';
|
|
@@ -1699,6 +1865,7 @@ class DialogContainerBuilder {
|
|
|
1699
1865
|
};
|
|
1700
1866
|
await hookService.runAsync(AXP_LAYOUT_BUILDER_DIALOG_BEFORE_OPEN_HOOK_KEY, beforePayload);
|
|
1701
1867
|
}
|
|
1868
|
+
const confirmCloseWhenDirty = normalizeDialogCloseConfirmation(this.dialogState.dialogOptions?.confirmCloseWhenDirty);
|
|
1702
1869
|
// Create dialog configuration
|
|
1703
1870
|
const dialogConfig = {
|
|
1704
1871
|
title: this.dialogState.dialogOptions?.title || '',
|
|
@@ -1709,6 +1876,7 @@ class DialogContainerBuilder {
|
|
|
1709
1876
|
metadata: this.dialogState.dialogOptions.metadata,
|
|
1710
1877
|
actions: this.dialogState.actions,
|
|
1711
1878
|
onAction: this.dialogState.dialogOptions?.onAction,
|
|
1879
|
+
confirmCloseWhenDirty,
|
|
1712
1880
|
};
|
|
1713
1881
|
//
|
|
1714
1882
|
if (hookService) {
|
|
@@ -1912,7 +2080,7 @@ class ActionBuilder {
|
|
|
1912
2080
|
constructor(dialogBuilder) {
|
|
1913
2081
|
this.dialogBuilder = dialogBuilder;
|
|
1914
2082
|
}
|
|
1915
|
-
cancel(text) {
|
|
2083
|
+
cancel(text, options) {
|
|
1916
2084
|
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1917
2085
|
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1918
2086
|
}
|
|
@@ -1920,10 +2088,11 @@ class ActionBuilder {
|
|
|
1920
2088
|
title: text || '@general:actions.cancel.title',
|
|
1921
2089
|
color: 'default',
|
|
1922
2090
|
command: { name: 'cancel' },
|
|
2091
|
+
shortcuts: resolveDialogActionShortcuts(DEFAULT_CANCEL_DIALOG_ACTION_SHORTCUTS, options?.shortcuts),
|
|
1923
2092
|
});
|
|
1924
2093
|
return this;
|
|
1925
2094
|
}
|
|
1926
|
-
submit(text) {
|
|
2095
|
+
submit(text, options) {
|
|
1927
2096
|
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1928
2097
|
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1929
2098
|
}
|
|
@@ -1931,22 +2100,27 @@ class ActionBuilder {
|
|
|
1931
2100
|
title: text || '@general:actions.submit.title',
|
|
1932
2101
|
color: 'primary',
|
|
1933
2102
|
command: { name: 'submit', options: { validate: true } },
|
|
2103
|
+
shortcuts: resolveDialogActionShortcuts(DEFAULT_SUBMIT_DIALOG_ACTION_SHORTCUTS, options?.shortcuts),
|
|
1934
2104
|
});
|
|
1935
2105
|
return this;
|
|
1936
2106
|
}
|
|
1937
|
-
custom(action) {
|
|
1938
|
-
const
|
|
2107
|
+
custom(action, options) {
|
|
2108
|
+
const item = {
|
|
2109
|
+
...action,
|
|
2110
|
+
shortcuts: resolveDialogActionShortcuts(action.shortcuts ?? [], options?.shortcuts),
|
|
2111
|
+
};
|
|
2112
|
+
const position = item.position ?? 'suffix';
|
|
1939
2113
|
if (position === 'prefix') {
|
|
1940
2114
|
if (!this.dialogBuilder['dialogState'].actions.footer.prefix) {
|
|
1941
2115
|
this.dialogBuilder['dialogState'].actions.footer.prefix = [];
|
|
1942
2116
|
}
|
|
1943
|
-
this.dialogBuilder['dialogState'].actions.footer.prefix.push(
|
|
2117
|
+
this.dialogBuilder['dialogState'].actions.footer.prefix.push(item);
|
|
1944
2118
|
}
|
|
1945
2119
|
else {
|
|
1946
2120
|
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1947
2121
|
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1948
2122
|
}
|
|
1949
|
-
this.dialogBuilder['dialogState'].actions.footer.suffix.push(
|
|
2123
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix.push(item);
|
|
1950
2124
|
}
|
|
1951
2125
|
return this;
|
|
1952
2126
|
}
|
|
@@ -2386,6 +2560,91 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2386
2560
|
}]
|
|
2387
2561
|
}] });
|
|
2388
2562
|
|
|
2563
|
+
/**
|
|
2564
|
+
* Returns true when a nested overlay is open and Esc should close it first.
|
|
2565
|
+
* Returns false when only the dialog shell is on top.
|
|
2566
|
+
* Returns null when the Acorex overlay service does not expose open-state queries yet.
|
|
2567
|
+
*/
|
|
2568
|
+
function hasOpenNestedOverlayFromAcorexService(overlayService, dialogOverlay) {
|
|
2569
|
+
const service = overlayService;
|
|
2570
|
+
if (typeof service.hasOpenAnchoredOverlay === 'function') {
|
|
2571
|
+
if (!service.hasOpenAnchoredOverlay()) {
|
|
2572
|
+
return false;
|
|
2573
|
+
}
|
|
2574
|
+
if (typeof service.hasOverlayAbove === 'function') {
|
|
2575
|
+
return service.hasOverlayAbove(dialogOverlay);
|
|
2576
|
+
}
|
|
2577
|
+
return true;
|
|
2578
|
+
}
|
|
2579
|
+
if (typeof service.hasOverlayAbove === 'function') {
|
|
2580
|
+
return service.hasOverlayAbove(dialogOverlay);
|
|
2581
|
+
}
|
|
2582
|
+
return null;
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* DOM fallback until {@link AXOverlayService} exposes open-overlay queries.
|
|
2586
|
+
*
|
|
2587
|
+
* Dialog popups use a centered `.ax-overlay-container` without `.ax-overlay-pane`.
|
|
2588
|
+
* Widget popovers (select, datetime, dropdown) use anchored containers with `.ax-overlay-pane`.
|
|
2589
|
+
*/
|
|
2590
|
+
function shouldDeferEscapeToNestedOverlayFromDom(document, dialogHost) {
|
|
2591
|
+
const dialogOverlay = findOverlayContainerAncestor(dialogHost);
|
|
2592
|
+
if (getNestedVisibleOverlayPanes(document, dialogOverlay).length > 0) {
|
|
2593
|
+
return true;
|
|
2594
|
+
}
|
|
2595
|
+
const topContainer = getTopVisibleOverlayContainer(document);
|
|
2596
|
+
if (!topContainer) {
|
|
2597
|
+
return false;
|
|
2598
|
+
}
|
|
2599
|
+
if (!dialogOverlay) {
|
|
2600
|
+
return topContainer.contains(dialogHost) === false;
|
|
2601
|
+
}
|
|
2602
|
+
return topContainer !== dialogOverlay;
|
|
2603
|
+
}
|
|
2604
|
+
/**
|
|
2605
|
+
* When a nested overlay is above this dialog (widget popover, confirm box, etc.), footer shortcuts
|
|
2606
|
+
* should not run on the parent dialog.
|
|
2607
|
+
*/
|
|
2608
|
+
function shouldDeferDialogShortcutsToNestedOverlay(document, dialogHost, overlayService) {
|
|
2609
|
+
const dialogOverlay = findOverlayContainerAncestor(dialogHost);
|
|
2610
|
+
if (overlayService) {
|
|
2611
|
+
const fromService = hasOpenNestedOverlayFromAcorexService(overlayService, dialogOverlay);
|
|
2612
|
+
if (fromService !== null) {
|
|
2613
|
+
return fromService;
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
return shouldDeferEscapeToNestedOverlayFromDom(document, dialogHost);
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
/**
|
|
2620
|
+
* Builds the `show()` resolve payload for layout-builder custom footer commands (fallback path).
|
|
2621
|
+
*/
|
|
2622
|
+
function buildLayoutBuilderCustomActionRef(createDialogRef, command) {
|
|
2623
|
+
return {
|
|
2624
|
+
...createDialogRef(command),
|
|
2625
|
+
action: () => command,
|
|
2626
|
+
};
|
|
2627
|
+
}
|
|
2628
|
+
/**
|
|
2629
|
+
* Keeps legacy popup `data.context` / `data.action` side fields in sync for custom footer commands.
|
|
2630
|
+
*/
|
|
2631
|
+
function syncLegacyDialogDataSideFields(data, context, action) {
|
|
2632
|
+
if (!data) {
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
data.context = context;
|
|
2636
|
+
data.action = action;
|
|
2637
|
+
}
|
|
2638
|
+
/**
|
|
2639
|
+
* Cancel from an `onAction` handler should route through the dirty-close gate only when configured.
|
|
2640
|
+
* Otherwise preserve the original resolve-then-close sequence.
|
|
2641
|
+
*/
|
|
2642
|
+
function shouldRouteOnActionCancelThroughDismissGate(confirmCloseWhenDirtyEnabled) {
|
|
2643
|
+
return confirmCloseWhenDirtyEnabled === true;
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
/** Debounce after widget count stabilizes before re-evaluating footer actions. */
|
|
2647
|
+
const DIALOG_WIDGET_COUNT_STABLE_DELAY_MS = 350;
|
|
2389
2648
|
class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
2390
2649
|
constructor() {
|
|
2391
2650
|
super(...arguments);
|
|
@@ -2393,8 +2652,18 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2393
2652
|
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
2394
2653
|
this.commandService = inject(AXPCommandService);
|
|
2395
2654
|
this.hookService = inject(AXPHookService, { optional: true });
|
|
2655
|
+
this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
|
|
2656
|
+
this.overlayService = inject(AXOverlayService);
|
|
2657
|
+
this.translationService = inject(AXTranslationService);
|
|
2658
|
+
this.document = inject(DOCUMENT);
|
|
2659
|
+
this.host = inject((ElementRef));
|
|
2396
2660
|
/** Ensures `show()` resolves once when the dialog closes (footer action or header close). */
|
|
2397
2661
|
this.callbackInvoked = false;
|
|
2662
|
+
/** Skips dirty confirmation on the next {@link onClosing} (successful submit / programmatic close). */
|
|
2663
|
+
this.skipNextOnClosingDirtyCheck = false;
|
|
2664
|
+
/** Blocks re-entrant {@link onClosing} while the first close gate is still resolving. */
|
|
2665
|
+
this.closeGateInProgress = false;
|
|
2666
|
+
this.destroyRef = inject(DestroyRef);
|
|
2398
2667
|
this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
|
|
2399
2668
|
// This will be set by the popup service automatically - same as dynamic-dialog
|
|
2400
2669
|
this.callBack = () => { };
|
|
@@ -2408,39 +2677,136 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2408
2677
|
this.contextChangedHooksSessionKey = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
|
|
2409
2678
|
? crypto.randomUUID()
|
|
2410
2679
|
: `layout-dialog-ctx-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
2680
|
+
/**
|
|
2681
|
+
* Capture-phase footer shortcuts — runs before widget editors (select, date, text) that stop keydown bubbling.
|
|
2682
|
+
*/
|
|
2683
|
+
this.onDialogShortcutCapture = (event) => {
|
|
2684
|
+
if (this.isDialogLoading()) {
|
|
2685
|
+
return;
|
|
2686
|
+
}
|
|
2687
|
+
// Unsaved-changes confirm is modal — parent footer shortcuts must not run underneath it.
|
|
2688
|
+
if (this.unsavedChangesConfirm.isConfirmPending()) {
|
|
2689
|
+
return;
|
|
2690
|
+
}
|
|
2691
|
+
if (shouldDeferDialogShortcutsToNestedOverlay(this.document, this.host.nativeElement, this.overlayService)) {
|
|
2692
|
+
return;
|
|
2693
|
+
}
|
|
2694
|
+
if (event.key === 'Escape' && this.config?.confirmCloseWhenDirty?.enabled) {
|
|
2695
|
+
event.preventDefault();
|
|
2696
|
+
event.stopImmediatePropagation();
|
|
2697
|
+
this.requestDismiss();
|
|
2698
|
+
return;
|
|
2699
|
+
}
|
|
2700
|
+
const actions = [...this.footerPrefixActions(), ...this.footerSuffixActions()];
|
|
2701
|
+
for (const action of actions) {
|
|
2702
|
+
if (action.disabled || action.hidden || !action.shortcuts?.length) {
|
|
2703
|
+
continue;
|
|
2704
|
+
}
|
|
2705
|
+
for (const shortcut of action.shortcuts) {
|
|
2706
|
+
if (event.key === 'Escape' && this.config?.confirmCloseWhenDirty?.enabled) {
|
|
2707
|
+
continue;
|
|
2708
|
+
}
|
|
2709
|
+
if (!matchesDialogActionShortcut(event, shortcut) || !shouldTriggerDialogActionShortcut(event, shortcut)) {
|
|
2710
|
+
continue;
|
|
2711
|
+
}
|
|
2712
|
+
event.preventDefault();
|
|
2713
|
+
event.stopImmediatePropagation();
|
|
2714
|
+
void this.executeAction(action);
|
|
2715
|
+
return;
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
};
|
|
2411
2719
|
//#endregion
|
|
2412
2720
|
//#region ---- View Accessors ----
|
|
2413
2721
|
// Access the internal layout renderer to reach the widgets container injector
|
|
2414
2722
|
this.layoutRenderer = viewChild(AXPLayoutRendererComponent, ...(ngDevMode ? [{ debugName: "layoutRenderer" }] : /* istanbul ignore next */ []));
|
|
2415
|
-
this.#
|
|
2416
|
-
let count = 0;
|
|
2723
|
+
this.#widgetActionsEffect = effect(() => {
|
|
2417
2724
|
this.aggregateAndEvaluateActions();
|
|
2418
2725
|
if (!this.widgetCoreService) {
|
|
2419
2726
|
const renderer = this.layoutRenderer();
|
|
2420
2727
|
const container = renderer?.getContainer();
|
|
2421
2728
|
this.widgetCoreService = container?.builderService ?? null;
|
|
2422
|
-
|
|
2729
|
+
return;
|
|
2423
2730
|
}
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
if (this.debounceTimer) {
|
|
2428
|
-
clearTimeout(this.debounceTimer);
|
|
2429
|
-
}
|
|
2430
|
-
// Set new timer to call after 200ms of no count changes
|
|
2431
|
-
this.debounceTimer = setTimeout(() => {
|
|
2432
|
-
this.aggregateAndEvaluateActions();
|
|
2433
|
-
}, 200);
|
|
2731
|
+
this.widgetCoreService.registeredWidgetsCount();
|
|
2732
|
+
if (this.debounceTimer) {
|
|
2733
|
+
clearTimeout(this.debounceTimer);
|
|
2434
2734
|
}
|
|
2435
|
-
|
|
2735
|
+
this.debounceTimer = setTimeout(() => {
|
|
2736
|
+
this.aggregateAndEvaluateActions();
|
|
2737
|
+
}, DIALOG_WIDGET_COUNT_STABLE_DELAY_MS);
|
|
2738
|
+
}, ...(ngDevMode ? [{ debugName: "#widgetActionsEffect" }] : /* istanbul ignore next */ []));
|
|
2436
2739
|
}
|
|
2437
2740
|
//#endregion
|
|
2438
2741
|
//#region ---- Lifecycle ----
|
|
2439
2742
|
ngOnInit() {
|
|
2440
|
-
this.
|
|
2743
|
+
const initialContext = this.config?.context || {};
|
|
2744
|
+
this.context.set(initialContext);
|
|
2745
|
+
this.document.addEventListener('keydown', this.onDialogShortcutCapture, true);
|
|
2746
|
+
this.destroyRef.onDestroy(() => {
|
|
2747
|
+
this.document.removeEventListener('keydown', this.onDialogShortcutCapture, true);
|
|
2748
|
+
});
|
|
2441
2749
|
void this.invokeLayoutContextChangedHooks();
|
|
2442
2750
|
}
|
|
2443
|
-
|
|
2751
|
+
//#endregion
|
|
2752
|
+
//#region ---- Popup Close Gate ----
|
|
2753
|
+
/**
|
|
2754
|
+
* Popup shell hook — handles header **X** and **Esc** (when `closeButton` is enabled).
|
|
2755
|
+
* This is the only place that prompts for unsaved changes.
|
|
2756
|
+
*/
|
|
2757
|
+
async onClosing(e) {
|
|
2758
|
+
if (this.unsavedChangesConfirm.isConfirmPending() || this.closeGateInProgress) {
|
|
2759
|
+
e.cancel = true;
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
2762
|
+
this.closeGateInProgress = true;
|
|
2763
|
+
try {
|
|
2764
|
+
if (this.skipNextOnClosingDirtyCheck) {
|
|
2765
|
+
this.skipNextOnClosingDirtyCheck = false;
|
|
2766
|
+
this.completeDismissResolve();
|
|
2767
|
+
return;
|
|
2768
|
+
}
|
|
2769
|
+
if (!this.config?.confirmCloseWhenDirty?.enabled) {
|
|
2770
|
+
this.completeDismissResolve();
|
|
2771
|
+
return;
|
|
2772
|
+
}
|
|
2773
|
+
if (!(await this.confirmDismissIfDirty())) {
|
|
2774
|
+
e.cancel = true;
|
|
2775
|
+
this.pendingDismissResolvePayload = undefined;
|
|
2776
|
+
return;
|
|
2777
|
+
}
|
|
2778
|
+
this.completeDismissResolve();
|
|
2779
|
+
}
|
|
2780
|
+
finally {
|
|
2781
|
+
this.closeGateInProgress = false;
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
/**
|
|
2785
|
+
* Footer cancel and other in-app dismiss actions. Routes through `super.close()` so the
|
|
2786
|
+
* popup shell invokes {@link onClosing} exactly once (same path as **X** / **Esc**).
|
|
2787
|
+
*/
|
|
2788
|
+
requestDismiss(resolvePayload) {
|
|
2789
|
+
this.pendingDismissResolvePayload = resolvePayload ?? this.createDialogRef('cancel');
|
|
2790
|
+
super.close();
|
|
2791
|
+
}
|
|
2792
|
+
/** Invokes `show()` callback with the pending payload or a default cancel {@link AXPDialogRef}. */
|
|
2793
|
+
completeDismissResolve() {
|
|
2794
|
+
const payload = this.pendingDismissResolvePayload;
|
|
2795
|
+
this.pendingDismissResolvePayload = undefined;
|
|
2796
|
+
if (payload !== undefined) {
|
|
2797
|
+
this.resolveDialog(payload);
|
|
2798
|
+
return;
|
|
2799
|
+
}
|
|
2800
|
+
if (!this.callbackInvoked) {
|
|
2801
|
+
this.resolveDialog(this.createDialogRef('cancel'));
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
//#endregion
|
|
2805
|
+
//#region ---- Dirty State ----
|
|
2806
|
+
getWidgetContainer() {
|
|
2807
|
+
return this.layoutRenderer()?.getContainer();
|
|
2808
|
+
}
|
|
2809
|
+
#widgetActionsEffect;
|
|
2444
2810
|
//#endregion
|
|
2445
2811
|
handleContextChanged(event) {
|
|
2446
2812
|
this.context.set(event);
|
|
@@ -2459,7 +2825,10 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2459
2825
|
}
|
|
2460
2826
|
const payload = {
|
|
2461
2827
|
sessionKey: this.contextChangedHooksSessionKey,
|
|
2462
|
-
getContext: () =>
|
|
2828
|
+
getContext: () => {
|
|
2829
|
+
const store = this.getWidgetContainer()?.contextService;
|
|
2830
|
+
return (store?.data() ?? this.context() ?? {});
|
|
2831
|
+
},
|
|
2463
2832
|
metadata: meta,
|
|
2464
2833
|
patchContext: (partial) => {
|
|
2465
2834
|
const merged = merge({}, this.context(), partial);
|
|
@@ -2525,6 +2894,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2525
2894
|
}
|
|
2526
2895
|
const context = this.context();
|
|
2527
2896
|
const onAction = this.config?.onAction;
|
|
2897
|
+
// `onAction` return value is passed through to `show()` unchanged — see dialog-resolve.util.ts.
|
|
2528
2898
|
if (onAction) {
|
|
2529
2899
|
const dialogRef = this.createDialogRef(cmd);
|
|
2530
2900
|
try {
|
|
@@ -2533,6 +2903,12 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2533
2903
|
if (this.shouldKeepDialogOpenAfterCommandResult(result)) {
|
|
2534
2904
|
return;
|
|
2535
2905
|
}
|
|
2906
|
+
if (cmd === 'cancel' &&
|
|
2907
|
+
shouldRouteOnActionCancelThroughDismissGate(this.config?.confirmCloseWhenDirty?.enabled)) {
|
|
2908
|
+
this.isDialogLoading.set(false);
|
|
2909
|
+
this.requestDismiss(result);
|
|
2910
|
+
return;
|
|
2911
|
+
}
|
|
2536
2912
|
this.resolveDialog(result);
|
|
2537
2913
|
await this.closeWithOptionalSkipValidate(result);
|
|
2538
2914
|
}
|
|
@@ -2544,21 +2920,43 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2544
2920
|
}
|
|
2545
2921
|
return;
|
|
2546
2922
|
}
|
|
2547
|
-
// Fallback:
|
|
2923
|
+
// Fallback: layout-builder custom footer commands (e.g. signature-apply, upload-image).
|
|
2924
|
+
// See dialog-resolve.util.ts — resolves {@link AXPDialogRef}; does not auto-close except cancel.
|
|
2548
2925
|
const result = { context, action: cmd };
|
|
2549
2926
|
this.dialogResult = result;
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
this.data.action = result.action;
|
|
2553
|
-
}
|
|
2554
|
-
this.resolveDialog({
|
|
2555
|
-
...this.createDialogRef(cmd),
|
|
2556
|
-
action: () => result.action,
|
|
2557
|
-
});
|
|
2558
|
-
// Without `onAction`, only the configured cancel action dismisses the dialog (not submit/custom).
|
|
2927
|
+
syncLegacyDialogDataSideFields(this.data, result.context, result.action);
|
|
2928
|
+
const dialogRefPayload = buildLayoutBuilderCustomActionRef((command) => this.createDialogRef(command), cmd);
|
|
2559
2929
|
if (cmd === 'cancel') {
|
|
2560
|
-
|
|
2930
|
+
this.requestDismiss(dialogRefPayload);
|
|
2931
|
+
return;
|
|
2932
|
+
}
|
|
2933
|
+
this.resolveDialog(dialogRefPayload);
|
|
2934
|
+
}
|
|
2935
|
+
isDialogDirty() {
|
|
2936
|
+
const confirmOptions = this.config?.confirmCloseWhenDirty;
|
|
2937
|
+
if (!confirmOptions?.enabled) {
|
|
2938
|
+
return false;
|
|
2939
|
+
}
|
|
2940
|
+
const container = this.getWidgetContainer();
|
|
2941
|
+
if (!container?.isSavedCommitted()) {
|
|
2942
|
+
return false;
|
|
2943
|
+
}
|
|
2944
|
+
const store = container.contextService;
|
|
2945
|
+
if (typeof confirmOptions.isDirty === 'function') {
|
|
2946
|
+
return confirmOptions.isDirty(store.data(), store.saved());
|
|
2561
2947
|
}
|
|
2948
|
+
return container.isFormDirty();
|
|
2949
|
+
}
|
|
2950
|
+
confirmDismissIfDirty() {
|
|
2951
|
+
const confirmOptions = this.config?.confirmCloseWhenDirty;
|
|
2952
|
+
if (!confirmOptions?.enabled || !this.isDialogDirty()) {
|
|
2953
|
+
return Promise.resolve(true);
|
|
2954
|
+
}
|
|
2955
|
+
return this.unsavedChangesConfirm.confirmIfDirty(true, {
|
|
2956
|
+
enabled: confirmOptions.enabled,
|
|
2957
|
+
title: confirmOptions.title,
|
|
2958
|
+
message: confirmOptions.message,
|
|
2959
|
+
});
|
|
2562
2960
|
}
|
|
2563
2961
|
/** Whether the layout form should be validated before running this footer command. */
|
|
2564
2962
|
shouldValidateBeforeAction(cmd) {
|
|
@@ -2614,10 +3012,12 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2614
3012
|
async closeWithOptionalSkipValidate(result) {
|
|
2615
3013
|
if (result && typeof result === 'object' && result.skipValidate) {
|
|
2616
3014
|
this.result.emit(result);
|
|
2617
|
-
|
|
3015
|
+
this.skipNextOnClosingDirtyCheck = true;
|
|
3016
|
+
this.pendingDismissResolvePayload = undefined;
|
|
3017
|
+
super.close(result);
|
|
2618
3018
|
return;
|
|
2619
3019
|
}
|
|
2620
|
-
await this.close(result);
|
|
3020
|
+
await this.close(result, { skipDirtyConfirm: true });
|
|
2621
3021
|
}
|
|
2622
3022
|
/** Resolves footer/widget action command to a string (e.g. `cancel`, `submit`, `widget:...`). */
|
|
2623
3023
|
resolveActionCommandName(command) {
|
|
@@ -2664,9 +3064,10 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2664
3064
|
//
|
|
2665
3065
|
}
|
|
2666
3066
|
}
|
|
2667
|
-
async close(result) {
|
|
2668
|
-
if (
|
|
2669
|
-
this.
|
|
3067
|
+
async close(result, options) {
|
|
3068
|
+
if (options?.skipDirtyConfirm) {
|
|
3069
|
+
this.skipNextOnClosingDirtyCheck = true;
|
|
3070
|
+
this.pendingDismissResolvePayload = undefined;
|
|
2670
3071
|
}
|
|
2671
3072
|
if (result) {
|
|
2672
3073
|
const isValid = await this.layoutRenderer()?.validate();
|
|
@@ -2716,6 +3117,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2716
3117
|
placement,
|
|
2717
3118
|
scope: a.scope,
|
|
2718
3119
|
predicateApiWidgetName: a.predicateApiWidgetName,
|
|
3120
|
+
shortcuts: resolveConfiguredFooterActionShortcuts(typeof a.command === 'string' ? a.command : a.command?.name, a.shortcuts),
|
|
2719
3121
|
});
|
|
2720
3122
|
const prefix = (footer?.prefix || []).map((a) => mapOne(a, 'prefix'));
|
|
2721
3123
|
const suffix = (footer?.suffix || []).map((a) => mapOne(a, 'suffix'));
|
|
@@ -3124,5 +3526,5 @@ var previewWidgetField_command = /*#__PURE__*/Object.freeze({
|
|
|
3124
3526
|
* Generated bundle index. Do not edit.
|
|
3125
3527
|
*/
|
|
3126
3528
|
|
|
3127
|
-
export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, AXPPreviewWidgetFieldCommand, AXP_LAYOUT_BUILDER_DIALOG_BEFORE_OPEN_HOOK_KEY, AXP_LAYOUT_BUILDER_DIALOG_CONFIG_HOOK_KEY, AXP_LAYOUT_BUILDER_DIALOG_CONTEXT_CHANGED_HOOK_KEY, AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY, LayoutBuilderModule, createDismissedDialogRef };
|
|
3529
|
+
export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, AXPPreviewWidgetFieldCommand, AXP_LAYOUT_BUILDER_DIALOG_BEFORE_OPEN_HOOK_KEY, AXP_LAYOUT_BUILDER_DIALOG_CONFIG_HOOK_KEY, AXP_LAYOUT_BUILDER_DIALOG_CONTEXT_CHANGED_HOOK_KEY, AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY, DEFAULT_CANCEL_DIALOG_ACTION_SHORTCUTS, DEFAULT_SUBMIT_DIALOG_ACTION_SHORTCUTS, LayoutBuilderModule, createDismissedDialogRef };
|
|
3128
3530
|
//# sourceMappingURL=acorex-platform-layout-builder.mjs.map
|