@nanahoshi/mona-ui 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 (134) hide show
  1. package/README.md +25 -0
  2. package/fesm2022/nanahoshi-mona-ui-auto-complete.mjs +590 -0
  3. package/fesm2022/nanahoshi-mona-ui-avatar.mjs +168 -0
  4. package/fesm2022/nanahoshi-mona-ui-breadcrumb.mjs +220 -0
  5. package/fesm2022/nanahoshi-mona-ui-button-group.mjs +225 -0
  6. package/fesm2022/nanahoshi-mona-ui-button.mjs +497 -0
  7. package/fesm2022/nanahoshi-mona-ui-calendar.mjs +1569 -0
  8. package/fesm2022/nanahoshi-mona-ui-check-box.mjs +339 -0
  9. package/fesm2022/nanahoshi-mona-ui-chip.mjs +453 -0
  10. package/fesm2022/nanahoshi-mona-ui-circular-progress-bar.mjs +200 -0
  11. package/fesm2022/nanahoshi-mona-ui-color-gradient.mjs +853 -0
  12. package/fesm2022/nanahoshi-mona-ui-color-palette.mjs +923 -0
  13. package/fesm2022/nanahoshi-mona-ui-color-picker.mjs +495 -0
  14. package/fesm2022/nanahoshi-mona-ui-combo-box.mjs +686 -0
  15. package/fesm2022/nanahoshi-mona-ui-common.mjs +642 -0
  16. package/fesm2022/nanahoshi-mona-ui-contextmenu.mjs +485 -0
  17. package/fesm2022/nanahoshi-mona-ui-date-input.mjs +132 -0
  18. package/fesm2022/nanahoshi-mona-ui-date-picker.mjs +460 -0
  19. package/fesm2022/nanahoshi-mona-ui-datetime-picker.mjs +659 -0
  20. package/fesm2022/nanahoshi-mona-ui-dialog.mjs +828 -0
  21. package/fesm2022/nanahoshi-mona-ui-dropdown-button.mjs +523 -0
  22. package/fesm2022/nanahoshi-mona-ui-dropdown-list.mjs +615 -0
  23. package/fesm2022/nanahoshi-mona-ui-dropdowns.mjs +701 -0
  24. package/fesm2022/nanahoshi-mona-ui-editor.mjs +1400 -0
  25. package/fesm2022/nanahoshi-mona-ui-expansion-panel.mjs +245 -0
  26. package/fesm2022/nanahoshi-mona-ui-fieldset.mjs +170 -0
  27. package/fesm2022/nanahoshi-mona-ui-filter.mjs +680 -0
  28. package/fesm2022/nanahoshi-mona-ui-grid-grid-footer-cell.component-B9SQH5N-.mjs +105 -0
  29. package/fesm2022/nanahoshi-mona-ui-grid-grid-footer-table-cell.directive-DlLwcCFT.mjs +42 -0
  30. package/fesm2022/nanahoshi-mona-ui-grid-grid-list.component-Dgea-O0X.mjs +130 -0
  31. package/fesm2022/nanahoshi-mona-ui-grid-grid-toggle.component-DIUutx9s.mjs +773 -0
  32. package/fesm2022/nanahoshi-mona-ui-grid-grid-virtual-list.component-DRHycGIh.mjs +240 -0
  33. package/fesm2022/nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-C3eZIaJK.mjs +5374 -0
  34. package/fesm2022/nanahoshi-mona-ui-grid.mjs +2 -0
  35. package/fesm2022/nanahoshi-mona-ui-internal-filter-input.mjs +87 -0
  36. package/fesm2022/nanahoshi-mona-ui-internal-indicator-icon.mjs +154 -0
  37. package/fesm2022/nanahoshi-mona-ui-internal-list.mjs +1356 -0
  38. package/fesm2022/nanahoshi-mona-ui-internal-tree.mjs +2263 -0
  39. package/fesm2022/nanahoshi-mona-ui-internal.mjs +379 -0
  40. package/fesm2022/nanahoshi-mona-ui-list-box.mjs +630 -0
  41. package/fesm2022/nanahoshi-mona-ui-list-view.mjs +527 -0
  42. package/fesm2022/nanahoshi-mona-ui-list.mjs +4 -0
  43. package/fesm2022/nanahoshi-mona-ui-menubar.mjs +966 -0
  44. package/fesm2022/nanahoshi-mona-ui-multi-select.mjs +641 -0
  45. package/fesm2022/nanahoshi-mona-ui-notification.mjs +536 -0
  46. package/fesm2022/nanahoshi-mona-ui-numeric-text-box.mjs +597 -0
  47. package/fesm2022/nanahoshi-mona-ui-pager.mjs +790 -0
  48. package/fesm2022/nanahoshi-mona-ui-placeholder.mjs +83 -0
  49. package/fesm2022/nanahoshi-mona-ui-popover.mjs +325 -0
  50. package/fesm2022/nanahoshi-mona-ui-popup-menu.mjs +1559 -0
  51. package/fesm2022/nanahoshi-mona-ui-popup.mjs +1321 -0
  52. package/fesm2022/nanahoshi-mona-ui-progress-bar.mjs +294 -0
  53. package/fesm2022/nanahoshi-mona-ui-query.mjs +175 -0
  54. package/fesm2022/nanahoshi-mona-ui-radio-button.mjs +339 -0
  55. package/fesm2022/nanahoshi-mona-ui-scroll-view.mjs +565 -0
  56. package/fesm2022/nanahoshi-mona-ui-slider.mjs +1049 -0
  57. package/fesm2022/nanahoshi-mona-ui-split-button.mjs +636 -0
  58. package/fesm2022/nanahoshi-mona-ui-splitter.mjs +843 -0
  59. package/fesm2022/nanahoshi-mona-ui-stepper.mjs +537 -0
  60. package/fesm2022/nanahoshi-mona-ui-switch.mjs +308 -0
  61. package/fesm2022/nanahoshi-mona-ui-tabs.mjs +664 -0
  62. package/fesm2022/nanahoshi-mona-ui-text-area.mjs +111 -0
  63. package/fesm2022/nanahoshi-mona-ui-text-box.mjs +369 -0
  64. package/fesm2022/nanahoshi-mona-ui-theme.mjs +314 -0
  65. package/fesm2022/nanahoshi-mona-ui-time-picker.mjs +450 -0
  66. package/fesm2022/nanahoshi-mona-ui-time-selector.mjs +723 -0
  67. package/fesm2022/nanahoshi-mona-ui-tooltip.mjs +716 -0
  68. package/fesm2022/nanahoshi-mona-ui-tree-view.mjs +733 -0
  69. package/fesm2022/nanahoshi-mona-ui-window.mjs +1329 -0
  70. package/fesm2022/nanahoshi-mona-ui.mjs +9 -0
  71. package/package.json +289 -0
  72. package/types/nanahoshi-mona-ui-auto-complete.d.ts +223 -0
  73. package/types/nanahoshi-mona-ui-avatar.d.ts +642 -0
  74. package/types/nanahoshi-mona-ui-breadcrumb.d.ts +70 -0
  75. package/types/nanahoshi-mona-ui-button-group.d.ts +77 -0
  76. package/types/nanahoshi-mona-ui-button.d.ts +111 -0
  77. package/types/nanahoshi-mona-ui-calendar.d.ts +262 -0
  78. package/types/nanahoshi-mona-ui-check-box.d.ts +133 -0
  79. package/types/nanahoshi-mona-ui-chip.d.ts +130 -0
  80. package/types/nanahoshi-mona-ui-circular-progress-bar.d.ts +113 -0
  81. package/types/nanahoshi-mona-ui-color-gradient.d.ts +201 -0
  82. package/types/nanahoshi-mona-ui-color-palette.d.ts +102 -0
  83. package/types/nanahoshi-mona-ui-color-picker.d.ts +156 -0
  84. package/types/nanahoshi-mona-ui-combo-box.d.ts +232 -0
  85. package/types/nanahoshi-mona-ui-common.d.ts +386 -0
  86. package/types/nanahoshi-mona-ui-contextmenu.d.ts +129 -0
  87. package/types/nanahoshi-mona-ui-date-input.d.ts +60 -0
  88. package/types/nanahoshi-mona-ui-date-picker.d.ts +177 -0
  89. package/types/nanahoshi-mona-ui-datetime-picker.d.ts +199 -0
  90. package/types/nanahoshi-mona-ui-dialog.d.ts +261 -0
  91. package/types/nanahoshi-mona-ui-dropdown-button.d.ts +159 -0
  92. package/types/nanahoshi-mona-ui-dropdown-list.d.ts +219 -0
  93. package/types/nanahoshi-mona-ui-dropdowns.d.ts +176 -0
  94. package/types/nanahoshi-mona-ui-editor.d.ts +113 -0
  95. package/types/nanahoshi-mona-ui-expansion-panel.d.ts +87 -0
  96. package/types/nanahoshi-mona-ui-fieldset.d.ts +68 -0
  97. package/types/nanahoshi-mona-ui-filter.d.ts +115 -0
  98. package/types/nanahoshi-mona-ui-grid.d.ts +1114 -0
  99. package/types/nanahoshi-mona-ui-internal-filter-input.d.ts +25 -0
  100. package/types/nanahoshi-mona-ui-internal-indicator-icon.d.ts +28 -0
  101. package/types/nanahoshi-mona-ui-internal-list.d.ts +269 -0
  102. package/types/nanahoshi-mona-ui-internal-tree.d.ts +391 -0
  103. package/types/nanahoshi-mona-ui-internal.d.ts +136 -0
  104. package/types/nanahoshi-mona-ui-list-box.d.ts +225 -0
  105. package/types/nanahoshi-mona-ui-list-view.d.ts +188 -0
  106. package/types/nanahoshi-mona-ui-list.d.ts +1 -0
  107. package/types/nanahoshi-mona-ui-menubar.d.ts +198 -0
  108. package/types/nanahoshi-mona-ui-multi-select.d.ts +247 -0
  109. package/types/nanahoshi-mona-ui-notification.d.ts +106 -0
  110. package/types/nanahoshi-mona-ui-numeric-text-box.d.ts +161 -0
  111. package/types/nanahoshi-mona-ui-pager.d.ts +238 -0
  112. package/types/nanahoshi-mona-ui-placeholder.d.ts +35 -0
  113. package/types/nanahoshi-mona-ui-popover.d.ts +130 -0
  114. package/types/nanahoshi-mona-ui-popup-menu.d.ts +412 -0
  115. package/types/nanahoshi-mona-ui-popup.d.ts +485 -0
  116. package/types/nanahoshi-mona-ui-progress-bar.d.ts +139 -0
  117. package/types/nanahoshi-mona-ui-query.d.ts +89 -0
  118. package/types/nanahoshi-mona-ui-radio-button.d.ts +128 -0
  119. package/types/nanahoshi-mona-ui-scroll-view.d.ts +166 -0
  120. package/types/nanahoshi-mona-ui-slider.d.ts +305 -0
  121. package/types/nanahoshi-mona-ui-split-button.d.ts +182 -0
  122. package/types/nanahoshi-mona-ui-splitter.d.ts +70 -0
  123. package/types/nanahoshi-mona-ui-stepper.d.ts +173 -0
  124. package/types/nanahoshi-mona-ui-switch.d.ts +125 -0
  125. package/types/nanahoshi-mona-ui-tabs.d.ts +158 -0
  126. package/types/nanahoshi-mona-ui-text-area.d.ts +42 -0
  127. package/types/nanahoshi-mona-ui-text-box.d.ts +164 -0
  128. package/types/nanahoshi-mona-ui-theme.d.ts +23 -0
  129. package/types/nanahoshi-mona-ui-time-picker.d.ts +184 -0
  130. package/types/nanahoshi-mona-ui-time-selector.d.ts +143 -0
  131. package/types/nanahoshi-mona-ui-tooltip.d.ts +130 -0
  132. package/types/nanahoshi-mona-ui-tree-view.d.ts +274 -0
  133. package/types/nanahoshi-mona-ui-window.d.ts +295 -0
  134. package/types/nanahoshi-mona-ui.d.ts +2 -0
