bways-report 0.1.0

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.
Files changed (185) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +477 -0
  3. package/esm2022/bways-report.mjs +5 -0
  4. package/esm2022/lib/core/errors/index.mjs +2 -0
  5. package/esm2022/lib/core/errors/reporting-errors.mjs +65 -0
  6. package/esm2022/lib/core/index.mjs +8 -0
  7. package/esm2022/lib/core/models/component-event.model.mjs +8 -0
  8. package/esm2022/lib/core/models/index.mjs +5 -0
  9. package/esm2022/lib/core/models/report-component.model.mjs +10 -0
  10. package/esm2022/lib/core/models/report-datasource.model.mjs +9 -0
  11. package/esm2022/lib/core/models/report-definition.model.mjs +13 -0
  12. package/esm2022/lib/core/models/report-grid.model.mjs +10 -0
  13. package/esm2022/lib/core/models/report-layout.model.mjs +9 -0
  14. package/esm2022/lib/core/models/report-parameter.model.mjs +9 -0
  15. package/esm2022/lib/core/models/validation.model.mjs +8 -0
  16. package/esm2022/lib/core/registry/component-category.mjs +8 -0
  17. package/esm2022/lib/core/registry/component-registry.mjs +90 -0
  18. package/esm2022/lib/core/registry/index.mjs +2 -0
  19. package/esm2022/lib/core/registry/property-definition.model.mjs +10 -0
  20. package/esm2022/lib/core/services/dynamic-form-builder.service.mjs +55 -0
  21. package/esm2022/lib/core/services/index.mjs +3 -0
  22. package/esm2022/lib/core/services/report-session-context.service.mjs +314 -0
  23. package/esm2022/lib/core/tokens/index.mjs +3 -0
  24. package/esm2022/lib/core/tokens/reporting-config.token.mjs +26 -0
  25. package/esm2022/lib/core/tokens/session-context.token.mjs +18 -0
  26. package/esm2022/lib/core/utilities/id-generator.mjs +17 -0
  27. package/esm2022/lib/core/utilities/index.mjs +3 -0
  28. package/esm2022/lib/core/utilities/schema-migration.mjs +38 -0
  29. package/esm2022/lib/core/utils/identifier-humanizer.mjs +88 -0
  30. package/esm2022/lib/core/validation/index.mjs +2 -0
  31. package/esm2022/lib/core/validation/validation-factory.mjs +70 -0
  32. package/esm2022/lib/data-access/adapters/http-lookup.adapter.mjs +107 -0
  33. package/esm2022/lib/data-access/adapters/http-schema-discovery.adapter.mjs +119 -0
  34. package/esm2022/lib/data-access/adapters/index.mjs +3 -0
  35. package/esm2022/lib/data-access/contracts/data-source.contract.mjs +28 -0
  36. package/esm2022/lib/data-access/contracts/index.mjs +7 -0
  37. package/esm2022/lib/data-access/contracts/lookup.contract.mjs +6 -0
  38. package/esm2022/lib/data-access/contracts/master-data.provider.mjs +24 -0
  39. package/esm2022/lib/data-access/contracts/report-persistence.contract.mjs +25 -0
  40. package/esm2022/lib/data-access/contracts/schema-discovery.contract.mjs +7 -0
  41. package/esm2022/lib/data-access/contracts/translation.contract.mjs +9 -0
  42. package/esm2022/lib/data-access/index.mjs +3 -0
  43. package/esm2022/lib/features/designer/components/component-palette/component-palette.component.mjs +542 -0
  44. package/esm2022/lib/features/designer/components/design-canvas/design-canvas.component.mjs +843 -0
  45. package/esm2022/lib/features/designer/components/property-editor/parameter-binding-editor.component.mjs +556 -0
  46. package/esm2022/lib/features/designer/components/property-editor/property-editor-datasource.component.mjs +845 -0
  47. package/esm2022/lib/features/designer/components/property-editor/property-editor-general.component.mjs +185 -0
  48. package/esm2022/lib/features/designer/components/property-editor/property-editor-grid.component.mjs +452 -0
  49. package/esm2022/lib/features/designer/components/property-editor/property-editor-layout.component.mjs +350 -0
  50. package/esm2022/lib/features/designer/components/property-editor/property-editor-report.component.mjs +175 -0
  51. package/esm2022/lib/features/designer/components/property-editor/property-editor-validation.component.mjs +137 -0
  52. package/esm2022/lib/features/designer/components/property-editor/property-editor.component.mjs +608 -0
  53. package/esm2022/lib/features/designer/components/toolbar/designer-toolbar.component.mjs +225 -0
  54. package/esm2022/lib/features/designer/designer.component.mjs +285 -0
  55. package/esm2022/lib/features/designer/index.mjs +7 -0
  56. package/esm2022/lib/features/designer/services/designer-state.service.mjs +310 -0
  57. package/esm2022/lib/features/designer/services/index.mjs +2 -0
  58. package/esm2022/lib/features/designer/utilities/canvas-layout.util.mjs +124 -0
  59. package/esm2022/lib/features/export/index.mjs +2 -0
  60. package/esm2022/lib/features/export/models/export.models.mjs +2 -0
  61. package/esm2022/lib/features/export/services/report-export.service.mjs +107 -0
  62. package/esm2022/lib/features/index.mjs +6 -0
  63. package/esm2022/lib/features/persistence/index.mjs +2 -0
  64. package/esm2022/lib/features/persistence/services/index.mjs +4 -0
  65. package/esm2022/lib/features/persistence/services/report-store.service.mjs +183 -0
  66. package/esm2022/lib/features/persistence/services/report-versioning.service.mjs +81 -0
  67. package/esm2022/lib/features/persistence/services/schema-validator.service.mjs +102 -0
  68. package/esm2022/lib/features/routing/components/routed-report-designer.component.mjs +156 -0
  69. package/esm2022/lib/features/routing/components/routed-report-runtime.component.mjs +163 -0
  70. package/esm2022/lib/features/routing/index.mjs +6 -0
  71. package/esm2022/lib/features/routing/models/report-route.models.mjs +2 -0
  72. package/esm2022/lib/features/routing/report-routes.mjs +49 -0
  73. package/esm2022/lib/features/routing/resolvers/report.resolver.mjs +22 -0
  74. package/esm2022/lib/features/routing/services/report-menu.service.mjs +77 -0
  75. package/esm2022/lib/features/runtime/dynamic-renderer.component.mjs +222 -0
  76. package/esm2022/lib/features/runtime/index.mjs +4 -0
  77. package/esm2022/lib/features/runtime/report-grid-bridge.component.mjs +409 -0
  78. package/esm2022/lib/features/runtime/report-runtime.component.mjs +147 -0
  79. package/esm2022/lib/primitives/components/button/rpt-button.component.mjs +88 -0
  80. package/esm2022/lib/primitives/components/chart-bridge/report-chart-bridge.component.mjs +361 -0
  81. package/esm2022/lib/primitives/components/checkbox/rpt-checkbox.component.mjs +86 -0
  82. package/esm2022/lib/primitives/components/date/rpt-date.component.mjs +91 -0
  83. package/esm2022/lib/primitives/components/dropdown/rpt-dropdown.component.mjs +204 -0
  84. package/esm2022/lib/primitives/components/icon/rpt-icon.component.mjs +476 -0
  85. package/esm2022/lib/primitives/components/index.mjs +10 -0
  86. package/esm2022/lib/primitives/components/input/rpt-input.component.mjs +88 -0
  87. package/esm2022/lib/primitives/components/kpi-card/rpt-kpi-card.component.mjs +197 -0
  88. package/esm2022/lib/primitives/components/number/rpt-number.component.mjs +110 -0
  89. package/esm2022/lib/primitives/index.mjs +3 -0
  90. package/esm2022/lib/primitives/register-builtins.mjs +328 -0
  91. package/esm2022/lib/provide-reporting.mjs +92 -0
  92. package/esm2022/public-api.mjs +9 -0
  93. package/fesm2022/bways-report.mjs +10360 -0
  94. package/fesm2022/bways-report.mjs.map +1 -0
  95. package/index.d.ts +5 -0
  96. package/lib/core/errors/index.d.ts +1 -0
  97. package/lib/core/errors/reporting-errors.d.ts +42 -0
  98. package/lib/core/index.d.ts +7 -0
  99. package/lib/core/models/component-event.model.d.ts +37 -0
  100. package/lib/core/models/index.d.ts +11 -0
  101. package/lib/core/models/report-component.model.d.ts +95 -0
  102. package/lib/core/models/report-datasource.model.d.ts +39 -0
  103. package/lib/core/models/report-definition.model.d.ts +100 -0
  104. package/lib/core/models/report-grid.model.d.ts +73 -0
  105. package/lib/core/models/report-layout.model.d.ts +43 -0
  106. package/lib/core/models/report-parameter.model.d.ts +22 -0
  107. package/lib/core/models/validation.model.d.ts +30 -0
  108. package/lib/core/registry/component-category.d.ts +16 -0
  109. package/lib/core/registry/component-registry.d.ts +101 -0
  110. package/lib/core/registry/index.d.ts +4 -0
  111. package/lib/core/registry/property-definition.model.d.ts +38 -0
  112. package/lib/core/services/dynamic-form-builder.service.d.ts +30 -0
  113. package/lib/core/services/index.d.ts +3 -0
  114. package/lib/core/services/report-session-context.service.d.ts +87 -0
  115. package/lib/core/tokens/index.d.ts +4 -0
  116. package/lib/core/tokens/reporting-config.token.d.ts +42 -0
  117. package/lib/core/tokens/session-context.token.d.ts +36 -0
  118. package/lib/core/utilities/id-generator.d.ts +9 -0
  119. package/lib/core/utilities/index.d.ts +3 -0
  120. package/lib/core/utilities/schema-migration.d.ts +10 -0
  121. package/lib/core/utils/identifier-humanizer.d.ts +22 -0
  122. package/lib/core/validation/index.d.ts +1 -0
  123. package/lib/core/validation/validation-factory.d.ts +31 -0
  124. package/lib/data-access/adapters/http-lookup.adapter.d.ts +19 -0
  125. package/lib/data-access/adapters/http-schema-discovery.adapter.d.ts +20 -0
  126. package/lib/data-access/adapters/index.d.ts +2 -0
  127. package/lib/data-access/contracts/data-source.contract.d.ts +37 -0
  128. package/lib/data-access/contracts/index.d.ts +9 -0
  129. package/lib/data-access/contracts/lookup.contract.d.ts +32 -0
  130. package/lib/data-access/contracts/master-data.provider.d.ts +54 -0
  131. package/lib/data-access/contracts/report-persistence.contract.d.ts +36 -0
  132. package/lib/data-access/contracts/schema-discovery.contract.d.ts +52 -0
  133. package/lib/data-access/contracts/translation.contract.d.ts +16 -0
  134. package/lib/data-access/index.d.ts +2 -0
  135. package/lib/features/designer/components/component-palette/component-palette.component.d.ts +39 -0
  136. package/lib/features/designer/components/design-canvas/design-canvas.component.d.ts +42 -0
  137. package/lib/features/designer/components/property-editor/parameter-binding-editor.component.d.ts +36 -0
  138. package/lib/features/designer/components/property-editor/property-editor-datasource.component.d.ts +68 -0
  139. package/lib/features/designer/components/property-editor/property-editor-general.component.d.ts +20 -0
  140. package/lib/features/designer/components/property-editor/property-editor-grid.component.d.ts +20 -0
  141. package/lib/features/designer/components/property-editor/property-editor-layout.component.d.ts +18 -0
  142. package/lib/features/designer/components/property-editor/property-editor-report.component.d.ts +15 -0
  143. package/lib/features/designer/components/property-editor/property-editor-validation.component.d.ts +12 -0
  144. package/lib/features/designer/components/property-editor/property-editor.component.d.ts +44 -0
  145. package/lib/features/designer/components/toolbar/designer-toolbar.component.d.ts +18 -0
  146. package/lib/features/designer/designer.component.d.ts +36 -0
  147. package/lib/features/designer/index.d.ts +7 -0
  148. package/lib/features/designer/services/designer-state.service.d.ts +103 -0
  149. package/lib/features/designer/services/index.d.ts +2 -0
  150. package/lib/features/designer/utilities/canvas-layout.util.d.ts +55 -0
  151. package/lib/features/export/index.d.ts +2 -0
  152. package/lib/features/export/models/export.models.d.ts +16 -0
  153. package/lib/features/export/services/report-export.service.d.ts +27 -0
  154. package/lib/features/index.d.ts +5 -0
  155. package/lib/features/persistence/index.d.ts +1 -0
  156. package/lib/features/persistence/services/index.d.ts +5 -0
  157. package/lib/features/persistence/services/report-store.service.d.ts +53 -0
  158. package/lib/features/persistence/services/report-versioning.service.d.ts +29 -0
  159. package/lib/features/persistence/services/schema-validator.service.d.ts +34 -0
  160. package/lib/features/routing/components/routed-report-designer.component.d.ts +18 -0
  161. package/lib/features/routing/components/routed-report-runtime.component.d.ts +18 -0
  162. package/lib/features/routing/index.d.ts +6 -0
  163. package/lib/features/routing/models/report-route.models.d.ts +41 -0
  164. package/lib/features/routing/report-routes.d.ts +16 -0
  165. package/lib/features/routing/resolvers/report.resolver.d.ts +7 -0
  166. package/lib/features/routing/services/report-menu.service.d.ts +30 -0
  167. package/lib/features/runtime/dynamic-renderer.component.d.ts +30 -0
  168. package/lib/features/runtime/index.d.ts +3 -0
  169. package/lib/features/runtime/report-grid-bridge.component.d.ts +94 -0
  170. package/lib/features/runtime/report-runtime.component.d.ts +26 -0
  171. package/lib/primitives/components/button/rpt-button.component.d.ts +19 -0
  172. package/lib/primitives/components/chart-bridge/report-chart-bridge.component.d.ts +45 -0
  173. package/lib/primitives/components/checkbox/rpt-checkbox.component.d.ts +14 -0
  174. package/lib/primitives/components/date/rpt-date.component.d.ts +17 -0
  175. package/lib/primitives/components/dropdown/rpt-dropdown.component.d.ts +32 -0
  176. package/lib/primitives/components/icon/rpt-icon.component.d.ts +41 -0
  177. package/lib/primitives/components/index.d.ts +12 -0
  178. package/lib/primitives/components/input/rpt-input.component.d.ts +16 -0
  179. package/lib/primitives/components/kpi-card/rpt-kpi-card.component.d.ts +43 -0
  180. package/lib/primitives/components/number/rpt-number.component.d.ts +20 -0
  181. package/lib/primitives/index.d.ts +2 -0
  182. package/lib/primitives/register-builtins.d.ts +11 -0
  183. package/lib/provide-reporting.d.ts +75 -0
  184. package/package.json +55 -0
  185. package/public-api.d.ts +5 -0