@@ -0,0 +1,642 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Pipe, linkedSignal, computed, signal } from '@angular/core';
3
+ import { any, contains, all, from, firstOrDefault, ImmutableDictionary } from '@mirei/ts-collections';
4
+ import { DateTime } from 'luxon';
5
+
6
+ class PreventableEvent {
7
+ #event;
8
+ #type;
9
+ #defaultPrevented = false;
10
+ constructor(type, event) {
11
+ this.#type = type;
12
+ this.#event = event;
13
+ }
14
+ isDefaultPrevented() {
15
+ return this.#defaultPrevented;
16
+ }
17
+ preventDefault() {
18
+ this.#defaultPrevented = true;
19
+ }
20
+ get originalEvent() {
21
+ return this.#event;
22
+ }
23
+ get type() {
24
+ return this.#type;
25
+ }
26
+ }
27
+
28
+ class FilterChangeEvent extends PreventableEvent {
29
+ #filter;
30
+ constructor(filterText) {
31
+ super("filterInputChange");
32
+ this.#filter = filterText;
33
+ }
34
+ get filter() {
35
+ return this.#filter;
36
+ }
37
+ }
38
+
39
+ class AnyPipe {
40
+ transform(sequence, predicate) {
41
+ if (sequence == null) {
42
+ return false;
43
+ }
44
+ if (!predicate) {
45
+ return any(sequence);
46
+ }
47
+ return any(sequence, predicate);
48
+ }
49
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: AnyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
50
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: AnyPipe, isStandalone: true, name: "monaAny" }); }
51
+ }
52
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: AnyPipe, decorators: [{
53
+ type: Pipe,
54
+ args: [{
55
+ name: "monaAny"
56
+ }]
57
+ }] });
58
+
59
+ class ContainsPipe {
60
+ transform(sequence, value) {
61
+ if (sequence == null) {
62
+ return false;
63
+ }
64
+ if (typeof value === "string") {
65
+ return contains(sequence, value);
66
+ }
67
+ if (Symbol.iterator in Object(value)) {
68
+ return all(value, item => contains(sequence, item));
69
+ }
70
+ return contains(sequence, value);
71
+ }
72
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ContainsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
73
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: ContainsPipe, isStandalone: true, name: "monaContains" }); }
74
+ }
75
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ContainsPipe, decorators: [{
76
+ type: Pipe,
77
+ args: [{
78
+ name: "monaContains"
79
+ }]
80
+ }] });
81
+
82
+ class SlicePipe {
83
+ transform(value, start, end) {
84
+ return from(value)
85
+ .skip(start)
86
+ .take(end - start)
87
+ .toArray();
88
+ }
89
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SlicePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
90
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: SlicePipe, isStandalone: true, name: "monaSlice" }); }
91
+ }
92
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SlicePipe, decorators: [{
93
+ type: Pipe,
94
+ args: [{
95
+ name: "monaSlice"
96
+ }]
97
+ }] });
98
+
99
+ class TakeFirstPipe {
100
+ transform(value) {
101
+ if (value == null) {
102
+ return null;
103
+ }
104
+ return firstOrDefault(value);
105
+ }
106
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: TakeFirstPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
107
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: TakeFirstPipe, isStandalone: true, name: "monaTakeFirst" }); }
108
+ }
109
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: TakeFirstPipe, decorators: [{
110
+ type: Pipe,
111
+ args: [{
112
+ name: "monaTakeFirst"
113
+ }]
114
+ }] });
115
+
116
+ const defaultOptions = { arrayStrategy: { kind: "replace" } };
117
+ const isEmptyObject = (obj) => {
118
+ return Object.keys(obj).length === 0;
119
+ };
120
+ const isPlainObject = (v) => {
121
+ return !!v && typeof v === "object" && Object.getPrototypeOf(v) === Object.prototype;
122
+ };
123
+ function deepMerge(base, patch, options = defaultOptions, path = []) {
124
+ if (!isPlainObject(patch)) {
125
+ return base;
126
+ }
127
+ const out = isPlainObject(base) ? { ...base } : {};
128
+ const keys = Object.keys(patch);
129
+ for (const key of keys) {
130
+ const patchValue = patch[key];
131
+ if (patchValue === undefined) {
132
+ continue;
133
+ }
134
+ const baseValue = out[key];
135
+ const currentPath = [...path, key];
136
+ if (Array.isArray(patchValue)) {
137
+ const rawStrategy = options.arrayStrategy ?? defaultOptions.arrayStrategy;
138
+ const strategy = typeof rawStrategy === "function" ? rawStrategy(key, currentPath) : rawStrategy;
139
+ if (strategy.kind === "replace" || !Array.isArray(baseValue)) {
140
+ out[key] = patchValue;
141
+ }
142
+ else if (strategy.kind === "concat") {
143
+ out[key] = [
144
+ ...baseValue,
145
+ ...patchValue
146
+ ];
147
+ }
148
+ else {
149
+ // unionBy Strategy
150
+ const by = strategy.key;
151
+ const map = new Map();
152
+ const getIdentifier = (item) => {
153
+ if (Array.isArray(by)) {
154
+ return by.map(k => String(item?.[k] ?? "")).join("|");
155
+ }
156
+ return String(item?.[by] ?? "");
157
+ };
158
+ for (const item of baseValue) {
159
+ map.set(getIdentifier(item), item);
160
+ }
161
+ for (const item of patchValue) {
162
+ const id = getIdentifier(item);
163
+ const existing = map.get(id);
164
+ const mergedItem = isPlainObject(item) && isPlainObject(existing)
165
+ ? // @ts-ignore // TODO: Remove this when it is no longer flagged as error
166
+ deepMerge(existing, item, options)
167
+ : { ...existing, ...item };
168
+ map.set(id, mergedItem);
169
+ }
170
+ out[key] = Array.from(map.values());
171
+ }
172
+ continue;
173
+ }
174
+ if (isPlainObject(patchValue) && isPlainObject(baseValue)) {
175
+ out[key] = deepMerge(baseValue, patchValue, options, currentPath);
176
+ continue;
177
+ }
178
+ out[key] = patchValue;
179
+ }
180
+ return out;
181
+ }
182
+ function mergeInto(base, patch, options) {
183
+ return deepMerge(base, patch, options);
184
+ }
185
+ function mergePatchInto(base, patch, options) {
186
+ return deepMerge(base, patch, options);
187
+ }
188
+ function buildNested(keys, leaf) {
189
+ const [head, ...rest] = keys;
190
+ if (head === undefined) {
191
+ return {};
192
+ }
193
+ if (rest.length === 0) {
194
+ return { [head]: leaf };
195
+ }
196
+ return { [head]: buildNested(rest, leaf) };
197
+ }
198
+ function patchAt(path, value) {
199
+ const keys = path;
200
+ const nested = buildNested(keys, value);
201
+ return nested;
202
+ }
203
+ function setAt(obj, path, value, options) {
204
+ return deepMerge(obj, patchAt(path, value), options);
205
+ }
206
+ function prunePatch(base, patch) {
207
+ if (patch === null || typeof patch !== "object" || base === null || typeof base !== "object") {
208
+ return base === patch ? undefined : patch;
209
+ }
210
+ const baseObj = base;
211
+ const patchObj = patch;
212
+ const result = { ...patchObj };
213
+ for (const key of Object.keys(patchObj)) {
214
+ if (!(key in baseObj)) {
215
+ continue;
216
+ }
217
+ const baseValue = baseObj[key];
218
+ const patchValue = patchObj[key];
219
+ if (isPlainObject(patchValue) && isPlainObject(baseValue)) {
220
+ const pruned = prunePatch(baseValue, patchValue);
221
+ if (pruned === undefined || (typeof pruned === "object" && Object.keys(pruned).length === 0)) {
222
+ delete result[key];
223
+ }
224
+ else {
225
+ result[key] = pruned;
226
+ }
227
+ }
228
+ else if (deepEquals(baseValue, patchValue)) {
229
+ delete result[key];
230
+ }
231
+ }
232
+ return Object.keys(result).length === 0 ? undefined : result;
233
+ }
234
+ function deepEquals(o1, o2) {
235
+ if (o1 === o2) {
236
+ return true;
237
+ }
238
+ if (typeof o1 !== typeof o2 || o1 === null || o2 === null || o1 === undefined || o2 === undefined) {
239
+ return false;
240
+ }
241
+ if (o1 instanceof Date && o2 instanceof Date) {
242
+ return DateTime.fromJSDate(o1).equals(DateTime.fromJSDate(o2));
243
+ }
244
+ if (Array.isArray(o1) !== Array.isArray(o2)) {
245
+ return false;
246
+ }
247
+ if (Array.isArray(o1) && Array.isArray(o2)) {
248
+ return o1.length === o2.length && o1.every((v, i) => deepEquals(v, o2[i]));
249
+ }
250
+ if (typeof o1 === "object" && typeof o2 === "object") {
251
+ const keys1 = Object.keys(o1);
252
+ const keys2 = Object.keys(o2);
253
+ if (keys1.length !== keys2.length) {
254
+ return false;
255
+ }
256
+ for (const key of keys1) {
257
+ const keyOfT = key;
258
+ if (!Object.prototype.hasOwnProperty.call(o2, key) || !deepEquals(o1[keyOfT], o2[keyOfT])) {
259
+ return false;
260
+ }
261
+ }
262
+ return true;
263
+ }
264
+ return false;
265
+ }
266
+
267
+ class ObjectPatchStore {
268
+ #base;
269
+ #committed;
270
+ #draft;
271
+ #options;
272
+ constructor(options) {
273
+ this.#draft = linkedSignal({ ...(ngDevMode ? { debugName: "#draft" } : /* istanbul ignore next */ {}), source: () => this.#base(),
274
+ computation: (newBase, previous) => {
275
+ const strategy = this.#options.baseChangeStrategy ?? "wipe";
276
+ if (!previous) {
277
+ // First computation — initialise from options.initial if provided.
278
+ return this.#options.initial?.() ?? {};
279
+ }
280
+ switch (strategy) {
281
+ case "preserve":
282
+ return previous.value;
283
+ case "rebase":
284
+ return prunePatch(newBase, previous.value) ?? {};
285
+ case "wipe":
286
+ default:
287
+ return {};
288
+ }
289
+ } });
290
+ this.changes = computed(() => {
291
+ const draft = this.#draft();
292
+ return isEmptyObject(draft) ? undefined : draft;
293
+ }, /* @ts-ignore */
294
+ ...(ngDevMode ? [{ debugName: "changes" }] : /* istanbul ignore next */ []));
295
+ this.pristine = computed(() => {
296
+ const base = this.#base();
297
+ const draft = this.#draft();
298
+ const committed = this.#committed();
299
+ const prunedDraft = prunePatch(base, draft) ?? {};
300
+ const prunedCommitted = prunePatch(base, committed) ?? {};
301
+ return deepEquals(prunedDraft, prunedCommitted);
302
+ }, /* @ts-ignore */
303
+ ...(ngDevMode ? [{ debugName: "pristine" }] : /* istanbul ignore next */ []));
304
+ this.view = computed(() => deepMerge(this.#base(), this.#draft()), /* @ts-ignore */
305
+ ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
306
+ this.#options = options;
307
+ this.#base = options.source();
308
+ const initial = options.initial?.() ?? {};
309
+ this.#committed = signal(initial, /* @ts-ignore */
310
+ ...(ngDevMode ? [{ debugName: "#committed" }] : /* istanbul ignore next */ []));
311
+ // Sync initial draft; linkedSignal computation handles subsequent base changes.
312
+ this.#draft.set(initial);
313
+ }
314
+ clear() {
315
+ this.#draft.set({});
316
+ }
317
+ commit() {
318
+ this.#committed.set(this.#draft());
319
+ }
320
+ getCommitted() {
321
+ return this.#committed();
322
+ }
323
+ hasDraft() {
324
+ return !isEmptyObject(this.#draft());
325
+ }
326
+ patch(patch, options) {
327
+ const effectiveOptions = options ?? this.#options.mergeOptions;
328
+ this.#draft.update(currentDraft => {
329
+ const currentFullView = deepMerge(this.#base(), currentDraft, effectiveOptions);
330
+ const updatedFullView = deepMerge(currentFullView, patch, effectiveOptions);
331
+ const nextDraft = prunePatch(this.#base(), updatedFullView);
332
+ return nextDraft ?? {};
333
+ });
334
+ }
335
+ patchPath(path, value, options) {
336
+ const patch = buildNested(path, value);
337
+ this.patch(patch, options);
338
+ }
339
+ reset() {
340
+ this.#draft.set({});
341
+ this.#committed.set({});
342
+ }
343
+ setDraft(patch) {
344
+ this.#draft.set(patch);
345
+ }
346
+ setPath(path, value, options) {
347
+ // Fix: delegate to patch() so the draft is merged rather than replaced,
348
+ // preserving any unrelated in-progress changes.
349
+ const patch = buildNested(path, value);
350
+ this.patch(patch, options);
351
+ }
352
+ select(projector, equal = deepEquals) {
353
+ return computed(() => projector(this.view()), { equal });
354
+ }
355
+ }
356
+ class IterablePatchStore {
357
+ #base;
358
+ /**
359
+ * O(1) lookup map derived from the base signal. Rebuilt only when the
360
+ * base iterable emits a new value, not on every patch operation.
361
+ */
362
+ #baseMap;
363
+ #committed;
364
+ #drafts;
365
+ #options;
366
+ /**
367
+ * Memoisation cache for the `view` computed. Keyed by item id; each
368
+ * entry stores the draft reference that produced the merged result so we
369
+ * can skip deepMerge when neither the base item nor its draft changed.
370
+ */
371
+ #viewCache;
372
+ constructor(options) {
373
+ /**
374
+ * O(1) lookup map derived from the base signal. Rebuilt only when the
375
+ * base iterable emits a new value, not on every patch operation.
376
+ */
377
+ this.#baseMap = computed(() => new Map(Array.from(this.#base()).map(item => [this.#options.idOf(item), item])), /* @ts-ignore */
378
+ ...(ngDevMode ? [{ debugName: "#baseMap" }] : /* istanbul ignore next */ []));
379
+ this.#drafts = linkedSignal({ ...(ngDevMode ? { debugName: "#drafts" } : /* istanbul ignore next */ {}), source: () => this.#options.source(),
380
+ computation: (newSource, previous) => {
381
+ const strategy = this.#options.baseChangeStrategy ?? "wipe";
382
+ if (!previous) {
383
+ return ImmutableDictionary.create();
384
+ }
385
+ switch (strategy) {
386
+ case "preserve":
387
+ return previous.value;
388
+ case "rebase": {
389
+ const baseArray = Array.from(newSource());
390
+ let rebased = ImmutableDictionary.create();
391
+ for (const [id, draft] of previous.value.entries()) {
392
+ const baseItem = baseArray.find(item => this.#options.idOf(item) === id);
393
+ if (!baseItem) {
394
+ // Item no longer exists in base — drop the draft.
395
+ continue;
396
+ }
397
+ const pruned = prunePatch(baseItem, draft);
398
+ if (pruned && !isEmptyObject(pruned)) {
399
+ rebased = rebased.put(id, pruned);
400
+ }
401
+ }
402
+ return rebased;
403
+ }
404
+ case "wipe":
405
+ default:
406
+ return ImmutableDictionary.create();
407
+ }
408
+ } });
409
+ /**
410
+ * Memoisation cache for the `view` computed. Keyed by item id; each
411
+ * entry stores the draft reference that produced the merged result so we
412
+ * can skip deepMerge when neither the base item nor its draft changed.
413
+ */
414
+ this.#viewCache = new Map();
415
+ this.changes = computed(() => {
416
+ const baseArray = Array.from(this.#base());
417
+ const drafts = this.#drafts();
418
+ return baseArray
419
+ .filter(b => {
420
+ const draft = drafts.get(this.#options.idOf(b));
421
+ return draft != null && !isEmptyObject(draft);
422
+ })
423
+ .map(b => deepMerge(b, drafts.get(this.#options.idOf(b))));
424
+ }, /* @ts-ignore */
425
+ ...(ngDevMode ? [{ debugName: "changes" }] : /* istanbul ignore next */ []));
426
+ this.pristine = computed(() => {
427
+ const baseArray = Array.from(this.#base());
428
+ const drafts = this.#drafts();
429
+ const committed = this.#committed();
430
+ const allIds = new Set([...drafts.keys(), ...committed.keys()]);
431
+ for (const id of allIds) {
432
+ const draft = drafts.get(id) ?? {};
433
+ const committedDraft = committed.get(id) ?? {};
434
+ const originalItem = baseArray.find(item => this.#options.idOf(item) === id);
435
+ const prunedDraft = originalItem ? (prunePatch(originalItem, draft) ?? {}) : draft;
436
+ const prunedCommitted = originalItem
437
+ ? (prunePatch(originalItem, committedDraft) ?? {})
438
+ : committedDraft;
439
+ if (!deepEquals(prunedDraft, prunedCommitted)) {
440
+ return false;
441
+ }
442
+ }
443
+ return true;
444
+ }, /* @ts-ignore */
445
+ ...(ngDevMode ? [{ debugName: "pristine" }] : /* istanbul ignore next */ []));
446
+ this.view = computed(() => {
447
+ const drafts = this.#drafts();
448
+ return Array.from(this.#base()).map(b => {
449
+ const id = this.#options.idOf(b);
450
+ const patch = drafts.get(id);
451
+ if (!patch || isEmptyObject(patch)) {
452
+ // No draft — return base item directly and evict any stale cache entry.
453
+ this.#viewCache.delete(id);
454
+ return b;
455
+ }
456
+ const cached = this.#viewCache.get(id);
457
+ if (cached && cached.patchRef === patch) {
458
+ // Draft reference hasn't changed — return cached merged value
459
+ // to avoid an unnecessary deepMerge and a new object allocation.
460
+ return cached.merged;
461
+ }
462
+ const merged = deepMerge(b, patch);
463
+ this.#viewCache.set(id, { patchRef: patch, merged });
464
+ return merged;
465
+ });
466
+ }, /* @ts-ignore */
467
+ ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
468
+ this.#options = options;
469
+ this.#base = options.source();
470
+ let initial;
471
+ if (options.initial) {
472
+ if (options.initial() instanceof ImmutableDictionary) {
473
+ initial = options.initial();
474
+ }
475
+ else {
476
+ initial = ImmutableDictionary.create(options.initial());
477
+ }
478
+ }
479
+ else {
480
+ initial = ImmutableDictionary.create();
481
+ }
482
+ this.#committed = signal(initial, /* @ts-ignore */
483
+ ...(ngDevMode ? [{ debugName: "#committed" }] : /* istanbul ignore next */ []));
484
+ if (options.initial) {
485
+ this.#drafts.set(ImmutableDictionary.create(initial));
486
+ }
487
+ }
488
+ clear(id) {
489
+ this.#drafts.update(drafts => {
490
+ if (!drafts.containsKey(id))
491
+ return drafts;
492
+ const newDrafts = ImmutableDictionary.create(drafts);
493
+ return newDrafts.remove(id);
494
+ });
495
+ }
496
+ clearAll() {
497
+ this.#drafts.set(ImmutableDictionary.create());
498
+ }
499
+ commit() {
500
+ this.#committed.set(ImmutableDictionary.create(this.#drafts()));
501
+ }
502
+ dirtyCount() {
503
+ let count = 0;
504
+ for (const patch of this.#drafts().values()) {
505
+ if (typeof patch === "object" && patch != null && !isEmptyObject(patch)) {
506
+ ++count;
507
+ }
508
+ }
509
+ return count;
510
+ }
511
+ getCommitted() {
512
+ return this.#committed();
513
+ }
514
+ hasDraft(id) {
515
+ const patch = this.#drafts().get(id);
516
+ return patch != null && !isEmptyObject(patch);
517
+ }
518
+ patch(id, patch, options) {
519
+ this.#drafts.update(drafts => {
520
+ let newDrafts = ImmutableDictionary.create(drafts);
521
+ const prev = drafts.get(id) ?? {};
522
+ let next = deepMerge(prev, patch, options);
523
+ // Fix: use #baseMap for O(1) lookup instead of a linear scan.
524
+ const originalItem = this.#baseMap().get(id);
525
+ if (originalItem) {
526
+ next = prunePatch(originalItem, next) ?? {};
527
+ }
528
+ if (isEmptyObject(next)) {
529
+ newDrafts = newDrafts.remove(id);
530
+ }
531
+ else {
532
+ newDrafts = newDrafts.put(id, next);
533
+ }
534
+ return newDrafts;
535
+ });
536
+ }
537
+ patchMany(patchTuple, options) {
538
+ // Fix: prune each resulting draft against the base item for consistency
539
+ // with patch(), and use #baseMap for O(1) lookups.
540
+ const baseMap = this.#baseMap();
541
+ this.#drafts.update(drafts => {
542
+ let newDrafts = ImmutableDictionary.create(drafts);
543
+ for (const [id, value] of patchTuple) {
544
+ const prev = newDrafts.get(id) ?? {};
545
+ let next = deepMerge(prev, value, options);
546
+ const originalItem = baseMap.get(id);
547
+ if (originalItem) {
548
+ next = prunePatch(originalItem, next) ?? {};
549
+ }
550
+ if (isEmptyObject(next)) {
551
+ newDrafts = newDrafts.remove(id);
552
+ }
553
+ else {
554
+ newDrafts = newDrafts.put(id, next);
555
+ }
556
+ }
557
+ return newDrafts;
558
+ });
559
+ }
560
+ patchPath(id, path, value, options) {
561
+ const patch = buildNested(path, value);
562
+ this.patch(id, patch, options);
563
+ }
564
+ reset() {
565
+ const empty = ImmutableDictionary.create();
566
+ this.#drafts.set(empty);
567
+ this.#committed.set(empty);
568
+ }
569
+ setDraft(id, patch) {
570
+ this.#drafts.update(drafts => {
571
+ let newDrafts = ImmutableDictionary.create(drafts);
572
+ newDrafts = newDrafts.put(id, patch);
573
+ return newDrafts;
574
+ });
575
+ }
576
+ setPath(id, path, value, options) {
577
+ // Fix: delegate to patch() so the draft is merged rather than replaced,
578
+ // preserving any unrelated in-progress changes.
579
+ const patch = buildNested(path, value);
580
+ this.patch(id, patch, options);
581
+ }
582
+ select(projector, equal = deepEquals) {
583
+ return computed(() => projector(this.view()), { equal });
584
+ }
585
+ }
586
+ const createIterablePatchStore = (options) => new IterablePatchStore(options);
587
+ const createObjectPatchStore = (options) => new ObjectPatchStore(options);
588
+
589
+ /**
590
+ * Calculates the percentage of a value within a given range, rounded to the specified precision.
591
+ * @param value The current value.
592
+ * @param min The minimum value.
593
+ * @param max The maximum value.
594
+ * @param precision The number of decimal places to round the percentage to.
595
+ * @default 2
596
+ * @returns The percentage of the value within the range, rounded to the specified precision.
597
+ */
598
+ const getPercentage = (value, min, max, precision = 2) => {
599
+ if (max <= min || !isFinite(value)) {
600
+ return 0;
601
+ }
602
+ const raw = ((value - min) / (max - min)) * 100;
603
+ return Number(Math.min(100, Math.max(0, raw)).toFixed(precision));
604
+ };
605
+
606
+ function moveIndices(array, indices, offset) {
607
+ if (offset === 0 || indices.length === 0) {
608
+ return [...array];
609
+ }
610
+ // Validate indices are within bounds
611
+ if (indices.some(i => i < 0 || i >= array.length)) {
612
+ return [...array];
613
+ }
614
+ // Check if any index would go out of bounds after the move
615
+ for (const index of indices) {
616
+ const newIndex = index + offset;
617
+ if (newIndex < 0 || newIndex >= array.length) {
618
+ return [...array];
619
+ }
620
+ }
621
+ // Create a copy of the array
622
+ const result = [...array];
623
+ // Sort indices based on movement direction to avoid conflicts
624
+ const sortedIndices = [...indices].sort((a, b) => (offset > 0 ? b - a : a - b));
625
+ // Move each item to its new position
626
+ for (const index of sortedIndices) {
627
+ const item = result[index];
628
+ const newIndex = index + offset;
629
+ // Remove item from current position
630
+ result.splice(index, 1);
631
+ // Insert at new position
632
+ result.splice(newIndex, 0, item);
633
+ }
634
+ return result;
635
+ }
636
+
637
+ /**
638
+ * Generated bundle index. Do not edit.
639
+ */
640
+
641
+ export { AnyPipe, ContainsPipe, FilterChangeEvent, IterablePatchStore, ObjectPatchStore, PreventableEvent, SlicePipe, TakeFirstPipe, buildNested, createIterablePatchStore, createObjectPatchStore, deepEquals, deepMerge, getPercentage, isEmptyObject, isPlainObject, mergeInto, mergePatchInto, moveIndices, patchAt, prunePatch, setAt };
642
+ //# sourceMappingURL=nanahoshi-mona-ui-common.mjs.map