@@ -0,0 +1,310 @@
1
+ import { computed, inject, Injectable, signal } from '@angular/core';
2
+ import { ComponentRegistry } from '../../../core/registry/component-registry';
3
+ import { generateId } from '../../../core/utilities/id-generator';
4
+ import * as i0 from "@angular/core";
5
+ const MAX_HISTORY = 30;
6
+ /**
7
+ * DesignerStateService coordinates state for the visual report designer.
8
+ *
9
+ * Scoped at the Designer component level (not root) to ensure multiple designer
10
+ * instances or navigation flows remain strictly isolated.
11
+ */
12
+ export class DesignerStateService {
13
+ registry = inject(ComponentRegistry);
14
+ /** Current active report definition */
15
+ definition = signal({
16
+ id: generateId('rpt'),
17
+ name: 'Untitled Report',
18
+ schemaVersion: 1,
19
+ version: 1,
20
+ layout: { columns: 12, gap: 16, padding: 24, direction: 'ltr' },
21
+ components: [],
22
+ parameters: [],
23
+ dataSources: [],
24
+ });
25
+ /** Selected component ID in canvas */
26
+ selectedComponentId = signal(null);
27
+ /** Active property editor tab */
28
+ activeTab = signal('properties');
29
+ /** Current view mode (design, preview, or raw json) */
30
+ viewMode = signal('design');
31
+ /** Dirty flag indicating unsaved changes */
32
+ isDirty = signal(false);
33
+ // History stack for Undo / Redo
34
+ history = signal([]);
35
+ historyIndex = signal(-1);
36
+ canUndo = computed(() => this.historyIndex() > 0);
37
+ canRedo = computed(() => this.historyIndex() >= 0 && this.historyIndex() < this.history().length - 1);
38
+ /** Currently selected component instance, or null if none */
39
+ selectedComponent = computed(() => {
40
+ const id = this.selectedComponentId();
41
+ if (!id)
42
+ return null;
43
+ return this.definition().components.find((c) => c.id === id) ?? null;
44
+ });
45
+ /**
46
+ * Initializes or reloads a report definition into the designer.
47
+ */
48
+ loadDefinition(def) {
49
+ const cloned = JSON.parse(JSON.stringify(def));
50
+ this.definition.set(cloned);
51
+ this.selectedComponentId.set(null);
52
+ this.isDirty.set(false);
53
+ this.history.set([JSON.parse(JSON.stringify(cloned))]);
54
+ this.historyIndex.set(0);
55
+ }
56
+ /**
57
+ * Selects a component for property editing.
58
+ */
59
+ selectComponent(id) {
60
+ this.selectedComponentId.set(id);
61
+ if (id) {
62
+ this.activeTab.set('properties');
63
+ }
64
+ }
65
+ /**
66
+ * Sets the active view mode (design, live preview, json schema).
67
+ */
68
+ setViewMode(mode) {
69
+ this.viewMode.set(mode);
70
+ }
71
+ /**
72
+ * Sets the active editor tab.
73
+ */
74
+ setActiveTab(tab) {
75
+ this.activeTab.set(tab);
76
+ }
77
+ /**
78
+ * Adds a new component of the specified type onto the canvas.
79
+ */
80
+ addComponent(type, targetIndex) {
81
+ const meta = this.registry.resolve(type);
82
+ const defaultConfig = meta?.createDefaultConfig() ?? {
83
+ id: generateId(type),
84
+ type,
85
+ label: meta?.displayName ?? type,
86
+ key: `${type}_${Math.random().toString(36).substring(2, 6)}`,
87
+ };
88
+ const newComponent = {
89
+ id: generateId(type),
90
+ type,
91
+ label: defaultConfig.label ?? meta?.displayName ?? type,
92
+ key: defaultConfig.key ?? `${type}_${Math.random().toString(36).substring(2, 6)}`,
93
+ order: 0,
94
+ layout: {
95
+ columnSpan: defaultConfig.layout?.columnSpan ?? (type === 'button' ? 2 : 4),
96
+ ...defaultConfig.layout,
97
+ },
98
+ properties: { ...(defaultConfig.properties ?? {}) },
99
+ validation: defaultConfig.validation ? { ...defaultConfig.validation } : undefined,
100
+ dataSource: defaultConfig.dataSource ? { ...defaultConfig.dataSource } : undefined,
101
+ enabled: defaultConfig.enabled ?? true,
102
+ };
103
+ const currentComponents = [...this.definition().components].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
104
+ if (targetIndex !== undefined && targetIndex >= 0 && targetIndex <= currentComponents.length) {
105
+ currentComponents.splice(targetIndex, 0, newComponent);
106
+ }
107
+ else {
108
+ currentComponents.push(newComponent);
109
+ }
110
+ // Recalculate order indices
111
+ currentComponents.forEach((c, idx) => (c.order = idx + 1));
112
+ this.mutateDefinition((def) => ({
113
+ ...def,
114
+ components: currentComponents,
115
+ }));
116
+ this.selectComponent(newComponent.id);
117
+ return newComponent;
118
+ }
119
+ /**
120
+ * Removes a component by its ID.
121
+ */
122
+ removeComponent(id) {
123
+ const currentComponents = this.definition().components.filter((c) => c.id !== id);
124
+ currentComponents.forEach((c, idx) => (c.order = idx + 1));
125
+ if (this.selectedComponentId() === id) {
126
+ this.selectedComponentId.set(null);
127
+ }
128
+ this.mutateDefinition((def) => ({
129
+ ...def,
130
+ components: currentComponents,
131
+ }));
132
+ }
133
+ /**
134
+ * Duplicates an existing component.
135
+ */
136
+ duplicateComponent(id) {
137
+ const existing = this.definition().components.find((c) => c.id === id);
138
+ if (!existing)
139
+ return null;
140
+ const duplicated = {
141
+ ...JSON.parse(JSON.stringify(existing)),
142
+ id: generateId(existing.type),
143
+ key: existing.key ? `${existing.key}_copy` : undefined,
144
+ label: existing.label ? `${existing.label} (Copy)` : undefined,
145
+ };
146
+ const currentComponents = [...this.definition().components].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
147
+ const index = currentComponents.findIndex((c) => c.id === id);
148
+ currentComponents.splice(index + 1, 0, duplicated);
149
+ currentComponents.forEach((c, idx) => (c.order = idx + 1));
150
+ this.mutateDefinition((def) => ({
151
+ ...def,
152
+ components: currentComponents,
153
+ }));
154
+ this.selectComponent(duplicated.id);
155
+ return duplicated;
156
+ }
157
+ /**
158
+ * Moves a component from previous index to current index (e.g. from CDK drag drop).
159
+ */
160
+ moveComponent(previousIndex, currentIndex) {
161
+ if (previousIndex === currentIndex)
162
+ return;
163
+ const currentComponents = [...this.definition().components].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
164
+ if (previousIndex < 0 || previousIndex >= currentComponents.length)
165
+ return;
166
+ const targetIdx = Math.max(0, Math.min(currentIndex, currentComponents.length - 1));
167
+ const [moved] = currentComponents.splice(previousIndex, 1);
168
+ currentComponents.splice(targetIdx, 0, moved);
169
+ currentComponents.forEach((c, idx) => (c.order = idx + 1));
170
+ this.mutateDefinition((def) => ({
171
+ ...def,
172
+ components: currentComponents,
173
+ }));
174
+ }
175
+ /**
176
+ * Updates partial properties of a component.
177
+ */
178
+ updateComponent(id, updates) {
179
+ const currentComponents = this.definition().components.map((c) => {
180
+ if (c.id === id) {
181
+ return { ...c, ...updates };
182
+ }
183
+ return c;
184
+ });
185
+ this.mutateDefinition((def) => ({
186
+ ...def,
187
+ components: currentComponents,
188
+ }));
189
+ }
190
+ /**
191
+ * Updates a single component property value within `properties`.
192
+ */
193
+ updateComponentProperty(id, propKey, value) {
194
+ const currentComponents = this.definition().components.map((c) => {
195
+ if (c.id === id) {
196
+ return {
197
+ ...c,
198
+ properties: {
199
+ ...(c.properties ?? {}),
200
+ [propKey]: value,
201
+ },
202
+ };
203
+ }
204
+ return c;
205
+ });
206
+ this.mutateDefinition((def) => ({
207
+ ...def,
208
+ components: currentComponents,
209
+ }));
210
+ }
211
+ /**
212
+ * Updates layout properties for a component (e.g. columnSpan).
213
+ */
214
+ updateComponentLayout(id, layout) {
215
+ const currentComponents = this.definition().components.map((c) => {
216
+ if (c.id === id) {
217
+ const nextLayout = {
218
+ ...(c.layout ?? {}),
219
+ ...layout,
220
+ };
221
+ for (const key of Object.keys(layout)) {
222
+ if (layout[key] === undefined) {
223
+ delete nextLayout[key];
224
+ }
225
+ }
226
+ return {
227
+ ...c,
228
+ layout: nextLayout,
229
+ };
230
+ }
231
+ return c;
232
+ });
233
+ this.mutateDefinition((def) => ({
234
+ ...def,
235
+ components: currentComponents,
236
+ }));
237
+ }
238
+ /**
239
+ * Updates report-level settings (name, description, layout).
240
+ */
241
+ updateReportSettings(settings) {
242
+ this.mutateDefinition((def) => ({
243
+ ...def,
244
+ ...settings,
245
+ }));
246
+ }
247
+ /**
248
+ * Updates grid definition settings.
249
+ */
250
+ updateGridSettings(grid) {
251
+ this.mutateDefinition((def) => ({
252
+ ...def,
253
+ grid,
254
+ }));
255
+ }
256
+ /**
257
+ * Reverts to the previous state in history.
258
+ */
259
+ undo() {
260
+ if (!this.canUndo())
261
+ return;
262
+ const newIndex = this.historyIndex() - 1;
263
+ this.historyIndex.set(newIndex);
264
+ const restored = JSON.parse(JSON.stringify(this.history()[newIndex]));
265
+ this.definition.set(restored);
266
+ this.isDirty.set(true);
267
+ }
268
+ /**
269
+ * Advances to the next state in history.
270
+ */
271
+ redo() {
272
+ if (!this.canRedo())
273
+ return;
274
+ const newIndex = this.historyIndex() + 1;
275
+ this.historyIndex.set(newIndex);
276
+ const restored = JSON.parse(JSON.stringify(this.history()[newIndex]));
277
+ this.definition.set(restored);
278
+ this.isDirty.set(true);
279
+ }
280
+ /**
281
+ * Marks the current definition state as saved.
282
+ */
283
+ markSaved() {
284
+ this.isDirty.set(false);
285
+ }
286
+ /**
287
+ * Applies an immutable state change and pushes to history.
288
+ */
289
+ mutateDefinition(updater) {
290
+ const next = updater(this.definition());
291
+ this.definition.set(next);
292
+ this.isDirty.set(true);
293
+ this.pushHistory(next);
294
+ }
295
+ pushHistory(def) {
296
+ const currentHist = this.history().slice(0, this.historyIndex() + 1);
297
+ currentHist.push(JSON.parse(JSON.stringify(def)));
298
+ if (currentHist.length > MAX_HISTORY) {
299
+ currentHist.shift();
300
+ }
301
+ this.history.set(currentHist);
302
+ this.historyIndex.set(currentHist.length - 1);
303
+ }
304
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DesignerStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
305
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DesignerStateService });
306
+ }
307
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DesignerStateService, decorators: [{
308
+ type: Injectable
309
+ }] });
310
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVzaWduZXItc3RhdGUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2J3YXlzLXJlcG9ydC9zcmMvbGliL2ZlYXR1cmVzL2Rlc2lnbmVyL3NlcnZpY2VzL2Rlc2lnbmVyLXN0YXRlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUtyRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUM5RSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0NBQXNDLENBQUM7O0FBS2xFLE1BQU0sV0FBVyxHQUFHLEVBQUUsQ0FBQztBQUV2Qjs7Ozs7R0FLRztBQUVILE1BQU0sT0FBTyxvQkFBb0I7SUFDZCxRQUFRLEdBQUcsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFFdEQsdUNBQXVDO0lBQzlCLFVBQVUsR0FBRyxNQUFNLENBQW1CO1FBQzdDLEVBQUUsRUFBRSxVQUFVLENBQUMsS0FBSyxDQUFDO1FBQ3JCLElBQUksRUFBRSxpQkFBaUI7UUFDdkIsYUFBYSxFQUFFLENBQUM7UUFDaEIsT0FBTyxFQUFFLENBQUM7UUFDVixNQUFNLEVBQUUsRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFO1FBQy9ELFVBQVUsRUFBRSxFQUFFO1FBQ2QsVUFBVSxFQUFFLEVBQUU7UUFDZCxXQUFXLEVBQUUsRUFBRTtLQUNoQixDQUFDLENBQUM7SUFFSCxzQ0FBc0M7SUFDN0IsbUJBQW1CLEdBQUcsTUFBTSxDQUFnQixJQUFJLENBQUMsQ0FBQztJQUUzRCxpQ0FBaUM7SUFDeEIsU0FBUyxHQUFHLE1BQU0sQ0FBb0IsWUFBWSxDQUFDLENB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O1FBQ3ZCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUVPLFdBQVcsQ0FBQyxHQUFxQjtRQUN2QyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsWUFBWSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDckUsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2xELElBQUksV0FBVyxDQUFDLE1BQU0sR0FBRyxXQUFXLEVBQUUsQ0FBQztZQUNyQyxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdEIsQ0FBQztRQUNELElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzlCLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDaEQsQ0FBQzt3R0E3VVUsb0JBQW9COzRHQUFwQixvQkFBb0I7OzRGQUFwQixvQkFBb0I7a0JBRGhDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjb21wdXRlZCwgaW5qZWN0LCBJbmplY3RhYmxlLCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFJlcG9ydERlZmluaXRpb24gfSBmcm9tICcuLi8uLi8uLi9jb3JlL21vZGVscy9yZXBvcnQtZGVmaW5pdGlvbi5tb2RlbCc7XG5pbXBvcnQgeyBSZXBvcnRDb21wb25lbnREZWZpbml0aW9uIH0gZnJvbSAnLi4vLi4vLi4vY29yZS9tb2RlbHMvcmVwb3J0LWNvbXBvbmVudC5tb2RlbCc7XG5pbXBvcnQgeyBDb21wb25lbnRMYXlvdXREZWZpbml0aW9uIH0gZnJvbSAnLi4vLi4vLi4vY29yZS9tb2RlbHMvcmVwb3J0LWxheW91dC5tb2RlbCc7XG5pbXBvcnQgeyBSZXBvcnRHcmlkRGVmaW5pdGlvbiB9IGZyb20gJy4uLy4uLy4uL2NvcmUvbW9kZWxzL3JlcG9ydC1ncmlkLm1vZGVsJztcbmltcG9ydCB7IENvbXBvbmVudFJlZ2lzdHJ5IH0gZnJvbSAnLi4vLi4vLi4vY29yZS9yZWdpc3RyeS9jb21wb25lbnQtcmVnaXN0cnknO1xuaW1wb3J0IHsgZ2VuZXJhdGVJZCB9IGZyb20gJy4uLy4uLy4uL2NvcmUvdXRpbGl0aWVzL2lkLWdlbmVyYXRvcic7XG5cbmV4cG9ydCB0eXBlIERlc2lnbmVyVmlld01vZGUgPSAnZGVzaWduJyB8ICdwcmV2aWV3JyB8ICdqc29uJztcbmV4cG9ydCB0eXBlIERlc2lnbmVyQWN0aXZlVGFiID0gJ3Byb3BlcnRpZXMnIHwgJ3JlcG9ydCcgfCAnZ3JpZCc7XG5cbmNvbnN0IE1BWF9ISVNUT1JZID0gMzA7XG5cbi8qKlxuICogRGVzaWduZXJTdGF0ZVNlcnZpY2UgY29vcmRpbmF0ZXMgc3RhdGUgZm9yIHRoZSB2aXN1YWwgcmVwb3J0IGRlc2lnbmVyLlxuICpcbiAqIFNjb3BlZCBhdCB0aGUgRGVzaWduZXIgY29tcG9uZW50IGxldmVsIChub3Qgcm9vdCkgdG8gZW5zdXJlIG11bHRpcGxlIGRlc2lnbmVyXG4gKiBpbnN0YW5jZXMgb3IgbmF2aWdhdGlvbiBmbG93cyByZW1haW4gc3RyaWN0bHkgaXNvbGF0ZWQuXG4gKi9cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBEZXNpZ25lclN0YXRlU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVnaXN0cnkgPSBpbmplY3QoQ29tcG9uZW50UmVnaXN0cnkpO1xuXG4gIC8qKiBDdXJyZW50IGFjdGl2ZSByZXBvcnQgZGVmaW5pdGlvbiAqL1xuICByZWFkb25seSBkZWZpbml0aW9uID0gc2lnbmFsPFJlcG9ydERlZmluaXRpb24+KHtcbiAgICBpZDogZ2VuZXJhdGVJZCgncnB0JyksXG4gICAgbmFtZTogJ1VudGl0bGVkIFJlcG9ydCcsXG4gICAgc2NoZW1hVmVyc2lvbjogMSxcbiAgICB2ZXJzaW9uOiAxLFxuICAgIGxheW91dDogeyBjb2x1bW5zOiAxMiwgZ2FwOiAxNiwgcGFkZGluZzogMjQsIGRpcmVjdGlvbjogJ2x0cicgfSxcbiAgICBjb21wb25lbnRzOiBbXSxcbiAgICBwYXJhbWV0ZXJzOiBbXSxcbiAgICBkYXRhU291cmNlczogW10sXG4gIH0pO1xuXG4gIC8qKiBTZWxlY3RlZCBjb21wb25lbnQgSUQgaW4gY2FudmFzICovXG4gIHJlYWRvbmx5IHNlbGVjdGVkQ29tcG9uZW50SWQgPSBzaWduYWw8c3RyaW5nIHwgbnVsbD4obnVsbCk7XG5cbiAgLyoqIEFjdGl2ZSBwcm9wZXJ0eSBlZGl0b3IgdGFiICovXG4gIHJlYWRvbmx5IGFjdGl2ZVRhYiA9IHNpZ25hbDxEZXNpZ25lckFjdGl2ZVRhYj4oJ3Byb3BlcnRpZXMnKTtcblxuICAvKiogQ3VycmVudCB2aWV3IG1vZGUgKGRlc2lnbiwgcHJldmlldywgb3IgcmF3IGpzb24pICovXG4gIHJlYWRvbmx5IHZpZXdNb2RlID0gc2lnbmFsPERlc2lnbmVyVmlld01vZGU+KCdkZXNpZ24nKTtcblxuICAvKiogRGlydHkgZmxhZyBpbmRpY2F0aW5nIHVuc2F2ZWQgY2hhbmdlcyAqL1xuICByZWFkb25seSBpc0RpcnR5ID0gc2lnbmFsPGJvb2xlYW4+KGZhbHNlKTtcblxuICAvLyBIaXN0b3J5IHN0YWNrIGZvciBVbmRvIC8gUmVkb1xuICBwcml2YXRlIHJlYWRvbmx5IGhpc3RvcnkgPSBzaWduYWw8UmVwb3J0RGVmaW5pdGlvbltdPihbXSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgaGlzdG9yeUluZGV4ID0gc2lnbmFsPG51bWJlcj4oLTEpO1xuXG4gIHJlYWRvbmx5IGNhblVuZG8gPSBjb21wdXRlZCgoKSA9PiB0aGlzLmhpc3RvcnlJbmRleCgpID4gMCk7XG4gIHJlYWRvbmx5IGNhblJlZG8gPSBjb21wdXRlZCgoKSA9PiB0aGlzLmhpc3RvcnlJbmRleCgpID49IDAgJiYgdGhpcy5oaXN0b3J5SW5kZXgoKSA8IHRoaXMuaGlzdG9yeSgpLmxlbmd0aCAtIDEpO1xuXG4gIC8qKiBDdXJyZW50bHkgc2VsZWN0ZWQgY29tcG9uZW50IGluc3RhbmNlLCBvciBudWxsIGlmIG5vbmUgKi9cbiAgcmVhZG9ubHkgc2VsZWN0ZWRDb21wb25lbnQgPSBjb21wdXRlZDxSZXBvcnRDb21wb25lbnREZWZpbml0aW9uIHwgbnVsbD4oKCkgPT4ge1xuICAgIGNvbnN0IGlkID0gdGhpcy5zZWxlY3RlZENvbXBvbmVudElkKCk7XG4gICAgaWYgKCFpZCkgcmV0dXJuIG51bGw7XG4gICAgcmV0dXJuIHRoaXMuZGVmaW5pdGlvbigpLmNvbXBvbmVudHMuZmluZCgoYykgPT4gYy5pZCA9PT0gaWQpID8/IG51bGw7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplcyBvciByZWxvYWRzIGEgcmVwb3J0IGRlZmluaXRpb24gaW50byB0aGUgZGVzaWduZXIuXG4gICAqL1xuICBsb2FkRGVmaW5pdGlvbihkZWY6IFJlcG9ydERlZmluaXRpb24pOiB2b2lkIHtcbiAgICBjb25zdCBjbG9uZWQgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGRlZikpIGFzIFJlcG9ydERlZmluaXRpb247XG4gICAgdGhpcy5kZWZpbml0aW9uLnNldChjbG9uZWQpO1xuICAgIHRoaXMuc2VsZWN0ZWRDb21wb25lbnRJZC5zZXQobnVsbCk7XG4gICAgdGhpcy5pc0RpcnR5LnNldChmYWxzZSk7XG4gICAgdGhpcy5oaXN0b3J5LnNldChbSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShjbG9uZWQpKV0pO1xuICAgIHRoaXMuaGlzdG9yeUluZGV4LnNldCgwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZWxlY3RzIGEgY29tcG9uZW50IGZvciBwcm9wZXJ0eSBlZGl0aW5nLlxuICAgKi9cbiAgc2VsZWN0Q29tcG9uZW50KGlkOiBzdHJpbmcgfCBudWxsKTogdm9pZCB7XG4gICAgdGhpcy5zZWxlY3RlZENvbXBvbmVudElkLnNldChpZCk7XG4gICAgaWYgKGlkKSB7XG4gICAgICB0aGlzLmFjdGl2ZVRhYi5zZXQoJ3Byb3BlcnRpZXMnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGUgYWN0aXZlIHZpZXcgbW9kZSAoZGVzaWduLCBsaXZlIHByZXZpZXcsIGpzb24gc2NoZW1hKS5cbiAgICovXG4gIHNldFZpZXdNb2RlKG1vZGU6IERlc2lnbmVyVmlld01vZGUpOiB2b2lkIHtcbiAgICB0aGlzLnZpZXdNb2RlLnNldChtb2RlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBhY3RpdmUgZWRpdG9yIHRhYi5cbiAgICovXG4gIHNldEFjdGl2ZVRhYih0YWI6IERlc2lnbmVyQWN0aXZlVGFiKTogdm9pZCB7XG4gICAgdGhpcy5hY3RpdmVUYWIuc2V0KHRhYik7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIG5ldyBjb21wb25lbnQgb2YgdGhlIHNwZWNpZmllZCB0eXBlIG9udG8gdGhlIGNhbnZhcy5cbiAgICovXG4gIGFkZENvbXBvbmVudCh0eXBlOiBzdHJpbmcsIHRhcmdldEluZGV4PzogbnVtYmVyKTogUmVwb3J0Q29tcG9uZW50RGVmaW5pdGlvbiB7XG4gICAgY29uc3QgbWV0YSA9IHRoaXMucmVnaXN0cnkucmVzb2x2ZSh0eXBlKTtcbiAgICBjb25zdCBkZWZhdWx0Q29uZmlnID0gbWV0YT8uY3JlYXRlRGVmYXVsdENvbmZpZygpID8/IHtcbiAgICAgIGlkOiBnZW5lcmF0ZUlkKHR5cGUpLFxuICAgICAgdHlwZSxcbiAgICAgIGxhYmVsOiBtZXRhPy5kaXNwbGF5TmFtZSA/PyB0eXBlLFxuICAgICAga2V5OiBgJHt0eXBlfV8ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cmluZygyLCA2KX1gLFxuICAgIH07XG5cbiAgICBjb25zdCBuZXdDb21wb25lbnQ6IFJlcG9ydENvbXBvbmVudERlZmluaXRpb24gPSB7XG4gICAgICBpZDogZ2VuZXJhdGVJZCh0eXBlKSxcbiAgICAgIHR5cGUsXG4gICAgICBsYWJlbDogZGVmYXVsdENvbmZpZy5sYWJlbCA/PyBtZXRhPy5kaXNwbGF5TmFtZSA/PyB0eXBlLFxuICAgICAga2V5OiBkZWZhdWx0Q29uZmlnLmtleSA/PyBgJHt0eXBlfV8ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cmluZygyLCA2KX1gLFxuICAgICAgb3JkZXI6IDAsXG4gICAgICBsYXlvdXQ6IHtcbiAgICAgICAgY29sdW1uU3BhbjogZGVmYXVsdENvbmZpZy5sYXlvdXQ/LmNvbHVtblNwYW4gPz8gKHR5cGUgPT09ICdidXR0b24nID8gMiA6IDQpLFxuICAgICAgICAuLi5kZWZhdWx0Q29uZmlnLmxheW91dCxcbiAgICAgIH0sXG4gICAgICBwcm9wZXJ0aWVzOiB7IC4uLihkZWZhdWx0Q29uZmlnLnByb3BlcnRpZXMgPz8ge30pIH0sXG4gICAgICB2YWxpZGF0aW9uOiBkZWZhdWx0Q29uZmlnLnZhbGlkYXRpb24gPyB7IC4uLmRlZmF1bHRDb25maWcudmFsaWRhdGlvbiB9IDogdW5kZWZpbmVkLFxuICAgICAgZGF0YVNvdXJjZTogZGVmYXVsdENvbmZpZy5kYXRhU291cmNlID8geyAuLi5kZWZhdWx0Q29uZmlnLmRhdGFTb3VyY2UgfSA6IHVuZGVmaW5lZCxcbiAgICAgIGVuYWJsZWQ6IGRlZmF1bHRDb25maWcuZW5hYmxlZCA/PyB0cnVlLFxuICAgIH07XG5cbiAgICBjb25zdCBjdXJyZW50Q29tcG9uZW50cyA9IFsuLi50aGlzLmRlZmluaXRpb24oKS5jb21wb25lbnRzXS5zb3J0KFxuICAgICAgKGEsIGIpID0+IChhLm9yZGVyID8/IDApIC0gKGIub3JkZXIgPz8gMClcbiAgICApO1xuICAgIGlmICh0YXJnZXRJbmRleCAhPT0gdW5kZWZpbmVkICYmIHRhcmdldEluZGV4ID49IDAgJiYgdGFyZ2V0SW5kZXggPD0gY3VycmVudENvbXBvbmVudHMubGVuZ3RoKSB7XG4gICAgICBjdXJyZW50Q29tcG9uZW50cy5zcGxpY2UodGFyZ2V0SW5kZXgsIDAsIG5ld0NvbXBvbmVudCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGN1cnJlbnRDb21wb25lbnRzLnB1c2gobmV3Q29tcG9uZW50KTtcbiAgICB9XG5cbiAgICAvLyBSZWNhbGN1bGF0ZSBvcmRlciBpbmRpY2VzXG4gICAgY3VycmVudENvbXBvbmVudHMuZm9yRWFjaCgoYywgaWR4KSA9PiAoYy5vcmRlciA9IGlkeCArIDEpKTtcblxuICAgIHRoaXMubXV0YXRlRGVmaW5pdGlvbigoZGVmKSA9PiAoe1xuICAgICAgLi4uZGVmLFxuICAgICAgY29tcG9uZW50czogY3VycmVudENvbXBvbmVudHMsXG4gICAgfSkpO1xuXG4gICAgdGhpcy5zZWxlY3RDb21wb25lbnQobmV3Q29tcG9uZW50LmlkKTtcbiAgICByZXR1cm4gbmV3Q29tcG9uZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYSBjb21wb25lbnQgYnkgaXRzIElELlxuICAgKi9cbiAgcmVtb3ZlQ29tcG9uZW50KGlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBjdXJyZW50Q29tcG9uZW50cyA9IHRoaXMuZGVmaW5pdGlvbigpLmNvbXBvbmVudHMuZmlsdGVyKChjKSA9PiBjLmlkICE9PSBpZCk7XG4gICAgY3VycmVudENvbXBvbmVudHMuZm9yRWFjaCgoYywgaWR4KSA9PiAoYy5vcmRlciA9IGlkeCArIDEpKTtcblxuICAgIGlmICh0aGlzLnNlbGVjdGVkQ29tcG9uZW50SWQoKSA9PT0gaWQpIHtcbiAgICAgIHRoaXMuc2VsZWN0ZWRDb21wb25lbnRJZC5zZXQobnVsbCk7XG4gICAgfVxuXG4gICAgdGhpcy5tdXRhdGVEZWZpbml0aW9uKChkZWYpID0+ICh7XG4gICAgICAuLi5kZWYsXG4gICAgICBjb21wb25lbnRzOiBjdXJyZW50Q29tcG9uZW50cyxcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogRHVwbGljYXRlcyBhbiBleGlzdGluZyBjb21wb25lbnQuXG4gICAqL1xuICBkdXBsaWNhdGVDb21wb25lbnQoaWQ6IHN0cmluZyk6IFJlcG9ydENvbXBvbmVudERlZmluaXRpb24gfCBudWxsIHtcbiAgICBjb25zdCBleGlzdGluZyA9IHRoaXMuZGVmaW5pdGlvbigpLmNvbXBvbmVudHMuZmluZCgoYykgPT4gYy5pZCA9PT0gaWQpO1xuICAgIGlmICghZXhpc3RpbmcpIHJldHVybiBudWxsO1xuXG4gICAgY29uc3QgZHVwbGljYXRlZDogUmVwb3J0Q29tcG9uZW50RGVmaW5pdGlvbiA9IHtcbiAgICAgIC4uLkpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZXhpc3RpbmcpKSxcbiAgICAgIGlkOiBnZW5lcmF0ZUlkKGV4aXN0aW5nLnR5cGUpLFxuICAgICAga2V5OiBleGlzdGluZy5rZXkgPyBgJHtleGlzdGluZy5rZXl9X2NvcHlgIDogdW5kZWZpbmVkLFxuICAgICAgbGFiZWw6IGV4aXN0aW5nLmxhYmVsID8gYCR7ZXhpc3RpbmcubGFiZWx9IChDb3B5KWAgOiB1bmRlZmluZWQsXG4gICAgfTtcblxuICAgIGNvbnN0IGN1cnJlbnRDb21wb25lbnRzID0gWy4uLnRoaXMuZGVmaW5pdGlvbigpLmNvbXBvbmVudHNdLnNvcnQoXG4gICAgICAoYSwgYikgPT4gKGEub3JkZXIgPz8gMCkgLSAoYi5vcmRlciA/PyAwKVxuICAgICk7XG4gICAgY29uc3QgaW5kZXggPSBjdXJyZW50Q29tcG9uZW50cy5maW5kSW5kZXgoKGMpID0+IGMuaWQgPT09IGlkKTtcbiAgICBjdXJyZW50Q29tcG9uZW50cy5zcGxpY2UoaW5kZXggKyAxLCAwLCBkdXBsaWNhdGVkKTtcbiAgICBjdXJyZW50Q29tcG9uZW50cy5mb3JFYWNoKChjLCBpZHgpID0+IChjLm9yZGVyID0gaWR4ICsgMSkpO1xuXG4gICAgdGhpcy5tdXRhdGVEZWZpbml0aW9uKChkZWYpID0+ICh7XG4gICAgICAuLi5kZWYsXG4gICAgICBjb21wb25lbnRzOiBjdXJyZW50Q29tcG9uZW50cyxcbiAgICB9KSk7XG5cbiAgICB0aGlzLnNlbGVjdENvbXBvbmVudChkdXBsaWNhdGVkLmlkKTtcbiAgICByZXR1cm4gZHVwbGljYXRlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb3ZlcyBhIGNvbXBvbmVudCBmcm9tIHByZXZpb3VzIGluZGV4IHRvIGN1cnJlbnQgaW5kZXggKGUuZy4gZnJvbSBDREsgZHJhZyBkcm9wKS5cbiAgICovXG4gIG1vdmVDb21wb25lbnQocHJldmlvdXNJbmRleDogbnVtYmVyLCBjdXJyZW50SW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIGlmIChwcmV2aW91c0luZGV4ID09PSBjdXJyZW50SW5kZXgpIHJldHVybjtcblxuICAgIGNvbnN0IGN1cnJlbnRDb21wb25lbnRzID0gWy4uLnRoaXMuZGVmaW5pdGlvbigpLmNvbXBvbmVudHNdLnNvcnQoXG4gICAgICAoYSwgYikgPT4gKGEub3JkZXIgPz8gMCkgLSAoYi5vcmRlciA/PyAwKVxuICAgICk7XG4gICAgaWYgKHByZXZpb3VzSW5kZXggPCAwIHx8IHByZXZpb3VzSW5kZXggPj0gY3VycmVudENvbXBvbmVudHMubGVuZ3RoKSByZXR1cm47XG4gICAgY29uc3QgdGFyZ2V0SWR4ID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oY3VycmVudEluZGV4LCBjdXJyZW50Q29tcG9uZW50cy5sZW5ndGggLSAxKSk7XG5cbiAgICBjb25zdCBbbW92ZWRdID0gY3VycmVudENvbXBvbmVudHMuc3BsaWNlKHByZXZpb3VzSW5kZXgsIDEpO1xuICAgIGN1cnJlbnRDb21wb25lbnRzLnNwbGljZSh0YXJnZXRJZHgsIDAsIG1vdmVkKTtcbiAgICBjdXJyZW50Q29tcG9uZW50cy5mb3JFYWNoKChjLCBpZHgpID0+IChjLm9yZGVyID0gaWR4ICsgMSkpO1xuXG4gICAgdGhpcy5tdXRhdGVEZWZpbml0aW9uKChkZWYpID0+ICh7XG4gICAgICAuLi5kZWYsXG4gICAgICBjb21wb25lbnRzOiBjdXJyZW50Q29tcG9uZW50cyxcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyBwYXJ0aWFsIHByb3BlcnRpZXMgb2YgYSBjb21wb25lbnQuXG4gICAqL1xuICB1cGRhdGVDb21wb25lbnQoaWQ6IHN0cmluZywgdXBkYXRlczogUGFydGlhbDxSZXBvcnRDb21wb25lbnREZWZpbml0aW9uPik6IHZvaWQge1xuICAgIGNvbnN0IGN1cnJlbnRDb21wb25lbnRzID0gdGhpcy5kZWZpbml0aW9uKCkuY29tcG9uZW50cy5tYXAoKGMpID0+IHtcbiAgICAgIGlmIChjLmlkID09PSBpZCkge1xuICAgICAgICByZXR1cm4geyAuLi5jLCAuLi51cGRhdGVzIH07XG4gICAgICB9XG4gICAgICByZXR1cm4gYztcbiAgICB9KTtcblxuICAgIHRoaXMubXV0YXRlRGVmaW5pdGlvbigoZGVmKSA9PiAoe1xuICAgICAgLi4uZGVmLFxuICAgICAgY29tcG9uZW50czogY3VycmVudENvbXBvbmVudHMsXG4gICAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgYSBzaW5nbGUgY29tcG9uZW50IHByb3BlcnR5IHZhbHVlIHdpdGhpbiBgcHJvcGVydGllc2AuXG4gICAqL1xuICB1cGRhdGVDb21wb25lbnRQcm9wZXJ0eShpZDogc3RyaW5nLCBwcm9wS2V5OiBzdHJpbmcsIHZhbHVlOiB1bmtub3duKTogdm9pZCB7XG4gICAgY29uc3QgY3VycmVudENvbXBvbmVudHMgPSB0aGlzLmRlZmluaXRpb24oKS5jb21wb25lbnRzLm1hcCgoYykgPT4ge1xuICAgICAgaWYgKGMuaWQgPT09IGlkKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgLi4uYyxcbiAgICAgICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICAuLi4oYy5wcm9wZXJ0aWVzID8/IHt9KSxcbiAgICAgICAgICAgIFtwcm9wS2V5XTogdmFsdWUsXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjO1xuICAgIH0pO1xuXG4gICAgdGhpcy5tdXRhdGVEZWZpbml0aW9uKChkZWYpID0+ICh7XG4gICAgICAuLi5kZWYsXG4gICAgICBjb21wb25lbnRzOiBjdXJyZW50Q29tcG9uZW50cyxcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyBsYXlvdXQgcHJvcGVydGllcyBmb3IgYSBjb21wb25lbnQgKGUuZy4gY29sdW1uU3BhbikuXG4gICAqL1xuICB1cGRhdGVDb21wb25lbnRMYXlvdXQoaWQ6IHN0cmluZywgbGF5b3V0OiBQYXJ0aWFsPENvbXBvbmVudExheW91dERlZmluaXRpb24+KTogdm9pZCB7XG4gICAgY29uc3QgY3VycmVudENvbXBvbmVudHMgPSB0aGlzLmRlZmluaXRpb24oKS5jb21wb25lbnRzLm1hcCgoYykgPT4ge1xuICAgICAgaWYgKGMuaWQgPT09IGlkKSB7XG4gICAgICAgIGNvbnN0IG5leHRMYXlvdXQgPSB7XG4gICAgICAgICAgLi4uKGMubGF5b3V0ID8/IHt9KSxcbiAgICAgICAgICAuLi5sYXlvdXQsXG4gICAgICAgIH07XG4gICAgICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGxheW91dCkgYXMgKGtleW9mIENvbXBvbmVudExheW91dERlZmluaXRpb24pW10pIHtcbiAgICAgICAgICBpZiAobGF5b3V0W2tleV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZGVsZXRlIG5leHRMYXlvdXRba2V5XTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAuLi5jLFxuICAgICAgICAgIGxheW91dDogbmV4dExheW91dCxcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjO1xuICAgIH0pO1xuXG4gICAgdGhpcy5tdXRhdGVEZWZpbml0aW9uKChkZWYpID0+ICh7XG4gICAgICAuLi5kZWYsXG4gICAgICBjb21wb25lbnRzOiBjdXJyZW50Q29tcG9uZW50cyxcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyByZXBvcnQtbGV2ZWwgc2V0dGluZ3MgKG5hbWUsIGRlc2NyaXB0aW9uLCBsYXlvdXQpLlxuICAgKi9cbiAgdXBkYXRlUmVwb3J0U2V0dGluZ3Moc2V0dGluZ3M6IFBhcnRpYWw8UmVwb3J0RGVmaW5pdGlvbj4pOiB2b2lkIHtcbiAgICB0aGlzLm11dGF0ZURlZmluaXRpb24oKGRlZikgPT4gKHtcbiAgICAgIC4uLmRlZixcbiAgICAgIC4uLnNldHRpbmdzLFxuICAgIH0pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIGdyaWQgZGVmaW5pdGlvbiBzZXR0aW5ncy5cbiAgICovXG4gIHVwZGF0ZUdyaWRTZXR0aW5ncyhncmlkOiBSZXBvcnRHcmlkRGVmaW5pdGlvbiB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIHRoaXMubXV0YXRlRGVmaW5pdGlvbigoZGVmKSA9PiAoe1xuICAgICAgLi4uZGVmLFxuICAgICAgZ3JpZCxcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogUmV2ZXJ0cyB0byB0aGUgcHJldmlvdXMgc3RhdGUgaW4gaGlzdG9yeS5cbiAgICovXG4gIHVuZG8oKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmNhblVuZG8oKSkgcmV0dXJuO1xuICAgIGNvbnN0IG5ld0luZGV4ID0gdGhpcy5oaXN0b3J5SW5kZXgoKSAtIDE7XG4gICAgdGhpcy5oaXN0b3J5SW5kZXguc2V0KG5ld0luZGV4KTtcbiAgICBjb25zdCByZXN0b3JlZCA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkodGhpcy5oaXN0b3J5KClbbmV3SW5kZXhdKSkgYXMgUmVwb3J0RGVmaW5pdGlvbjtcbiAgICB0aGlzLmRlZmluaXRpb24uc2V0KHJlc3RvcmVkKTtcbiAgICB0aGlzLmlzRGlydHkuc2V0KHRydWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkdmFuY2VzIHRvIHRoZSBuZXh0IHN0YXRlIGluIGhpc3RvcnkuXG4gICAqL1xuICByZWRvKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5jYW5SZWRvKCkpIHJldHVybjtcbiAgICBjb25zdCBuZXdJbmRleCA9IHRoaXMuaGlzdG9yeUluZGV4KCkgKyAxO1xuICAgIHRoaXMuaGlzdG9yeUluZGV4LnNldChuZXdJbmRleCk7XG4gICAgY29uc3QgcmVzdG9yZWQgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KHRoaXMuaGlzdG9yeSgpW25ld0luZGV4XSkpIGFzIFJlcG9ydERlZmluaXRpb247XG4gICAgdGhpcy5kZWZpbml0aW9uLnNldChyZXN0b3JlZCk7XG4gICAgdGhpcy5pc0RpcnR5LnNldCh0cnVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNYXJrcyB0aGUgY3VycmVudCBkZWZpbml0aW9uIHN0YXRlIGFzIHNhdmVkLlxuICAgKi9cbiAgbWFya1NhdmVkKCk6IHZvaWQge1xuICAgIHRoaXMuaXNEaXJ0eS5zZXQoZmFsc2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFwcGxpZXMgYW4gaW1tdXRhYmxlIHN0YXRlIGNoYW5nZSBhbmQgcHVzaGVzIHRvIGhpc3RvcnkuXG4gICAqL1xuICBwcml2YXRlIG11dGF0ZURlZmluaXRpb24odXBkYXRlcjogKGN1cnJlbnQ6IFJlcG9ydERlZmluaXRpb24pID0+IFJlcG9ydERlZmluaXRpb24pOiB2b2lkIHtcbiAgICBjb25zdCBuZXh0ID0gdXBkYXRlcih0aGlzLmRlZmluaXRpb24oKSk7XG4gICAgdGhpcy5kZWZpbml0aW9uLnNldChuZXh0KTtcbiAgICB0aGlzLmlzRGlydHkuc2V0KHRydWUpO1xuICAgIHRoaXMucHVzaEhpc3RvcnkobmV4dCk7XG4gIH1cblxuICBwcml2YXRlIHB1c2hIaXN0b3J5KGRlZjogUmVwb3J0RGVmaW5pdGlvbik6IHZvaWQge1xuICAgIGNvbnN0IGN1cnJlbnRIaXN0ID0gdGhpcy5oaXN0b3J5KCkuc2xpY2UoMCwgdGhpcy5oaXN0b3J5SW5kZXgoKSArIDEpO1xuICAgIGN1cnJlbnRIaXN0LnB1c2goSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShkZWYpKSk7XG4gICAgaWYgKGN1cnJlbnRIaXN0Lmxlbmd0aCA+IE1BWF9ISVNUT1JZKSB7XG4gICAgICBjdXJyZW50SGlzdC5zaGlmdCgpO1xuICAgIH1cbiAgICB0aGlzLmhpc3Rvcnkuc2V0KGN1cnJlbnRIaXN0KTtcbiAgICB0aGlzLmhpc3RvcnlJbmRleC5zZXQoY3VycmVudEhpc3QubGVuZ3RoIC0gMSk7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,2 @@
1
+ export { DesignerStateService } from './designer-state.service';
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9id2F5cy1yZXBvcnQvc3JjL2xpYi9mZWF0dXJlcy9kZXNpZ25lci9zZXJ2aWNlcy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB7IERlc2lnbmVyU3RhdGVTZXJ2aWNlIH0gZnJvbSAnLi9kZXNpZ25lci1zdGF0ZS5zZXJ2aWNlJztcbmV4cG9ydCB0eXBlIHtcbiAgRGVzaWduZXJWaWV3TW9kZSxcbiAgRGVzaWduZXJBY3RpdmVUYWIsXG59IGZyb20gJy4vZGVzaWduZXItc3RhdGUuc2VydmljZSc7XG4iXX0=
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Pure utility functions for design canvas layout, grid calculations, and sizing.
3
+ *
4
+ * Implemented as framework-independent pure functions per Rule 10 & 11 (Pure Logic First).
5
+ */
6
+ /**
7
+ * Resolves the effective column span for a component.
8
+ * Uses layout.columnSpan if specified, otherwise defaults based on component type (e.g. 2 for button, 4 for others).
9
+ */
10
+ export function resolveComponentSpan(comp, totalColumns = 12, overrideSpan) {
11
+ if (overrideSpan !== undefined && overrideSpan !== null) {
12
+ return Math.max(1, Math.min(totalColumns, overrideSpan));
13
+ }
14
+ const defaultSpan = comp.type === 'button' ? 2 : 4;
15
+ const rawSpan = comp.layout?.columnSpan ?? defaultSpan;
16
+ return Math.max(1, Math.min(totalColumns, rawSpan));
17
+ }
18
+ /**
19
+ * Computes the CSS `grid-column` specification string for a component.
20
+ */
21
+ export function calculateGridColumn(comp, totalColumns = 12, span) {
22
+ const effectiveSpan = span ?? resolveComponentSpan(comp, totalColumns);
23
+ const clamped = Math.max(1, Math.min(effectiveSpan, totalColumns));
24
+ const col = comp.layout?.column;
25
+ if (col && col >= 1 && col <= totalColumns) {
26
+ return `${col} / span ${clamped}`;
27
+ }
28
+ return comp.layout?.newRow ? `1 / span ${clamped}` : `span ${clamped}`;
29
+ }
30
+ /**
31
+ * Computes the CSS `grid-row` specification string for a component.
32
+ */
33
+ export function calculateGridRow(comp) {
34
+ const rowSpan = comp.layout?.rowSpan;
35
+ if (rowSpan && rowSpan > 1) {
36
+ return `span ${rowSpan}`;
37
+ }
38
+ return 'auto';
39
+ }
40
+ /**
41
+ * Overhead in pixels for the Visual Canvas card (card header 32px + card body vertical padding 16px).
42
+ * Adding this overhead to the component's logical height ensures that the canvas card body
43
+ * renders at the exact same pixel dimensions as the live preview component.
44
+ */
45
+ export const CANVAS_CARD_OVERHEAD = 48;
46
+ /**
47
+ * Resolves the CSS height property for the canvas component card.
48
+ * Accounts for the card header and padding overhead so the inner mock body
49
+ * accurately mirrors the runtime component height.
50
+ */
51
+ export function resolveCanvasCardHeight(comp, overrideComponentHeight, overhead = CANVAS_CARD_OVERHEAD) {
52
+ if (overrideComponentHeight !== undefined && overrideComponentHeight !== null) {
53
+ return `${overrideComponentHeight + overhead}px`;
54
+ }
55
+ const h = comp.layout?.height;
56
+ if (!h || h === 'auto')
57
+ return 'auto';
58
+ const parsed = parseInt(h, 10);
59
+ return isNaN(parsed) ? h : `${parsed + overhead}px`;
60
+ }
61
+ /**
62
+ * Resolves the CSS min-height property for the canvas component card.
63
+ */
64
+ export function resolveCanvasCardMinHeight(comp, overrideComponentHeight, overhead = CANVAS_CARD_OVERHEAD) {
65
+ if (overrideComponentHeight !== undefined && overrideComponentHeight !== null) {
66
+ return `${overrideComponentHeight + overhead}px`;
67
+ }
68
+ const minH = comp.layout?.minHeight;
69
+ if (!minH || minH === 'auto')
70
+ return 'auto';
71
+ const parsed = parseInt(minH, 10);
72
+ return isNaN(parsed) ? minH : `${parsed + overhead}px`;
73
+ }
74
+ /**
75
+ * Resolves the CSS height property for a runtime component.
76
+ */
77
+ export function resolveComponentHeight(comp, overrideHeight) {
78
+ if (overrideHeight !== undefined && overrideHeight !== null) {
79
+ return `${overrideHeight}px`;
80
+ }
81
+ return comp.layout?.height || 'auto';
82
+ }
83
+ /**
84
+ * Resolves the CSS min-height property for a runtime component.
85
+ */
86
+ export function resolveComponentMinHeight(comp, overrideHeight) {
87
+ if (overrideHeight !== undefined && overrideHeight !== null) {
88
+ return `${overrideHeight}px`;
89
+ }
90
+ return comp.layout?.minHeight || 'auto';
91
+ }
92
+ /**
93
+ * Calculates new snapped span given drag deltaX, column width, and grid gap.
94
+ */
95
+ export function calculateSnappedSpan(deltaX, startSpan, colWidth, gap, totalCols) {
96
+ const step = colWidth + gap;
97
+ if (step <= 0)
98
+ return startSpan;
99
+ const spanDelta = Math.round(deltaX / step);
100
+ return Math.max(1, Math.min(totalCols, startSpan + spanDelta));
101
+ }
102
+ /**
103
+ * Calculates new height given drag deltaY and minimum height constraint.
104
+ */
105
+ export function calculateSnappedHeight(deltaY, startHeight, minHeight = 50) {
106
+ return Math.max(minHeight, Math.round(startHeight + deltaY));
107
+ }
108
+ /**
109
+ * Maps component type to standard icon identifier.
110
+ */
111
+ export function getComponentIconName(type) {
112
+ switch (type) {
113
+ case 'input': return 'text-fields';
114
+ case 'dropdown': return 'dropdown';
115
+ case 'date': return 'calendar';
116
+ case 'number': return 'number';
117
+ case 'checkbox': return 'checkbox';
118
+ case 'button': return 'button';
119
+ case 'kpi-card': return 'kpi';
120
+ case 'chart': return 'chart-bar';
121
+ default: return 'box';
122
+ }
123
+ }
124
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FudmFzLWxheW91dC51dGlsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYndheXMtcmVwb3J0L3NyYy9saWIvZmVhdHVyZXMvZGVzaWduZXIvdXRpbGl0aWVzL2NhbnZhcy1sYXlvdXQudXRpbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQTs7OztHQUlHO0FBRUg7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUNsQyxJQUErQixFQUMvQixlQUF1QixFQUFFLEVBQ3pCLFlBQTRCO0lBRTVCLElBQUksWUFBWSxLQUFLLFNBQVMsSUFBSSxZQUFZLEtBQUssSUFBSSxFQUFFLENBQUM7UUFDeEQsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDO0lBQzNELENBQUM7SUFDRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxVQUFVLElBQUksV0FBVyxDQUFDO0lBQ3ZELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztBQUN0RCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsbUJBQW1CLENBQ2pDLElBQStCLEVBQy9CLGVBQXVCLEVBQUUsRUFDekIsSUFBYTtJQUViLE1BQU0sYUFBYSxHQUFHLElBQUksSUFBSSxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDdkUsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdB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TyxRQUFRLENBQUM7UUFDL0IsS0FBSyxVQUFVLENBQUMsQ0FBQyxPQUFPLFVBQVUsQ0FBQztRQUNuQyxLQUFLLFFBQVEsQ0FBQyxDQUFDLE9BQU8sUUFBUSxDQUFDO1FBQy9CLEtBQUssVUFBVSxDQUFDLENBQUMsT0FBTyxLQUFLLENBQUM7UUFDOUIsS0FBSyxPQUFPLENBQUMsQ0FBQyxPQUFPLFdBQVcsQ0FBQztRQUNqQyxPQUFPLENBQUMsQ0FBQyxPQUFPLEtBQUssQ0FBQztJQUN4QixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlcG9ydENvbXBvbmVudERlZmluaXRpb24gfSBmcm9tICcuLi8uLi8uLi9jb3JlL21vZGVscy9yZXBvcnQtY29tcG9uZW50Lm1vZGVsJztcblxuLyoqXG4gKiBQdXJlIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBkZXNpZ24gY2FudmFzIGxheW91dCwgZ3JpZCBjYWxjdWxhdGlvbnMsIGFuZCBzaXppbmcuXG4gKlxuICogSW1wbGVtZW50ZWQgYXMgZnJhbWV3b3JrLWluZGVwZW5kZW50IHB1cmUgZnVuY3Rpb25zIHBlciBSdWxlIDEwICYgMTEgKFB1cmUgTG9naWMgRmlyc3QpLlxuICovXG5cbi8qKlxuICogUmVzb2x2ZXMgdGhlIGVmZmVjdGl2ZSBjb2x1bW4gc3BhbiBmb3IgYSBjb21wb25lbnQuXG4gKiBVc2VzIGxheW91dC5jb2x1bW5TcGFuIGlmIHNwZWNpZmllZCwgb3RoZXJ3aXNlIGRlZmF1bHRzIGJhc2VkIG9uIGNvbXBvbmVudCB0eXBlIChlLmcuIDIgZm9yIGJ1dHRvbiwgNCBmb3Igb3RoZXJzKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVDb21wb25lbnRTcGFuKFxuICBjb21wOiBSZXBvcnRDb21wb25lbnREZWZpbml0aW9uLFxuICB0b3RhbENvbHVtbnM6IG51bWJlciA9IDEyLFxuICBvdmVycmlkZVNwYW4/OiBudW1iZXIgfCBudWxsXG4pOiBudW1iZXIge1xuICBpZiAob3ZlcnJpZGVTcGFuICE9PSB1bmRlZmluZWQgJiYgb3ZlcnJpZGVTcGFuICE9PSBudWxsKSB7XG4gICAgcmV0dXJuIE1hdGgubWF4KDEsIE1hdGgubWluKHRvdGFsQ29sdW1ucywgb3ZlcnJpZGVTcGFuKSk7XG4gIH1cbiAgY29uc3QgZGVmYXVsdFNwYW4gPSBjb21wLnR5cGUgPT09ICdidXR0b24nID8gMiA6IDQ7XG4gIGNvbnN0IHJhd1NwYW4gPSBjb21wLmxheW91dD8uY29sdW1uU3BhbiA/PyBkZWZhdWx0U3BhbjtcbiAgcmV0dXJuIE1hdGgubWF4KDEsIE1hdGgubWluKHRvdGFsQ29sdW1ucywgcmF3U3BhbikpO1xufVxuXG4vKipcbiAqIENvbXB1dGVzIHRoZSBDU1MgYGdyaWQtY29sdW1uYCBzcGVjaWZpY2F0aW9uIHN0cmluZyBmb3IgYSBjb21wb25lbnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjYWxjdWxhdGVHcmlkQ29sdW1uKFxuICBjb21wOiBSZXBvcnRDb21wb25lbnREZWZpbml0aW9uLFxuICB0b3RhbENvbHVtbnM6IG51bWJlciA9IDEyLFxuICBzcGFuPzogbnVtYmVyXG4pOiBzdHJpbmcge1xuICBjb25zdCBlZmZlY3RpdmVTcGFuID0gc3BhbiA/PyByZXNvbHZlQ29tcG9uZW50U3Bhbihjb21wLCB0b3RhbENvbHVtbnMpO1xuICBjb25zdCBjbGFtcGVkID0gTWF0aC5tYXgoMSwgTWF0aC5taW4oZWZmZWN0aXZlU3BhbiwgdG90YWxDb2x1bW5zKSk7XG4gIGNvbnN0IGNvbCA9IGNvbXAubGF5b3V0Py5jb2x1bW47XG5cbiAgaWYgKGNvbCAmJiBjb2wgPj0gMSAmJiBjb2wgPD0gdG90YWxDb2x1bW5zKSB7XG4gICAgcmV0dXJuIGAke2NvbH0gLyBzcGFuICR7Y2xhbXBlZH1gO1xuICB9XG5cbiAgcmV0dXJuIGNvbXAubGF5b3V0Py5uZXdSb3cgPyBgMSAvIHNwYW4gJHtjbGFtcGVkfWAgOiBgc3BhbiAke2NsYW1wZWR9YDtcbn1cblxuLyoqXG4gKiBDb21wdXRlcyB0aGUgQ1NTIGBncmlkLXJvd2Agc3BlY2lmaWNhdGlvbiBzdHJpbmcgZm9yIGEgY29tcG9uZW50LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2FsY3VsYXRlR3JpZFJvdyhjb21wOiBSZXBvcnRDb21wb25lbnREZWZpbml0aW9uKTogc3RyaW5nIHtcbiAgY29uc3Qgcm93U3BhbiA9IGNvbXAubGF5b3V0Py5yb3dTcGFuO1xuICBpZiAocm93U3BhbiAmJiByb3dTcGFuID4gMSkge1xuICAgIHJldHVybiBgc3BhbiAke3Jvd1NwYW59YDtcbiAgfVxuICByZXR1cm4gJ2F1dG8nO1xufVxuXG4vKipcbiAqIE92ZXJoZWFkIGluIHBpeGVscyBmb3IgdGhlIFZpc3VhbCBDYW52YXMgY2FyZCAoY2FyZCBoZWFkZXIgMzJweCArIGNhcmQgYm9keSB2ZXJ0aWNhbCBwYWRkaW5nIDE2cHgpLlxuICogQWRkaW5nIHRoaXMgb3ZlcmhlYWQgdG8gdGhlIGNvbXBvbmVudCdzIGxvZ2ljYWwgaGVpZ2h0IGVuc3VyZXMgdGhhdCB0aGUgY2FudmFzIGNhcmQgYm9keVxuICogcmVuZGVycyBhdCB0aGUgZXhhY3Qgc2FtZSBwaXhlbCBkaW1lbnNpb25zIGFzIHRoZSBsaXZlIHByZXZpZXcgY29tcG9uZW50LlxuICovXG5leHBvcnQgY29uc3QgQ0FOVkFTX0NBUkRfT1ZFUkhFQUQgPSA0ODtcblxuLyoqXG4gKiBSZXNvbHZlcyB0aGUgQ1NTIGhlaWdodCBwcm9wZXJ0eSBmb3IgdGhlIGNhbnZhcyBjb21wb25lbnQgY2FyZC5cbiAqIEFjY291bnRzIGZvciB0aGUgY2FyZCBoZWFkZXIgYW5kIHBhZGRpbmcgb3ZlcmhlYWQgc28gdGhlIGlubmVyIG1vY2sgYm9keVxuICogYWNjdXJhdGVseSBtaXJyb3JzIHRoZSBydW50aW1lIGNvbXBvbmVudCBoZWlnaHQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQ2FudmFzQ2FyZEhlaWdodChcbiAgY29tcDogUmVwb3J0Q29tcG9uZW50RGVmaW5pdGlvbixcbiAgb3ZlcnJpZGVDb21wb25lbnRIZWlnaHQ/OiBudW1iZXIgfCBudWxsLFxuICBvdmVyaGVhZDogbnVtYmVyID0gQ0FOVkFTX0NBUkRfT1ZFUkhFQURcbik6IHN0cmluZyB7XG4gIGlmIChvdmVycmlkZUNvbXBvbmVudEhlaWdodCAhPT0gdW5kZWZpbmVkICYmIG92ZXJyaWRlQ29tcG9uZW50SGVpZ2h0ICE9PSBudWxsKSB7XG4gICAgcmV0dXJuIGAke292ZXJyaWRlQ29tcG9uZW50SGVpZ2h0ICsgb3ZlcmhlYWR9cHhgO1xuICB9XG4gIGNvbnN0IGggPSBjb21wLmxheW91dD8uaGVpZ2h0O1xuICBpZiAoIWggfHwgaCA9PT0gJ2F1dG8nKSByZXR1cm4gJ2F1dG8nO1xuICBjb25zdCBwYXJzZWQgPSBwYXJzZUludChoLCAxMCk7XG4gIHJldHVybiBpc05hTihwYXJzZWQpID8gaCA6IGAke3BhcnNlZCArIG92ZXJoZWFkfXB4YDtcbn1cblxuLyoqXG4gKiBSZXNvbHZlcyB0aGUgQ1NTIG1pbi1oZWlnaHQgcHJvcGVydHkgZm9yIHRoZSBjYW52YXMgY29tcG9uZW50IGNhcmQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQ2FudmFzQ2FyZE1pbkhlaWdodChcbiAgY29tcDogUmVwb3J0Q29tcG9uZW50RGVmaW5pdGlvbixcbiAgb3ZlcnJpZGVDb21wb25lbnRIZWlnaHQ/OiBudW1iZXIgfCBudWxsLFxuICBvdmVyaGVhZDogbnVtYmVyID0gQ0FOVkFTX0NBUkRfT1ZFUkhFQURcbik6IHN0cmluZyB7XG4gIGlmIChvdmVycmlkZUNvbXBvbmVudEhlaWdodCAhPT0gdW5kZWZpbmVkICYmIG92ZXJyaWRlQ29tcG9uZW50SGVpZ2h0ICE9PSBudWxsKSB7XG4gICAgcmV0dXJuIGAke292ZXJyaWRlQ29tcG9uZW50SGVpZ2h0ICsgb3ZlcmhlYWR9cHhgO1xuICB9XG4gIGNvbnN0IG1pbkggPSBjb21wLmxheW91dD8ubWluSGVpZ2h0O1xuICBpZiAoIW1pbkggfHwgbWluSCA9PT0gJ2F1dG8nKSByZXR1cm4gJ2F1dG8nO1xuICBjb25zdCBwYXJzZWQgPSBwYXJzZUludChtaW5ILCAxMCk7XG4gIHJldHVybiBpc05hTihwYXJzZWQpID8gbWluSCA6IGAke3BhcnNlZCArIG92ZXJoZWFkfXB4YDtcbn1cblxuLyoqXG4gKiBSZXNvbHZlcyB0aGUgQ1NTIGhlaWdodCBwcm9wZXJ0eSBmb3IgYSBydW50aW1lIGNvbXBvbmVudC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVDb21wb25lbnRIZWlnaHQoXG4gIGNvbXA6IFJlcG9ydENvbXBvbmVudERlZmluaXRpb24sXG4gIG92ZXJyaWRlSGVpZ2h0PzogbnVtYmVyIHwgbnVsbFxuKTogc3RyaW5nIHtcbiAgaWYgKG92ZXJyaWRlSGVpZ2h0ICE9PSB1bmRlZmluZWQgJiYgb3ZlcnJpZGVIZWlnaHQgIT09IG51bGwpIHtcbiAgICByZXR1cm4gYCR7b3ZlcnJpZGVIZWlnaHR9cHhgO1xuICB9XG4gIHJldHVybiBjb21wLmxheW91dD8uaGVpZ2h0IHx8ICdhdXRvJztcbn1cblxuLyoqXG4gKiBSZXNvbHZlcyB0aGUgQ1NTIG1pbi1oZWlnaHQgcHJvcGVydHkgZm9yIGEgcnVudGltZSBjb21wb25lbnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQ29tcG9uZW50TWluSGVpZ2h0KFxuICBjb21wOiBSZXBvcnRDb21wb25lbnREZWZpbml0aW9uLFxuICBvdmVycmlkZUhlaWdodD86IG51bWJlciB8IG51bGxcbik6IHN0cmluZyB7XG4gIGlmIChvdmVycmlkZUhlaWdodCAhPT0gdW5kZWZpbmVkICYmIG92ZXJyaWRlSGVpZ2h0ICE9PSBudWxsKSB7XG4gICAgcmV0dXJuIGAke292ZXJyaWRlSGVpZ2h0fXB4YDtcbiAgfVxuICByZXR1cm4gY29tcC5sYXlvdXQ/Lm1pbkhlaWdodCB8fCAnYXV0byc7XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlcyBuZXcgc25hcHBlZCBzcGFuIGdpdmVuIGRyYWcgZGVsdGFYLCBjb2x1bW4gd2lkdGgsIGFuZCBncmlkIGdhcC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhbGN1bGF0ZVNuYXBwZWRTcGFuKFxuICBkZWx0YVg6IG51bWJlcixcbiAgc3RhcnRTcGFuOiBudW1iZXIsXG4gIGNvbFdpZHRoOiBudW1iZXIsXG4gIGdhcDogbnVtYmVyLFxuICB0b3RhbENvbHM6IG51bWJlclxuKTogbnVtYmVyIHtcbiAgY29uc3Qgc3RlcCA9IGNvbFdpZHRoICsgZ2FwO1xuICBpZiAoc3RlcCA8PSAwKSByZXR1cm4gc3RhcnRTcGFuO1xuICBjb25zdCBzcGFuRGVsdGEgPSBNYXRoLnJvdW5kKGRlbHRhWCAvIHN0ZXApO1xuICByZXR1cm4gTWF0aC5tYXgoMSwgTWF0aC5taW4odG90YWxDb2xzLCBzdGFydFNwYW4gKyBzcGFuRGVsdGEpKTtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIG5ldyBoZWlnaHQgZ2l2ZW4gZHJhZyBkZWx0YVkgYW5kIG1pbmltdW0gaGVpZ2h0IGNvbnN0cmFpbnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjYWxjdWxhdGVTbmFwcGVkSGVpZ2h0KFxuICBkZWx0YVk6IG51bWJlcixcbiAgc3RhcnRIZWlnaHQ6IG51bWJlcixcbiAgbWluSGVpZ2h0OiBudW1iZXIgPSA1MFxuKTogbnVtYmVyIHtcbiAgcmV0dXJuIE1hdGgubWF4KG1pbkhlaWdodCwgTWF0aC5yb3VuZChzdGFydEhlaWdodCArIGRlbHRhWSkpO1xufVxuXG4vKipcbiAqIE1hcHMgY29tcG9uZW50IHR5cGUgdG8gc3RhbmRhcmQgaWNvbiBpZGVudGlmaWVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q29tcG9uZW50SWNvbk5hbWUodHlwZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgc3dpdGNoICh0eXBlKSB7XG4gICAgY2FzZSAnaW5wdXQnOiByZXR1cm4gJ3RleHQtZmllbGRzJztcbiAgICBjYXNlICdkcm9wZG93bic6IHJldHVybiAnZHJvcGRvd24nO1xuICAgIGNhc2UgJ2RhdGUnOiByZXR1cm4gJ2NhbGVuZGFyJztcbiAgICBjYXNlICdudW1iZXInOiByZXR1cm4gJ251bWJlcic7XG4gICAgY2FzZSAnY2hlY2tib3gnOiByZXR1cm4gJ2NoZWNrYm94JztcbiAgICBjYXNlICdidXR0b24nOiByZXR1cm4gJ2J1dHRvbic7XG4gICAgY2FzZSAna3BpLWNhcmQnOiByZXR1cm4gJ2twaSc7XG4gICAgY2FzZSAnY2hhcnQnOiByZXR1cm4gJ2NoYXJ0LWJhcic7XG4gICAgZGVmYXVsdDogcmV0dXJuICdib3gnO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ export { ReportExportService, sanitizeCsvCell, generateCsvContent } from './services/report-export.service';
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9id2F5cy1yZXBvcnQvc3JjL2xpYi9mZWF0dXJlcy9leHBvcnQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixlQUFlLEVBQ2Ysa0JBQWtCLEVBQ25CLE1BQU0sa0NBQWtDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgdHlwZSB7IEV4cG9ydENvbHVtbiwgQ3N2RXhwb3J0T3B0aW9ucywgSnNvbkV4cG9ydE9wdGlvbnMgfSBmcm9tICcuL21vZGVscy9leHBvcnQubW9kZWxzJztcbmV4cG9ydCB7XG4gIFJlcG9ydEV4cG9ydFNlcnZpY2UsXG4gIHNhbml0aXplQ3N2Q2VsbCxcbiAgZ2VuZXJhdGVDc3ZDb250ZW50XG59IGZyb20gJy4vc2VydmljZXMvcmVwb3J0LWV4cG9ydC5zZXJ2aWNlJztcbiJdfQ==
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwb3J0Lm1vZGVscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2J3YXlzLXJlcG9ydC9zcmMvbGliL2ZlYXR1cmVzL2V4cG9ydC9tb2RlbHMvZXhwb3J0Lm1vZGVscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGludGVyZmFjZSBFeHBvcnRDb2x1bW4ge1xuICBmaWVsZDogc3RyaW5nO1xuICBoZWFkZXI6IHN0cmluZztcbiAgZm9ybWF0dGVyPzogKHZhbHVlOiBhbnksIHJvdz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3N2RXhwb3J0T3B0aW9ucyB7XG4gIGZpbGVOYW1lPzogc3RyaW5nO1xuICBjb2x1bW5zPzogRXhwb3J0Q29sdW1uW107XG4gIGluY2x1ZGVIZWFkZXI/OiBib29sZWFuO1xuICBkZWxpbWl0ZXI/OiBzdHJpbmc7XG4gIGFkZEJvbT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSnNvbkV4cG9ydE9wdGlvbnMge1xuICBmaWxlTmFtZT86IHN0cmluZztcbiAgcHJldHR5PzogYm9vbGVhbjtcbn1cbiJdfQ==
@@ -0,0 +1,107 @@
1
+ import { Injectable, inject } from '@angular/core';
2
+ import { DOCUMENT } from '@angular/common';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Sanitizes and escapes a single cell value for CSV output.
6
+ */
7
+ export function sanitizeCsvCell(value, delimiter = ',') {
8
+ if (value === null || value === undefined) {
9
+ return '';
10
+ }
11
+ let str = String(value);
12
+ // If value contains delimiter, quote, or newline, escape and wrap in quotes
13
+ const mustQuote = str.includes(delimiter) ||
14
+ str.includes('"') ||
15
+ str.includes('\n') ||
16
+ str.includes('\r');
17
+ if (mustQuote) {
18
+ str = '"' + str.replace(/"/g, '""') + '"';
19
+ }
20
+ return str;
21
+ }
22
+ /**
23
+ * Pure generator function to create CSV content string from row data and columns.
24
+ */
25
+ export function generateCsvContent(rows, columns, delimiter = ',', includeHeader = true, addBom = true) {
26
+ const lines = [];
27
+ if (includeHeader) {
28
+ const headerLine = columns
29
+ .map((col) => sanitizeCsvCell(col.header, delimiter))
30
+ .join(delimiter);
31
+ lines.push(headerLine);
32
+ }
33
+ for (const row of rows) {
34
+ const rowValues = columns.map((col) => {
35
+ const val = row[col.field];
36
+ const formatted = col.formatter ? col.formatter(val, row) : val;
37
+ return sanitizeCsvCell(formatted, delimiter);
38
+ });
39
+ lines.push(rowValues.join(delimiter));
40
+ }
41
+ const csvBody = lines.join('\r\n');
42
+ return addBom ? '\uFEFF' + csvBody : csvBody;
43
+ }
44
+ export class ReportExportService {
45
+ document = inject(DOCUMENT);
46
+ /**
47
+ * Generates and triggers browser download of a CSV file.
48
+ */
49
+ exportCsv(rows, options = {}) {
50
+ if (!rows || rows.length === 0) {
51
+ console.warn('[bways-report] No rows to export');
52
+ return;
53
+ }
54
+ const delimiter = options.delimiter ?? ',';
55
+ const includeHeader = options.includeHeader !== false;
56
+ const addBom = options.addBom !== false;
57
+ const fileName = options.fileName || `report-export-${Date.now()}.csv`;
58
+ // If columns not provided, infer from first row keys
59
+ const columns = options.columns && options.columns.length > 0
60
+ ? options.columns
61
+ : Object.keys(rows[0]).map((key) => ({
62
+ field: key,
63
+ header: key
64
+ }));
65
+ const csvContent = generateCsvContent(rows, columns, delimiter, includeHeader, addBom);
66
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
67
+ this.downloadBlob(blob, fileName);
68
+ }
69
+ /**
70
+ * Generates and triggers browser download of a JSON file.
71
+ */
72
+ exportJson(data, options = {}) {
73
+ const fileName = options.fileName || `report-export-${Date.now()}.json`;
74
+ const pretty = options.pretty !== false;
75
+ const jsonString = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
76
+ const blob = new Blob([jsonString], { type: 'application/json;charset=utf-8;' });
77
+ this.downloadBlob(blob, fileName);
78
+ }
79
+ /**
80
+ * Safe file download trigger via temporary anchor tag.
81
+ */
82
+ downloadBlob(blob, fileName) {
83
+ if (!this.document || !this.document.createElement) {
84
+ return;
85
+ }
86
+ const url = URL.createObjectURL(blob);
87
+ const link = this.document.createElement('a');
88
+ link.href = url;
89
+ link.download = fileName;
90
+ link.style.display = 'none';
91
+ this.document.body.appendChild(link);
92
+ link.click();
93
+ setTimeout(() => {
94
+ this.document.body.removeChild(link);
95
+ URL.revokeObjectURL(url);
96
+ }, 100);
97
+ }
98
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ReportExportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
99
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ReportExportService, providedIn: 'root' });
100
+ }
101
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ReportExportService, decorators: [{
102
+ type: Injectable,
103
+ args: [{
104
+ providedIn: 'root'
105
+ }]
106
+ }] });
107
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0LWV4cG9ydC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYndheXMtcmVwb3J0L3NyYy9saWIvZmVhdHVyZXMvZXhwb3J0L3NlcnZpY2VzL3JlcG9ydC1leHBvcnQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7O0FBRzNDOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FBQyxLQUFjLEVBQUUsWUFBb0IsR0FBRztJQUNyRSxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQzFDLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVELElBQUksR0FBRyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUV4Qiw0RUFBNEU7SUFDNUUsTUFBTSxTQUFTLEdBQ2IsR0FBRyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUM7UUFDdkIsR0FBRyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUM7UUFDakIsR0FBRyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7UUFDbEIsR0FBRyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUVyQixJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQ2QsR0FBRyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUM7SUFDNUMsQ0FBQztJQUVELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGtCQUFrQixDQUNoQyxJQUErQixFQUMvQixPQUF1QixFQUN2QixZQUFvQixHQUFHLEVBQ3ZCLGdCQUF5QixJQUFJ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LENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3JDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUViLFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDZCxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDckMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMzQixDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDVixDQUFDO3dHQWhFVSxtQkFBbUI7NEdBQW5CLG1CQUFtQixjQUZsQixNQUFNOzs0RkFFUCxtQkFBbUI7a0JBSC9CLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBDc3ZFeHBvcnRPcHRpb25zLCBFeHBvcnRDb2x1bW4sIEpzb25FeHBvcnRPcHRpb25zIH0gZnJvbSAnLi4vbW9kZWxzL2V4cG9ydC5tb2RlbHMnO1xuXG4vKipcbiAqIFNhbml0aXplcyBhbmQgZXNjYXBlcyBhIHNpbmdsZSBjZWxsIHZhbHVlIGZvciBDU1Ygb3V0cHV0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemVDc3ZDZWxsKHZhbHVlOiB1bmtub3duLCBkZWxpbWl0ZXI6IHN0cmluZyA9ICcsJyk6IHN0cmluZyB7XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuICcnO1xuICB9XG5cbiAgbGV0IHN0ciA9IFN0cmluZyh2YWx1ZSk7XG5cbiAgLy8gSWYgdmFsdWUgY29udGFpbnMgZGVsaW1pdGVyLCBxdW90ZSwgb3IgbmV3bGluZSwgZXNjYXBlIGFuZCB3cmFwIGluIHF1b3Rlc1xuICBjb25zdCBtdXN0UXVvdGUgPVxuICAgIHN0ci5pbmNsdWRlcyhkZWxpbWl0ZXIpIHx8XG4gICAgc3RyLmluY2x1ZGVzKCdcIicpIHx8XG4gICAgc3RyLmluY2x1ZGVzKCdcXG4nKSB8fFxuICAgIHN0ci5pbmNsdWRlcygnXFxyJyk7XG5cbiAgaWYgKG11c3RRdW90ZSkge1xuICAgIHN0ciA9ICdcIicgKyBzdHIucmVwbGFjZSgvXCIvZywgJ1wiXCInKSArICdcIic7XG4gIH1cblxuICByZXR1cm4gc3RyO1xufVxuXG4vKipcbiAqIFB1cmUgZ2VuZXJhdG9yIGZ1bmN0aW9uIHRvIGNyZWF0ZSBDU1YgY29udGVudCBzdHJpbmcgZnJvbSByb3cgZGF0YSBhbmQgY29sdW1ucy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlQ3N2Q29udGVudChcbiAgcm93czogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXSxcbiAgY29sdW1uczogRXhwb3J0Q29sdW1uW10sXG4gIGRlbGltaXRlcjogc3RyaW5nID0gJywnLFxuICBpbmNsdWRlSGVhZGVyOiBib29sZWFuID0gdHJ1ZSxcbiAgYWRkQm9tOiBib29sZWFuID0gdHJ1ZVxuKTogc3RyaW5nIHtcbiAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG5cbiAgaWYgKGluY2x1ZGVIZWFkZXIpIHtcbiAgICBjb25zdCBoZWFkZXJMaW5lID0gY29sdW1uc1xuICAgICAgLm1hcCgoY29sKSA9PiBzYW5pdGl6ZUNzdkNlbGwoY29sLmhlYWRlciwgZGVsaW1pdGVyKSlcbiAgICAgIC5qb2luKGRlbGltaXRlcik7XG4gICAgbGluZXMucHVzaChoZWFkZXJMaW5lKTtcbiAgfVxuXG4gIGZvciAoY29uc3Qgcm93IG9mIHJvd3MpIHtcbiAgICBjb25zdCByb3dWYWx1ZXMgPSBjb2x1bW5zLm1hcCgoY29sKSA9PiB7XG4gICAgICBjb25zdCB2YWwgPSByb3dbY29sLmZpZWxkXTtcbiAgICAgIGNvbnN0IGZvcm1hdHRlZCA9IGNvbC5mb3JtYXR0ZXIgPyBjb2wuZm9ybWF0dGVyKHZhbCwgcm93KSA6IHZhbDtcbiAgICAgIHJldHVybiBzYW5pdGl6ZUNzdkNlbGwoZm9ybWF0dGVkLCBkZWxpbWl0ZXIpO1xuICAgIH0pO1xuICAgIGxpbmVzLnB1c2gocm93VmFsdWVzLmpvaW4oZGVsaW1pdGVyKSk7XG4gIH1cblxuICBjb25zdCBjc3ZCb2R5ID0gbGluZXMuam9pbignXFxyXFxuJyk7XG4gIHJldHVybiBhZGRCb20gPyAnXFx1RkVGRicgKyBjc3ZCb2R5IDogY3N2Qm9keTtcbn1cblxuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCdcbn0pXG5leHBvcnQgY2xhc3MgUmVwb3J0RXhwb3J0U2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgZG9jdW1lbnQgPSBpbmplY3QoRE9DVU1FTlQpO1xuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYW5kIHRyaWdnZXJzIGJyb3dzZXIgZG93bmxvYWQgb2YgYSBDU1YgZmlsZS5cbiAgICovXG4gIGV4cG9ydENzdihyb3dzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdLCBvcHRpb25zOiBDc3ZFeHBvcnRPcHRpb25zID0ge30pOiB2b2lkIHtcbiAgICBpZiAoIXJvd3MgfHwgcm93cy5sZW5ndGggPT09IDApIHtcbiAgICAgIGNvbnNvbGUud2FybignW2J3YXlzLXJlcG9ydF0gTm8gcm93cyB0byBleHBvcnQnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBkZWxpbWl0ZXIgPSBvcHRpb25zLmRlbGltaXRlciA/PyAnLCc7XG4gICAgY29uc3QgaW5jbHVkZUhlYWRlciA9IG9wdGlvbnMuaW5jbHVkZUhlYWRlciAhPT0gZmFsc2U7XG4gICAgY29uc3QgYWRkQm9tID0gb3B0aW9ucy5hZGRCb20gIT09IGZhbHNlO1xuICAgIGNvbnN0IGZpbGVOYW1lID0gb3B0aW9ucy5maWxlTmFtZSB8fCBgcmVwb3J0LWV4cG9ydC0ke0RhdGUubm93KCl9LmNzdmA7XG5cbiAgICAvLyBJZiBjb2x1bW5zIG5vdCBwcm92aWRlZCwgaW5mZXIgZnJvbSBmaXJzdCByb3cga2V5c1xuICAgIGNvbnN0IGNvbHVtbnM6IEV4cG9ydENvbHVtbltdID1cbiAgICAgIG9wdGlvbnMuY29sdW1ucyAmJiBvcHRpb25zLmNvbHVtbnMubGVuZ3RoID4gMFxuICAgICAgICA/IG9wdGlvbnMuY29sdW1uc1xuICAgICAgICA6IE9iamVjdC5rZXlzKHJvd3NbMF0pLm1hcCgoa2V5KSA9PiAoe1xuICAgICAgICAgICAgZmllbGQ6IGtleSxcbiAgICAgICAgICAgIGhlYWRlcjoga2V5XG4gICAgICAgICAgfSkpO1xuXG4gICAgY29uc3QgY3N2Q29udGVudCA9IGdlbmVyYXRlQ3N2Q29udGVudChyb3dzLCBjb2x1bW5zLCBkZWxpbWl0ZXIsIGluY2x1ZGVIZWFkZXIsIGFkZEJvbSk7XG4gICAgY29uc3QgYmxvYiA9IG5ldyBCbG9iKFtjc3ZDb250ZW50XSwgeyB0eXBlOiAndGV4dC9jc3Y7Y2hhcnNldD11dGYtODsnIH0pO1xuICAgIHRoaXMuZG93bmxvYWRCbG9iKGJsb2IsIGZpbGVOYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYW5kIHRyaWdnZXJzIGJyb3dzZXIgZG93bmxvYWQgb2YgYSBKU09OIGZpbGUuXG4gICAqL1xuICBleHBvcnRKc29uKGRhdGE6IHVua25vd24sIG9wdGlvbnM6IEpzb25FeHBvcnRPcHRpb25zID0ge30pOiB2b2lkIHtcbiAgICBjb25zdCBmaWxlTmFtZSA9IG9wdGlvbnMuZmlsZU5hbWUgfHwgYHJlcG9ydC1leHBvcnQtJHtEYXRlLm5vdygpfS5qc29uYDtcbiAgICBjb25zdCBwcmV0dHkgPSBvcHRpb25zLnByZXR0eSAhPT0gZmFsc2U7XG4gICAgY29uc3QganNvblN0cmluZyA9IHByZXR0eSA/IEpTT04uc3RyaW5naWZ5KGRhdGEsIG51bGwsIDIpIDogSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG5cbiAgICBjb25zdCBibG9iID0gbmV3IEJsb2IoW2pzb25TdHJpbmddLCB7IHR5cGU6ICdhcHBsaWNhdGlvbi9qc29uO2NoYXJzZXQ9dXRmLTg7JyB9KTtcbiAgICB0aGlzLmRvd25sb2FkQmxvYihibG9iLCBmaWxlTmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogU2FmZSBmaWxlIGRvd25sb2FkIHRyaWdnZXIgdmlhIHRlbXBvcmFyeSBhbmNob3IgdGFnLlxuICAgKi9cbiAgcHJpdmF0ZSBkb3dubG9hZEJsb2IoYmxvYjogQmxvYiwgZmlsZU5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICghdGhpcy5kb2N1bWVudCB8fCAhdGhpcy5kb2N1bWVudC5jcmVhdGVFbGVtZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgdXJsID0gVVJMLmNyZWF0ZU9iamVjdFVSTChibG9iKTtcbiAgICBjb25zdCBsaW5rID0gdGhpcy5kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG4gICAgbGluay5ocmVmID0gdXJsO1xuICAgIGxpbmsuZG93bmxvYWQgPSBmaWxlTmFtZTtcbiAgICBsaW5rLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cbiAgICB0aGlzLmRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQobGluayk7XG4gICAgbGluay5jbGljaygpO1xuXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmRvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQobGluayk7XG4gICAgICBVUkwucmV2b2tlT2JqZWN0VVJMKHVybCk7XG4gICAgfSwgMTAwKTtcbiAgfVxufVxuIl19