@acorex/platform 21.0.0-next.90 → 21.0.0-next.91

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 (52) hide show
  1. package/fesm2022/acorex-platform-auth.mjs +1 -1
  2. package/fesm2022/acorex-platform-auth.mjs.map +1 -1
  3. package/fesm2022/acorex-platform-common-common-settings.provider-DilV4dql.mjs.map +1 -1
  4. package/fesm2022/acorex-platform-common.mjs +3 -10
  5. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  6. package/fesm2022/acorex-platform-contracts.mjs +1736 -27
  7. package/fesm2022/acorex-platform-contracts.mjs.map +1 -1
  8. package/fesm2022/acorex-platform-core.mjs +6 -1708
  9. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  10. package/fesm2022/acorex-platform-domain-contracts.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  12. package/fesm2022/acorex-platform-layout-components.mjs +2 -2
  13. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  14. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  15. package/fesm2022/acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs.map +1 -1
  16. package/fesm2022/acorex-platform-layout-entity-contracts.mjs +27 -1
  17. package/fesm2022/acorex-platform-layout-entity-contracts.mjs.map +1 -1
  18. package/fesm2022/acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs.map +1 -1
  19. package/fesm2022/acorex-platform-layout-entity.mjs +263 -115
  20. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  21. package/fesm2022/acorex-platform-layout-views.mjs +4 -2
  22. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  23. package/fesm2022/acorex-platform-layout-widget-core.mjs +87 -11
  24. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  25. package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-D10yO28c.mjs.map +1 -1
  26. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +1 -1
  27. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-BvFykMTH.mjs.map +1 -1
  28. package/fesm2022/acorex-platform-layout-widgets.mjs +2 -4
  29. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  30. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  31. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-CWLfNqV0.mjs.map +1 -1
  32. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-C7cT82K2.mjs.map +1 -1
  33. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs.map +1 -1
  34. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  35. package/fesm2022/{acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs → acorex-platform-themes-shared-settings.provider-DxtfyNGS.mjs} +2 -2
  36. package/fesm2022/acorex-platform-themes-shared-settings.provider-DxtfyNGS.mjs.map +1 -0
  37. package/fesm2022/acorex-platform-themes-shared.mjs +2 -2
  38. package/fesm2022/acorex-platform-workflow.mjs +2 -2
  39. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  40. package/package.json +1 -1
  41. package/types/acorex-platform-common.d.ts +3 -5
  42. package/types/acorex-platform-contracts.d.ts +862 -7
  43. package/types/acorex-platform-core.d.ts +64 -921
  44. package/types/acorex-platform-layout-builder.d.ts +3 -3
  45. package/types/acorex-platform-layout-components.d.ts +6 -6
  46. package/types/acorex-platform-layout-designer.d.ts +4 -5
  47. package/types/acorex-platform-layout-entity-contracts.d.ts +90 -3
  48. package/types/acorex-platform-layout-entity.d.ts +45 -102
  49. package/types/acorex-platform-layout-views.d.ts +13 -11
  50. package/types/acorex-platform-layout-widget-core.d.ts +83 -77
  51. package/types/acorex-platform-layout-widgets.d.ts +9 -8
  52. package/fesm2022/acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs.map +0 -1
@@ -1,3 +1,5 @@
1
+ import { isPlainObject, get, set, isNil, isEmpty, isArray, merge, isObjectLike, transform, isEqual, differenceWith, union, cloneDeep } from 'lodash-es';
2
+
1
3
  //#region ---- Core contract types (no Angular / no @acorex/*) ----
2
4
  /** Returns dot-path keys for a nested plain object. */
3
5
  function getNestedKeys(obj, prefix = '') {
@@ -83,6 +85,855 @@ var AXPSystemActionType;
83
85
  })(AXPSystemActionType || (AXPSystemActionType = {}));
84
86
  //#endregion
85
87
 
88
+ //#region ---- Context store contracts ----
89
+ class AXPContextChangeEvent {
90
+ }
91
+ //#endregion
92
+
93
+ /**
94
+ * Additional suggested generic actions for future consideration:
95
+ *
96
+ * Data & Content Actions:
97
+ * - Search = 'search' - Search functionality
98
+ * - Filter = 'filter' - Apply filters
99
+ * - Sort = 'sort' - Sort data
100
+ * - Group = 'group' - Group data
101
+ * - Expand = 'expand' - Expand details
102
+ * - Collapse = 'collapse' - Collapse details
103
+ * - Pin = 'pin' - Pin to favorites
104
+ * - Bookmark = 'bookmark' - Bookmark item
105
+ * - Favorite = 'favorite' - Mark as favorite
106
+ * - Star = 'star' - Star rating
107
+ *
108
+ * Workflow Actions:
109
+ * - Start = 'start' - Start process/workflow
110
+ * - Stop = 'stop' - Stop process
111
+ * - Pause = 'pause' - Pause process
112
+ * - Resume = 'resume' - Resume process
113
+ * - Cancel = 'cancel' - Cancel operation
114
+ * - Complete = 'complete' - Mark as complete
115
+ * - Close = 'close' - Close item
116
+ * - Reopen = 'reopen' - Reopen closed item
117
+ * - Forward = 'forward' - Forward to next step
118
+ * - Back = 'back' - Go back
119
+ *
120
+ * Communication Actions:
121
+ * - Reply = 'reply' - Reply to message
122
+ * - Forward = 'forward' - Forward message
123
+ * - Notify = 'notify' - Send notification
124
+ * - Invite = 'invite' - Invite user
125
+ * - Join = 'join' - Join group/meeting
126
+ * - Leave = 'leave' - Leave group/meeting
127
+ *
128
+ * Security Actions:
129
+ * - Login = 'login' - User login
130
+ * - Logout = 'logout' - User logout
131
+ * - Block = 'block' - Block user/content
132
+ * - Unblock = 'unblock' - Unblock user/content
133
+ * - Ban = 'ban' - Ban user
134
+ * - Unban = 'unban' - Unban user
135
+ * - Verify = 'verify' - Verify identity
136
+ * - Authenticate = 'authenticate' - Authenticate
137
+ *
138
+ * File & Media Actions:
139
+ * - Open = 'open' - Open file
140
+ * - Save = 'save' - Save file
141
+ * - SaveAs = 'save-as' - Save as new file
142
+ * - Attach = 'attach' - Attach file
143
+ * - Detach = 'detach' - Detach file
144
+ * - Compress = 'compress' - Compress files
145
+ * - Extract = 'extract' - Extract archive
146
+ * - Convert = 'convert' - Convert format
147
+ * - Crop = 'crop' - Crop image
148
+ * - Resize = 'resize' - Resize image
149
+ *
150
+ * System Actions:
151
+ * - Sync = 'sync' - Synchronize data
152
+ * - Backup = 'backup' - Create backup
153
+ * - Restore = 'restore' - Restore from backup
154
+ * - Reset = 'reset' - Reset to defaults
155
+ * - Clear = 'clear' - Clear data
156
+ * - Optimize = 'optimize' - Optimize performance
157
+ * - Update = 'update' - Update system
158
+ * - Install = 'install' - Install component
159
+ * - Uninstall = 'uninstall' - Uninstall component
160
+ * - Enable = 'enable' - Enable feature
161
+ * - Disable = 'disable' - Disable feature
162
+ *
163
+ * Analytics & Monitoring:
164
+ * - Monitor = 'monitor' - Monitor activity
165
+ * - Track = 'track' - Track progress
166
+ * - Analyze = 'analyze' - Analyze data
167
+ * - Debug = 'debug' - Debug issue
168
+ * - Log = 'log' - View logs
169
+ * - Alert = 'alert' - Set alert
170
+ * - Dashboard = 'dashboard' - View dashboard
171
+ * - Metrics = 'metrics' - View metrics
172
+ *
173
+ * Collaboration Actions:
174
+ * - Collaborate = 'collaborate' - Start collaboration
175
+ * - Share = 'share' - Share content
176
+ * - Comment = 'comment' - Add comment
177
+ * - Like = 'like' - Like content
178
+ * - Follow = 'follow' - Follow user/content
179
+ * - Subscribe = 'subscribe' - Subscribe to updates
180
+ * - Unsubscribe = 'unsubscribe' - Unsubscribe
181
+ * - Rate = 'rate' - Rate content
182
+ * - Review = 'review' - Review content
183
+ * - Recommend = 'recommend' - Recommend content
184
+ */
185
+ const i18n$1 = (key) => `@general:actions.${key}`;
186
+ const AXPSystemActions = Object.freeze({
187
+ View: {
188
+ key: AXPSystemActionType.View,
189
+ title: i18n$1('view.title'),
190
+ icon: 'fa-light fa-eye',
191
+ color: 'primary',
192
+ descriptions: {
193
+ title: i18n$1('view.title'),
194
+ tooltip: i18n$1('view.description'),
195
+ permission: i18n$1('view.permission'),
196
+ audit: i18n$1('view.audit')
197
+ }
198
+ },
199
+ Create: {
200
+ key: AXPSystemActionType.Create,
201
+ title: i18n$1('create.title'),
202
+ icon: 'fa-light fa-plus',
203
+ color: 'primary',
204
+ descriptions: {
205
+ title: i18n$1('create.title'),
206
+ tooltip: i18n$1('create.description'),
207
+ permission: i18n$1('create.permission'),
208
+ audit: i18n$1('create.audit')
209
+ }
210
+ },
211
+ Edit: {
212
+ key: AXPSystemActionType.Update,
213
+ title: i18n$1('edit.title'),
214
+ icon: 'fa-light fa-pen',
215
+ color: 'default',
216
+ descriptions: {
217
+ title: i18n$1('edit.title'),
218
+ tooltip: i18n$1('edit.description'),
219
+ permission: i18n$1('edit.permission'),
220
+ audit: i18n$1('edit.audit')
221
+ }
222
+ },
223
+ Delete: {
224
+ key: AXPSystemActionType.Delete,
225
+ title: i18n$1('delete.title'),
226
+ icon: 'fa-light fa-trash',
227
+ color: 'danger',
228
+ critical: true,
229
+ descriptions: {
230
+ title: i18n$1('delete.title'),
231
+ tooltip: i18n$1('delete.description'),
232
+ permission: i18n$1('delete.permission'),
233
+ audit: i18n$1('delete.audit')
234
+ }
235
+ },
236
+ Approve: {
237
+ key: AXPSystemActionType.Approve,
238
+ title: i18n$1('approve.title'),
239
+ icon: 'fa-light fa-circle-check',
240
+ color: 'success',
241
+ critical: true,
242
+ descriptions: {
243
+ title: i18n$1('approve.title'),
244
+ tooltip: i18n$1('approve.description'),
245
+ permission: i18n$1('approve.permission'),
246
+ audit: i18n$1('approve.audit')
247
+ }
248
+ },
249
+ Submit: {
250
+ key: AXPSystemActionType.Submit,
251
+ title: i18n$1('submit.title'),
252
+ icon: 'fa-light fa-paper-plane',
253
+ color: 'primary',
254
+ descriptions: {
255
+ title: i18n$1('submit.title'),
256
+ tooltip: i18n$1('submit.description'),
257
+ permission: i18n$1('submit.permission'),
258
+ audit: i18n$1('submit.audit')
259
+ }
260
+ },
261
+ Reject: {
262
+ key: AXPSystemActionType.Reject,
263
+ title: i18n$1('reject.title'),
264
+ icon: 'fa-light fa-ban',
265
+ color: 'danger',
266
+ critical: true,
267
+ descriptions: {
268
+ title: i18n$1('reject.title'),
269
+ tooltip: i18n$1('reject.description'),
270
+ permission: i18n$1('reject.permission'),
271
+ audit: i18n$1('reject.audit')
272
+ }
273
+ },
274
+ Export: {
275
+ key: AXPSystemActionType.Export,
276
+ title: i18n$1('export.title'),
277
+ icon: 'fa-light fa-download',
278
+ color: 'default',
279
+ descriptions: {
280
+ title: i18n$1('export.title'),
281
+ tooltip: i18n$1('export.description'),
282
+ permission: i18n$1('export.permission'),
283
+ audit: i18n$1('export.audit')
284
+ }
285
+ },
286
+ Import: {
287
+ key: AXPSystemActionType.Import,
288
+ title: i18n$1('import.title'),
289
+ icon: 'fa-light fa-upload',
290
+ color: 'default',
291
+ descriptions: {
292
+ title: i18n$1('import.title'),
293
+ tooltip: i18n$1('import.description'),
294
+ permission: i18n$1('import.permission'),
295
+ audit: i18n$1('import.audit')
296
+ }
297
+ },
298
+ Print: {
299
+ key: AXPSystemActionType.Print,
300
+ title: i18n$1('print.title'),
301
+ icon: 'fa-light fa-print',
302
+ color: 'default',
303
+ descriptions: {
304
+ title: i18n$1('print.title'),
305
+ tooltip: i18n$1('print.description'),
306
+ permission: i18n$1('print.permission'),
307
+ audit: i18n$1('print.audit')
308
+ }
309
+ },
310
+ Duplicate: {
311
+ key: AXPSystemActionType.Duplicate,
312
+ title: i18n$1('duplicate.title'),
313
+ icon: 'fa-light fa-clone',
314
+ color: 'warning',
315
+ descriptions: {
316
+ title: i18n$1('duplicate.title'),
317
+ tooltip: i18n$1('duplicate.description'),
318
+ permission: i18n$1('duplicate.permission'),
319
+ audit: i18n$1('duplicate.audit')
320
+ }
321
+ },
322
+ Archive: {
323
+ key: AXPSystemActionType.Archive,
324
+ title: i18n$1('archive.title'),
325
+ icon: 'fa-light fa-box-archive',
326
+ color: 'default',
327
+ descriptions: {
328
+ title: i18n$1('archive.title'),
329
+ tooltip: i18n$1('archive.description'),
330
+ permission: i18n$1('archive.permission'),
331
+ audit: i18n$1('archive.audit')
332
+ }
333
+ },
334
+ Restore: {
335
+ key: AXPSystemActionType.Restore,
336
+ title: i18n$1('restore.title'),
337
+ icon: 'fa-light fa-arrow-rotate-left',
338
+ color: 'default',
339
+ descriptions: {
340
+ title: i18n$1('restore.title'),
341
+ tooltip: i18n$1('restore.description'),
342
+ permission: i18n$1('restore.permission'),
343
+ audit: i18n$1('restore.audit')
344
+ }
345
+ },
346
+ Assign: {
347
+ key: AXPSystemActionType.Assign,
348
+ title: i18n$1('assign.title'),
349
+ icon: 'fa-light fa-user-plus',
350
+ color: 'primary',
351
+ descriptions: {
352
+ title: i18n$1('assign.title'),
353
+ tooltip: i18n$1('assign.description'),
354
+ permission: i18n$1('assign.permission'),
355
+ audit: i18n$1('assign.audit')
356
+ }
357
+ },
358
+ Lock: {
359
+ key: AXPSystemActionType.Lock,
360
+ title: i18n$1('lock.title'),
361
+ icon: 'fa-light fa-lock',
362
+ color: 'warning',
363
+ descriptions: {
364
+ title: i18n$1('lock.title'),
365
+ tooltip: i18n$1('lock.description'),
366
+ permission: i18n$1('lock.permission'),
367
+ audit: i18n$1('lock.audit')
368
+ }
369
+ },
370
+ Unlock: {
371
+ key: AXPSystemActionType.Unlock,
372
+ title: i18n$1('unlock.title'),
373
+ icon: 'fa-light fa-unlock',
374
+ color: 'success',
375
+ descriptions: {
376
+ title: i18n$1('unlock.title'),
377
+ tooltip: i18n$1('unlock.description'),
378
+ permission: i18n$1('unlock.permission'),
379
+ audit: i18n$1('unlock.audit')
380
+ }
381
+ },
382
+ Share: {
383
+ key: AXPSystemActionType.Share,
384
+ title: i18n$1('share.title'),
385
+ icon: 'fa-light fa-share-nodes',
386
+ color: 'info',
387
+ descriptions: {
388
+ title: i18n$1('share.title'),
389
+ tooltip: i18n$1('share.description'),
390
+ permission: i18n$1('share.permission'),
391
+ audit: i18n$1('share.audit')
392
+ }
393
+ },
394
+ Configure: {
395
+ key: AXPSystemActionType.Configure,
396
+ title: i18n$1('configure.title'),
397
+ icon: 'fa-light fa-sliders',
398
+ color: 'primary',
399
+ descriptions: {
400
+ title: i18n$1('configure.title'),
401
+ tooltip: i18n$1('configure.description'),
402
+ permission: i18n$1('configure.permission'),
403
+ audit: i18n$1('configure.audit')
404
+ }
405
+ },
406
+ Reorder: {
407
+ key: AXPSystemActionType.Reorder,
408
+ title: i18n$1('reorder.title'),
409
+ icon: 'fa-light fa-arrow-down-up-across-line',
410
+ color: 'default',
411
+ descriptions: {
412
+ title: i18n$1('reorder.title'),
413
+ tooltip: i18n$1('reorder.description'),
414
+ permission: i18n$1('reorder.permission'),
415
+ audit: i18n$1('reorder.audit')
416
+ }
417
+ },
418
+ Preview: {
419
+ key: AXPSystemActionType.Preview,
420
+ title: i18n$1('preview.title'),
421
+ icon: 'fa-light fa-magnifying-glass',
422
+ color: 'default',
423
+ descriptions: {
424
+ title: i18n$1('preview.title'),
425
+ tooltip: i18n$1('preview.description'),
426
+ permission: i18n$1('preview.permission'),
427
+ audit: i18n$1('preview.audit')
428
+ }
429
+ },
430
+ Publish: {
431
+ key: AXPSystemActionType.Publish,
432
+ title: i18n$1('publish.title'),
433
+ icon: 'fa-light fa-globe',
434
+ color: 'success',
435
+ descriptions: {
436
+ title: i18n$1('publish.title'),
437
+ tooltip: i18n$1('publish.description'),
438
+ permission: i18n$1('publish.permission'),
439
+ audit: i18n$1('publish.audit')
440
+ }
441
+ },
442
+ Unpublish: {
443
+ key: AXPSystemActionType.Unpublish,
444
+ title: i18n$1('unpublish.title'),
445
+ icon: 'fa-light fa-globe-slash',
446
+ color: 'danger',
447
+ descriptions: {
448
+ title: i18n$1('unpublish.title'),
449
+ tooltip: i18n$1('unpublish.description'),
450
+ permission: i18n$1('unpublish.permission'),
451
+ audit: i18n$1('unpublish.audit')
452
+ }
453
+ },
454
+ Upload: {
455
+ key: AXPSystemActionType.Upload,
456
+ title: i18n$1('upload.title'),
457
+ icon: 'fa-light fa-upload',
458
+ color: 'default',
459
+ descriptions: {
460
+ title: i18n$1('upload.title'),
461
+ tooltip: i18n$1('upload.description'),
462
+ permission: i18n$1('upload.permission'),
463
+ audit: i18n$1('upload.audit')
464
+ }
465
+ },
466
+ Download: {
467
+ key: AXPSystemActionType.Download,
468
+ title: i18n$1('download.title'),
469
+ icon: 'fa-light fa-download',
470
+ color: 'default',
471
+ descriptions: {
472
+ title: i18n$1('download.title'),
473
+ tooltip: i18n$1('download.description'),
474
+ permission: i18n$1('download.permission'),
475
+ audit: i18n$1('download.audit')
476
+ }
477
+ },
478
+ Copy: {
479
+ key: AXPSystemActionType.Copy,
480
+ title: i18n$1('copy.title'),
481
+ icon: 'fa-light fa-copy',
482
+ color: 'default',
483
+ descriptions: {
484
+ title: i18n$1('copy.title'),
485
+ tooltip: i18n$1('copy.description'),
486
+ permission: i18n$1('copy.permission'),
487
+ audit: i18n$1('copy.audit')
488
+ }
489
+ },
490
+ Move: {
491
+ key: AXPSystemActionType.Move,
492
+ title: i18n$1('move.title'),
493
+ icon: 'fa-light fa-arrow-right-arrow-left',
494
+ color: 'default',
495
+ descriptions: {
496
+ title: i18n$1('move.title'),
497
+ tooltip: i18n$1('move.description'),
498
+ permission: i18n$1('move.permission'),
499
+ audit: i18n$1('move.audit')
500
+ }
501
+ },
502
+ Rename: {
503
+ key: AXPSystemActionType.Rename,
504
+ title: i18n$1('rename.title'),
505
+ icon: 'fa-light fa-pen',
506
+ color: 'default',
507
+ descriptions: {
508
+ title: i18n$1('rename.title'),
509
+ tooltip: i18n$1('rename.description'),
510
+ permission: i18n$1('rename.permission'),
511
+ audit: i18n$1('rename.audit')
512
+ }
513
+ },
514
+ Manage: {
515
+ key: AXPSystemActionType.Manage,
516
+ title: i18n$1('manage.title'),
517
+ icon: 'fa-light fa-gear',
518
+ color: 'default',
519
+ descriptions: {
520
+ title: i18n$1('manage.title'),
521
+ tooltip: i18n$1('manage.description'),
522
+ permission: i18n$1('manage.permission'),
523
+ audit: i18n$1('manage.audit')
524
+ }
525
+ },
526
+ Info: {
527
+ key: AXPSystemActionType.Info,
528
+ title: i18n$1('info.title'),
529
+ icon: 'fa-light fa-info',
530
+ color: 'default',
531
+ descriptions: {
532
+ title: i18n$1('info.title'),
533
+ tooltip: i18n$1('info.description'),
534
+ permission: i18n$1('info.permission'),
535
+ audit: i18n$1('info.audit')
536
+ }
537
+ },
538
+ Confirm: {
539
+ key: AXPSystemActionType.Confirm,
540
+ title: i18n$1('confirm.title'),
541
+ icon: 'fa-light fa-check',
542
+ color: 'success',
543
+ descriptions: {
544
+ title: i18n$1('confirm.title'),
545
+ tooltip: i18n$1('confirm.description'),
546
+ permission: i18n$1('confirm.permission'),
547
+ audit: i18n$1('confirm.audit')
548
+ }
549
+ },
550
+ Design: {
551
+ key: AXPSystemActionType.Design,
552
+ title: i18n$1('design.title'),
553
+ icon: 'fa-light fa-paintbrush',
554
+ color: 'default',
555
+ descriptions: {
556
+ title: i18n$1('design.title'),
557
+ tooltip: i18n$1('design.description'),
558
+ permission: i18n$1('design.permission'),
559
+ audit: i18n$1('design.audit')
560
+ }
561
+ },
562
+ VersionHistory: {
563
+ key: AXPSystemActionType.VersionHistory,
564
+ title: i18n$1('version-history.title'),
565
+ icon: 'fa-light fa-history',
566
+ color: 'default',
567
+ descriptions: {
568
+ title: i18n$1('version-history.title'),
569
+ tooltip: i18n$1('version-history.description'),
570
+ permission: i18n$1('version-history.permission'),
571
+ audit: i18n$1('version-history.audit')
572
+ }
573
+ },
574
+ Compare: {
575
+ key: AXPSystemActionType.Compare,
576
+ title: i18n$1('compare.title'),
577
+ icon: 'fa-light fa-code-compare',
578
+ color: 'default',
579
+ descriptions: {
580
+ title: i18n$1('compare.title'),
581
+ tooltip: i18n$1('compare.description'),
582
+ permission: i18n$1('compare.permission'),
583
+ audit: i18n$1('compare.audit')
584
+ }
585
+ },
586
+ Comments: {
587
+ key: AXPSystemActionType.Comments,
588
+ title: i18n$1('comments.title'),
589
+ icon: 'fa-light fa-comments',
590
+ color: 'default',
591
+ descriptions: {
592
+ title: i18n$1('comments.title'),
593
+ tooltip: i18n$1('comments.description'),
594
+ permission: i18n$1('comments.permission'),
595
+ audit: i18n$1('comments.audit')
596
+ }
597
+ },
598
+ Sign: {
599
+ key: AXPSystemActionType.Sign,
600
+ title: i18n$1('sign.title'),
601
+ icon: 'fa-light fa-signature',
602
+ color: 'default',
603
+ descriptions: {
604
+ title: i18n$1('sign.title'),
605
+ tooltip: i18n$1('sign.description'),
606
+ permission: i18n$1('sign.permission'),
607
+ audit: i18n$1('sign.audit')
608
+ }
609
+ },
610
+ Setup: {
611
+ key: AXPSystemActionType.Setup,
612
+ title: i18n$1('setup.title'),
613
+ icon: 'fa-light fa-cog',
614
+ color: 'default',
615
+ descriptions: {
616
+ title: i18n$1('setup.title'),
617
+ tooltip: i18n$1('setup.description'),
618
+ permission: i18n$1('setup.permission'),
619
+ audit: i18n$1('setup.audit')
620
+ }
621
+ },
622
+ Send: {
623
+ key: AXPSystemActionType.Send,
624
+ title: i18n$1('send.title'),
625
+ icon: 'fa-light fa-envelope',
626
+ color: 'default',
627
+ descriptions: {
628
+ title: i18n$1('send.title'),
629
+ tooltip: i18n$1('send.description'),
630
+ permission: i18n$1('send.permission'),
631
+ audit: i18n$1('send.audit')
632
+ }
633
+ },
634
+ Report: {
635
+ key: AXPSystemActionType.Report,
636
+ title: i18n$1('report.title'),
637
+ icon: 'fa-light fa-chart-line',
638
+ color: 'default',
639
+ descriptions: {
640
+ title: i18n$1('report.title'),
641
+ tooltip: i18n$1('report.description'),
642
+ permission: i18n$1('report.permission'),
643
+ audit: i18n$1('report.audit')
644
+ }
645
+ },
646
+ Sent: {
647
+ key: AXPSystemActionType.Sent,
648
+ title: i18n$1('sent.title'),
649
+ icon: 'fa-light fa-paper-plane',
650
+ color: 'default',
651
+ descriptions: {
652
+ title: i18n$1('sent.title'),
653
+ tooltip: i18n$1('sent.description'),
654
+ permission: i18n$1('sent.permission'),
655
+ audit: i18n$1('sent.audit')
656
+ }
657
+ },
658
+ Review: {
659
+ key: AXPSystemActionType.Review,
660
+ title: i18n$1('review.title'),
661
+ icon: 'fa-light fa-eye',
662
+ color: 'default',
663
+ descriptions: {
664
+ title: i18n$1('review.title'),
665
+ tooltip: i18n$1('review.description'),
666
+ permission: i18n$1('review.permission'),
667
+ audit: i18n$1('review.audit')
668
+ }
669
+ },
670
+ Generate: {
671
+ key: AXPSystemActionType.Generate,
672
+ title: i18n$1('generate.title'),
673
+ icon: 'fa-light fa-wand-magic-sparkles',
674
+ color: 'primary',
675
+ descriptions: {
676
+ title: i18n$1('generate.title'),
677
+ tooltip: i18n$1('generate.description'),
678
+ permission: i18n$1('generate.permission'),
679
+ audit: i18n$1('generate.audit')
680
+ }
681
+ },
682
+ Refresh: {
683
+ key: AXPSystemActionType.Refresh,
684
+ title: i18n$1('refresh.title'),
685
+ icon: 'fa-light fa-arrows-rotate',
686
+ color: 'default',
687
+ descriptions: {
688
+ title: i18n$1('refresh.title'),
689
+ tooltip: i18n$1('refresh.description'),
690
+ permission: i18n$1('refresh.permission'),
691
+ audit: i18n$1('refresh.audit')
692
+ }
693
+ },
694
+ Reload: {
695
+ key: AXPSystemActionType.Reload,
696
+ title: i18n$1('reload.title'),
697
+ icon: 'fa-light fa-arrows-rotate',
698
+ color: 'default',
699
+ descriptions: {
700
+ title: i18n$1('reload.title'),
701
+ tooltip: i18n$1('reload.description'),
702
+ permission: i18n$1('reload.permission'),
703
+ audit: i18n$1('reload.audit')
704
+ }
705
+ },
706
+ Search: {
707
+ key: AXPSystemActionType.Search,
708
+ title: i18n$1('search.title'),
709
+ icon: 'fa-light fa-magnifying-glass',
710
+ color: 'default',
711
+ descriptions: {
712
+ title: i18n$1('search.title'),
713
+ tooltip: i18n$1('search.description'),
714
+ permission: i18n$1('search.permission'),
715
+ audit: i18n$1('search.audit')
716
+ }
717
+ },
718
+ Filter: {
719
+ key: AXPSystemActionType.Filter,
720
+ title: i18n$1('filter.title'),
721
+ icon: 'fa-light fa-filter',
722
+ color: 'default',
723
+ descriptions: {
724
+ title: i18n$1('filter.title'),
725
+ tooltip: i18n$1('filter.description'),
726
+ permission: i18n$1('filter.permission'),
727
+ audit: i18n$1('filter.audit')
728
+ }
729
+ },
730
+ Sort: {
731
+ key: AXPSystemActionType.Sort,
732
+ title: i18n$1('sort.title'),
733
+ icon: 'fa-light fa-arrow-down-up-across-line',
734
+ color: 'default',
735
+ descriptions: {
736
+ title: i18n$1('sort.title'),
737
+ tooltip: i18n$1('sort.description'),
738
+ permission: i18n$1('sort.permission'),
739
+ audit: i18n$1('sort.audit')
740
+ }
741
+ },
742
+ Start: {
743
+ key: AXPSystemActionType.Start,
744
+ title: i18n$1('start.title'),
745
+ icon: 'fa-light fa-play',
746
+ color: 'success',
747
+ descriptions: {
748
+ title: i18n$1('start.title'),
749
+ tooltip: i18n$1('start.description'),
750
+ permission: i18n$1('start.permission'),
751
+ audit: i18n$1('start.audit')
752
+ }
753
+ },
754
+ Stop: {
755
+ key: AXPSystemActionType.Stop,
756
+ title: i18n$1('stop.title'),
757
+ icon: 'fa-light fa-stop',
758
+ color: 'danger',
759
+ critical: true,
760
+ descriptions: {
761
+ title: i18n$1('stop.title'),
762
+ tooltip: i18n$1('stop.description'),
763
+ permission: i18n$1('stop.permission'),
764
+ audit: i18n$1('stop.audit')
765
+ }
766
+ },
767
+ Pause: {
768
+ key: AXPSystemActionType.Pause,
769
+ title: i18n$1('pause.title'),
770
+ icon: 'fa-light fa-pause',
771
+ color: 'warning',
772
+ descriptions: {
773
+ title: i18n$1('pause.title'),
774
+ tooltip: i18n$1('pause.description'),
775
+ permission: i18n$1('pause.permission'),
776
+ audit: i18n$1('pause.audit')
777
+ }
778
+ },
779
+ Cancel: {
780
+ key: AXPSystemActionType.Cancel,
781
+ title: i18n$1('cancel.title'),
782
+ icon: 'fa-light fa-xmark',
783
+ critical: true,
784
+ descriptions: {
785
+ title: i18n$1('cancel.title'),
786
+ tooltip: i18n$1('cancel.description'),
787
+ permission: i18n$1('cancel.permission'),
788
+ audit: i18n$1('cancel.audit')
789
+ }
790
+ },
791
+ Close: {
792
+ key: AXPSystemActionType.Close,
793
+ title: i18n$1('close.title'),
794
+ icon: 'fa-light fa-xmark',
795
+ color: 'default',
796
+ descriptions: {
797
+ title: i18n$1('close.title'),
798
+ tooltip: i18n$1('close.description'),
799
+ permission: i18n$1('close.permission'),
800
+ audit: i18n$1('close.audit')
801
+ }
802
+ },
803
+ Complete: {
804
+ key: AXPSystemActionType.Complete,
805
+ title: i18n$1('complete.title'),
806
+ icon: 'fa-light fa-check',
807
+ color: 'success',
808
+ descriptions: {
809
+ title: i18n$1('complete.title'),
810
+ tooltip: i18n$1('complete.description'),
811
+ permission: i18n$1('complete.permission'),
812
+ audit: i18n$1('complete.audit')
813
+ }
814
+ },
815
+ Save: {
816
+ key: AXPSystemActionType.Save,
817
+ title: i18n$1('save.title'),
818
+ icon: 'fa-light fa-floppy-disk',
819
+ color: 'primary',
820
+ descriptions: {
821
+ title: i18n$1('save.title'),
822
+ tooltip: i18n$1('save.description'),
823
+ permission: i18n$1('save.permission'),
824
+ audit: i18n$1('save.audit')
825
+ }
826
+ },
827
+ SaveAs: {
828
+ key: AXPSystemActionType.SaveAs,
829
+ title: i18n$1('save-as.title'),
830
+ icon: 'fa-light fa-floppy-disk',
831
+ color: 'default',
832
+ descriptions: {
833
+ title: i18n$1('save-as.title'),
834
+ tooltip: i18n$1('save-as.description'),
835
+ permission: i18n$1('save-as.permission'),
836
+ audit: i18n$1('save-as.audit')
837
+ }
838
+ },
839
+ Sync: {
840
+ key: AXPSystemActionType.Sync,
841
+ title: i18n$1('sync.title'),
842
+ icon: 'fa-light fa-arrows-rotate',
843
+ color: 'default',
844
+ descriptions: {
845
+ title: i18n$1('sync.title'),
846
+ tooltip: i18n$1('sync.description'),
847
+ permission: i18n$1('sync.permission'),
848
+ audit: i18n$1('sync.audit')
849
+ }
850
+ },
851
+ Reset: {
852
+ key: AXPSystemActionType.Reset,
853
+ title: i18n$1('reset.title'),
854
+ icon: 'fa-light fa-arrow-rotate-left',
855
+ color: 'warning',
856
+ critical: true,
857
+ descriptions: {
858
+ title: i18n$1('reset.title'),
859
+ tooltip: i18n$1('reset.description'),
860
+ permission: i18n$1('reset.permission'),
861
+ audit: i18n$1('reset.audit')
862
+ }
863
+ },
864
+ Clear: {
865
+ key: AXPSystemActionType.Clear,
866
+ title: i18n$1('clear.title'),
867
+ icon: 'fa-light fa-eraser',
868
+ color: 'default',
869
+ descriptions: {
870
+ title: i18n$1('clear.title'),
871
+ tooltip: i18n$1('clear.description'),
872
+ permission: i18n$1('clear.permission'),
873
+ audit: i18n$1('clear.audit')
874
+ }
875
+ },
876
+ Distribution: {
877
+ key: AXPSystemActionType.Distribution,
878
+ title: i18n$1('distribution.title'),
879
+ icon: 'fa-light fa-share-nodes',
880
+ color: 'default',
881
+ descriptions: {
882
+ title: i18n$1('distribution.title'),
883
+ tooltip: i18n$1('distribution.description'),
884
+ permission: i18n$1('distribution.permission'),
885
+ audit: i18n$1('distribution.audit')
886
+ }
887
+ },
888
+ });
889
+ function getSystemActions(type) {
890
+ return Object.values(AXPSystemActions).find(action => action.key === type);
891
+ }
892
+ /**
893
+ * Resolves the visual appearance (color and icon) for entity actions.
894
+ */
895
+ function resolveActionLook(actionType) {
896
+ const systemActionType = actionType;
897
+ if (systemActionType) {
898
+ const systemAction = getSystemActions(systemActionType);
899
+ if (systemAction) {
900
+ return {
901
+ color: (systemAction.color || 'default'),
902
+ icon: systemAction.icon || ''
903
+ };
904
+ }
905
+ }
906
+ return {
907
+ color: 'default',
908
+ icon: ''
909
+ };
910
+ }
911
+ /**
912
+ * Resolves the title, description, icon and color for button actions.
913
+ */
914
+ function getActionButton(actionType) {
915
+ const systemActionType = actionType;
916
+ if (systemActionType) {
917
+ const systemAction = getSystemActions(systemActionType);
918
+ if (systemAction) {
919
+ return {
920
+ name: actionType,
921
+ icon: systemAction.icon || '',
922
+ color: systemAction.color || 'default',
923
+ title: systemAction.title,
924
+ description: systemAction.descriptions.title
925
+ };
926
+ }
927
+ }
928
+ return {
929
+ name: actionType,
930
+ title: actionType,
931
+ description: `Perform ${actionType} action`,
932
+ icon: '',
933
+ color: 'default'
934
+ };
935
+ }
936
+
86
937
  //#region ---- CDK / component shims (pure contracts, no @acorex/cdk) ----
87
938
  //#endregion
88
939
 
@@ -120,6 +971,890 @@ function resolvePlatformScopeName(scope) {
120
971
  //#region ---- Core contracts ----
121
972
  //#endregion
122
973
 
974
+ //#region ---- Locale map shape ----
975
+ /** Per-locale string map (`{ 'en-US': '...', 'fa-IR': '...' }`). */
976
+ function isLocaleStringMap(value) {
977
+ if (!isPlainObject(value)) {
978
+ return false;
979
+ }
980
+ const entries = Object.values(value);
981
+ if (entries.length === 0) {
982
+ return false;
983
+ }
984
+ return entries.every((entry) => entry === null || entry === undefined || typeof entry === 'string');
985
+ }
986
+ /**
987
+ * Use locale-map read/write when the option is on or live/saved data is already a map.
988
+ * Auto-enables when API data is a map but the editor option was left off.
989
+ */
990
+ function shouldUseLocaleMapShape(localeMapOptionEnabled, current, saved) {
991
+ return localeMapOptionEnabled || isLocaleStringMap(current) || isLocaleStringMap(saved);
992
+ }
993
+ /** Updates one locale entry; preserves sibling locales from current or saved map. */
994
+ function buildLocaleTextMapValue(current, saved, lang, input) {
995
+ const seed = isLocaleStringMap(current)
996
+ ? { ...current }
997
+ : isLocaleStringMap(saved)
998
+ ? { ...saved }
999
+ : {};
1000
+ seed[lang] = input ?? '';
1001
+ for (const key of Object.keys(seed)) {
1002
+ if ((seed[key] ?? '').trim() === '') {
1003
+ delete seed[key];
1004
+ }
1005
+ }
1006
+ return Object.keys(seed).length === 0 ? null : seed;
1007
+ }
1008
+ //#endregion
1009
+
1010
+ function extractNestedFieldsWildcard(obj, basePath, fields) {
1011
+ const result = {};
1012
+ if (fields.length === 1 && fields[0] === '*') {
1013
+ const fullObj = get(obj, basePath);
1014
+ return isPlainObject(fullObj) ? fullObj : {};
1015
+ }
1016
+ for (const field of fields) {
1017
+ const fullPath = basePath ? `${basePath}.${field}` : field;
1018
+ const value = get(obj, fullPath);
1019
+ set(result, field, value);
1020
+ }
1021
+ return result;
1022
+ }
1023
+ function setSmart(obj, smartPath, value) {
1024
+ const pathParts = smartPath.split('.');
1025
+ const lastPart = pathParts[pathParts.length - 1];
1026
+ const fieldMatch = lastPart.match(/^\{(.+)\}$/);
1027
+ if (!fieldMatch) {
1028
+ // Fix: If value is undefined and we're setting a nested property,
1029
+ // check if the parent object exists and if setting this would result in
1030
+ // all properties being undefined. If so, set the parent to null instead.
1031
+ if (isNil(value) && pathParts.length > 1) {
1032
+ const parentPath = pathParts.slice(0, -1).join('.');
1033
+ const parentObj = get(obj, parentPath);
1034
+ // If parent is already null/undefined, don't recreate the object structure
1035
+ if (isNil(parentObj)) {
1036
+ return obj;
1037
+ }
1038
+ // Check if parent is a plain object (not array, not null)
1039
+ if (isPlainObject(parentObj)) {
1040
+ const existingKeys = Object.keys(parentObj);
1041
+ // Check if all existing properties are null/undefined using lodash
1042
+ const allNil = isEmpty(existingKeys) || existingKeys.every((key) => isNil(parentObj[key]));
1043
+ if (allNil) {
1044
+ // Set parent to null instead of creating/keeping an object with all undefined properties
1045
+ set(obj, parentPath, null);
1046
+ return obj;
1047
+ }
1048
+ }
1049
+ }
1050
+ set(obj, smartPath, value);
1051
+ // After setting, check again if parent should be null using lodash
1052
+ if (isNil(value) && pathParts.length > 1) {
1053
+ const parentPath = pathParts.slice(0, -1).join('.');
1054
+ const parentObj = get(obj, parentPath);
1055
+ if (isPlainObject(parentObj)) {
1056
+ // Use lodash to check if all properties are null/undefined
1057
+ const allNil = Object.keys(parentObj).every((key) => isNil(parentObj[key]));
1058
+ if (allNil) {
1059
+ set(obj, parentPath, null);
1060
+ }
1061
+ }
1062
+ }
1063
+ return obj;
1064
+ }
1065
+ const fields = fieldMatch[1].split(',').map((f) => f.trim());
1066
+ const basePath = pathParts.slice(0, -1).join('.');
1067
+ const [arrayKey, ...restPath] = basePath.split('.');
1068
+ // Make sure the array exists
1069
+ if (!obj[arrayKey])
1070
+ obj[arrayKey] = [];
1071
+ // 🟡 Case A: value is array (normal set)
1072
+ if (isArray(value)) {
1073
+ for (let i = 0; i < value.length; i++) {
1074
+ const item = value[i];
1075
+ const targetItem = obj[arrayKey][i] ?? {};
1076
+ const nested = {};
1077
+ if (restPath.length > 0) {
1078
+ const picked = extractNestedFieldsWildcard(item, restPath.join('.'), fields);
1079
+ set(nested, restPath.join('.'), picked);
1080
+ }
1081
+ else {
1082
+ const picked = extractNestedFieldsWildcard(item, '', fields);
1083
+ Object.assign(nested, picked);
1084
+ }
1085
+ obj[arrayKey][i] = merge({}, targetItem, nested);
1086
+ }
1087
+ }
1088
+ // 🟢 Case B: value is a single value → broadcast
1089
+ else {
1090
+ for (let i = 0; i < obj[arrayKey].length; i++) {
1091
+ const targetItem = obj[arrayKey][i] ?? {};
1092
+ const nested = {};
1093
+ if (restPath.length > 0) {
1094
+ for (const field of fields) {
1095
+ set(nested, `${restPath.join('.')}.${field}`, value);
1096
+ }
1097
+ }
1098
+ else {
1099
+ for (const field of fields) {
1100
+ set(nested, field, value);
1101
+ }
1102
+ }
1103
+ obj[arrayKey][i] = merge({}, targetItem, nested);
1104
+ }
1105
+ }
1106
+ return obj;
1107
+ }
1108
+ function extractFieldsFromPath(obj, basePath, fields) {
1109
+ if (fields.length === 1 && fields[0] === '*') {
1110
+ const fullObj = basePath ? get(obj, basePath) : obj;
1111
+ return isPlainObject(fullObj) ? fullObj : {};
1112
+ }
1113
+ const result = {};
1114
+ for (const field of fields) {
1115
+ const fullPath = basePath ? `${basePath}.${field}` : field;
1116
+ const val = get(obj, fullPath);
1117
+ if (val !== undefined) {
1118
+ result[field] = val;
1119
+ }
1120
+ }
1121
+ return result;
1122
+ }
1123
+ function getSmart(obj, smartPath) {
1124
+ const pathParts = smartPath.split('.');
1125
+ const lastPart = pathParts[pathParts.length - 1];
1126
+ const fieldMatch = lastPart.match(/^\{(.+)\}$/);
1127
+ // Simple get (no fields)
1128
+ if (!fieldMatch) {
1129
+ return get(obj, smartPath);
1130
+ }
1131
+ const fields = fieldMatch[1].split(',').map((f) => f.trim());
1132
+ const basePath = pathParts.slice(0, -1).join('.');
1133
+ const items = get(obj, basePath);
1134
+ if (!isArray(items))
1135
+ return [];
1136
+ const nestedPath = basePath.includes('.') ? basePath.split('.').slice(1).join('.') : '';
1137
+ return items.map((item) => {
1138
+ return extractFieldsFromPath(item, nestedPath, fields);
1139
+ });
1140
+ }
1141
+ function extractValue(value, key = 'id') {
1142
+ if (isNil(value)) {
1143
+ return null;
1144
+ }
1145
+ return isObjectLike(value) ? get(value, key) : value;
1146
+ }
1147
+ function cleanDeep(obj) {
1148
+ return transform(obj, (result, value, key) => {
1149
+ if (isObjectLike(value)) {
1150
+ const cleaned = cleanDeep(value);
1151
+ if (!isEmpty(cleaned)) {
1152
+ result[key] = cleaned;
1153
+ }
1154
+ }
1155
+ else if (!isNil(value) && // not null or undefined
1156
+ !(typeof value === 'string' && value.trim() === '') && // not empty string
1157
+ !(Array.isArray(value) && value.length === 0) // not empty array
1158
+ ) {
1159
+ result[key] = value;
1160
+ }
1161
+ });
1162
+ }
1163
+ function getDeepChanges(obj1, obj2) {
1164
+ const changes = [];
1165
+ function walk(o1, o2, currentPath = []) {
1166
+ // If both values are deeply equal, skip
1167
+ if (isEqual(o1, o2))
1168
+ return;
1169
+ const isObj1Nil = o1 === null || o1 === undefined;
1170
+ const isObj2Nil = o2 === null || o2 === undefined;
1171
+ // If obj1 is null/undefined and obj2 is not, treat entire obj2 as added
1172
+ if (isObj1Nil && !isObj2Nil) {
1173
+ if (isPlainObject(o2)) {
1174
+ for (const key of Object.keys(o2)) {
1175
+ walk(undefined, o2[key], [...currentPath, key]);
1176
+ }
1177
+ }
1178
+ else if (Array.isArray(o2)) {
1179
+ changes.push({
1180
+ path: currentPath.join('.'),
1181
+ oldValue: undefined,
1182
+ newValue: o2,
1183
+ arrayDiff: {
1184
+ added: o2,
1185
+ removed: [],
1186
+ },
1187
+ });
1188
+ }
1189
+ else {
1190
+ changes.push({
1191
+ path: currentPath.join('.'),
1192
+ oldValue: undefined,
1193
+ newValue: o2,
1194
+ });
1195
+ }
1196
+ return;
1197
+ }
1198
+ // If obj2 is null/undefined and obj1 is not, treat entire obj1 as removed
1199
+ if (!isObj1Nil && isObj2Nil) {
1200
+ if (isPlainObject(o1)) {
1201
+ for (const key of Object.keys(o1)) {
1202
+ walk(o1[key], undefined, [...currentPath, key]);
1203
+ }
1204
+ }
1205
+ else if (Array.isArray(o1)) {
1206
+ changes.push({
1207
+ path: currentPath.join('.'),
1208
+ oldValue: o1,
1209
+ newValue: undefined,
1210
+ arrayDiff: {
1211
+ added: [],
1212
+ removed: o1,
1213
+ },
1214
+ });
1215
+ }
1216
+ else {
1217
+ changes.push({
1218
+ path: currentPath.join('.'),
1219
+ oldValue: o1,
1220
+ newValue: undefined,
1221
+ });
1222
+ }
1223
+ return;
1224
+ }
1225
+ // If both are arrays, compare items
1226
+ if (Array.isArray(o1) && Array.isArray(o2)) {
1227
+ if (!isEqual(o1, o2)) {
1228
+ const added = differenceWith(o2, o1, isEqual);
1229
+ const removed = differenceWith(o1, o2, isEqual);
1230
+ changes.push({
1231
+ path: currentPath.join('.'),
1232
+ oldValue: o1,
1233
+ newValue: o2,
1234
+ arrayDiff: {
1235
+ added,
1236
+ removed,
1237
+ },
1238
+ });
1239
+ }
1240
+ return;
1241
+ }
1242
+ // If both are plain objects, walk each key
1243
+ if (isPlainObject(o1) && isPlainObject(o2)) {
1244
+ const allKeys = union(Object.keys(o1), Object.keys(o2));
1245
+ for (const key of allKeys) {
1246
+ walk(o1[key], o2[key], [...currentPath, key]);
1247
+ }
1248
+ return;
1249
+ }
1250
+ // Primitive values or mismatched types
1251
+ changes.push({
1252
+ path: currentPath.join('.'),
1253
+ oldValue: o1,
1254
+ newValue: o2,
1255
+ });
1256
+ }
1257
+ walk(obj1, obj2);
1258
+ return changes;
1259
+ }
1260
+ // Method 1: Returns only changed paths
1261
+ function getChangedPaths(obj1, obj2) {
1262
+ return getDeepChanges(obj1, obj2).map((change) => change.path);
1263
+ }
1264
+ // Method 2: Returns full change entries
1265
+ function getDetailedChanges(obj1, obj2) {
1266
+ return getDeepChanges(obj1, obj2);
1267
+ }
1268
+ function getEnumValues(enumType) {
1269
+ return Object.entries(enumType).map(([key, value]) => ({ id: value, title: key }));
1270
+ }
1271
+ //#region ---- Form value equality (dirty / baseline) ----
1272
+ /** Whether a value uses the multi-language text widget shape (string or locale map). */
1273
+ function isMultiLanguageFormShape(value) {
1274
+ if (value === null || value === undefined) {
1275
+ return true;
1276
+ }
1277
+ if (typeof value === 'string') {
1278
+ return true;
1279
+ }
1280
+ return isLocaleStringMap(value);
1281
+ }
1282
+ /** Drops empty/whitespace locale entries from a multi-language map. */
1283
+ function normalizeLocaleStringMap(value) {
1284
+ const normalized = {};
1285
+ for (const [key, entry] of Object.entries(value)) {
1286
+ if (typeof entry !== 'string') {
1287
+ continue;
1288
+ }
1289
+ const trimmed = entry.trim();
1290
+ if (trimmed !== '') {
1291
+ normalized[key] = trimmed;
1292
+ }
1293
+ }
1294
+ return Object.keys(normalized).length === 0 ? null : normalized;
1295
+ }
1296
+ function compareMultiLanguageLocaleStrings(a, b) {
1297
+ const htmlEqual = compareHtmlFormValues(a, b);
1298
+ if (htmlEqual !== null) {
1299
+ return htmlEqual;
1300
+ }
1301
+ return a === b;
1302
+ }
1303
+ /**
1304
+ * Compares multi-language field values (plain string vs locale map) for dirty/baseline checks.
1305
+ * Returns `null` when either side is not a multi-language shape (caller uses generic normalization).
1306
+ */
1307
+ function compareMultiLanguageFormValues(a, b) {
1308
+ if (!isMultiLanguageFormShape(a) || !isMultiLanguageFormShape(b)) {
1309
+ return null;
1310
+ }
1311
+ const normalizeScalar = (value) => {
1312
+ if (value === null || value === undefined) {
1313
+ return null;
1314
+ }
1315
+ if (typeof value === 'string') {
1316
+ const trimmed = value.trim();
1317
+ return trimmed === '' ? null : trimmed;
1318
+ }
1319
+ if (isLocaleStringMap(value)) {
1320
+ return normalizeLocaleStringMap(value);
1321
+ }
1322
+ return null;
1323
+ };
1324
+ const left = normalizeScalar(a);
1325
+ const right = normalizeScalar(b);
1326
+ if (left === null && right === null) {
1327
+ return true;
1328
+ }
1329
+ if (left === null || right === null) {
1330
+ return false;
1331
+ }
1332
+ if (typeof left === 'string' && typeof right === 'string') {
1333
+ return compareMultiLanguageLocaleStrings(left, right);
1334
+ }
1335
+ if (typeof left === 'string' && typeof right === 'object') {
1336
+ return Object.values(right).some((text) => typeof text === 'string' && compareMultiLanguageLocaleStrings(left, text));
1337
+ }
1338
+ if (typeof right === 'string' && typeof left === 'object') {
1339
+ return Object.values(left).some((text) => typeof text === 'string' && compareMultiLanguageLocaleStrings(right, text));
1340
+ }
1341
+ if (typeof left !== 'object' || typeof right !== 'object') {
1342
+ return false;
1343
+ }
1344
+ const leftMap = left;
1345
+ const rightMap = right;
1346
+ const leftKeys = Object.keys(leftMap).sort();
1347
+ const rightKeys = Object.keys(rightMap).sort();
1348
+ if (leftKeys.length !== rightKeys.length) {
1349
+ return false;
1350
+ }
1351
+ return leftKeys.every((key) => compareMultiLanguageLocaleStrings(leftMap[key], rightMap[key]));
1352
+ }
1353
+ /**
1354
+ * Lookup/select expose may write a resolved MLS string while the baseline keeps the locale map.
1355
+ * Restore baseline shape when the string matches any locale entry.
1356
+ */
1357
+ function shouldRestoreSavedMultiLanguageShape(value, savedAtPath) {
1358
+ if (typeof value !== 'string' || !isLocaleStringMap(savedAtPath)) {
1359
+ return false;
1360
+ }
1361
+ const trimmed = value.trim();
1362
+ if (trimmed === '') {
1363
+ return false;
1364
+ }
1365
+ return Object.values(savedAtPath).some((entry) => typeof entry === 'string' && entry.trim() === trimmed);
1366
+ }
1367
+ /** Decode common HTML entities for rich-text baseline compare. */
1368
+ function decodeHtmlEntities(value) {
1369
+ return value
1370
+ .replace(/&#x([0-9a-f]+);/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
1371
+ .replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(parseInt(dec, 10)))
1372
+ .replace(/&amp;/g, '&')
1373
+ .replace(/&lt;/g, '<')
1374
+ .replace(/&gt;/g, '>')
1375
+ .replace(/&quot;/g, '"');
1376
+ }
1377
+ function looksLikeHtmlFormValue(value) {
1378
+ return /<[a-z][\s\S]*>/i.test(value.trim());
1379
+ }
1380
+ /** Normalizes rich-text HTML for semantic dirty/baseline compare (e.g. Quill `p`/`br` drift). */
1381
+ function normalizeRichTextHtmlForCompare(value) {
1382
+ const html = decodeHtmlEntities(value.trim());
1383
+ if (typeof document === 'undefined') {
1384
+ return html.replace(/\s+/g, ' ').trim();
1385
+ }
1386
+ const doc = new DOMParser().parseFromString(html, 'text/html');
1387
+ return (doc.body.textContent ?? '').replace(/\s+/g, ' ').trim();
1388
+ }
1389
+ /**
1390
+ * Compares rich-text HTML strings by visible text (ignores `p` vs `br` structure drift).
1391
+ * Returns `null` when either side is not HTML markup.
1392
+ */
1393
+ function compareHtmlFormValues(a, b) {
1394
+ if (typeof a !== 'string' || typeof b !== 'string') {
1395
+ return null;
1396
+ }
1397
+ if (!looksLikeHtmlFormValue(a) || !looksLikeHtmlFormValue(b)) {
1398
+ return null;
1399
+ }
1400
+ return normalizeRichTextHtmlForCompare(a) === normalizeRichTextHtmlForCompare(b);
1401
+ }
1402
+ /** Lookup/select filter-mode payload: `{ value, displayText?, operation }`. */
1403
+ function isFilterFormShape(value) {
1404
+ if (!isPlainObject(value)) {
1405
+ return false;
1406
+ }
1407
+ const record = value;
1408
+ return 'value' in record && 'operation' in record;
1409
+ }
1410
+ /**
1411
+ * Compares filter-mode widget values by selection identity; ignores derived `displayText`.
1412
+ */
1413
+ function compareFilterFormValues(a, b) {
1414
+ if (!isFilterFormShape(a) || !isFilterFormShape(b)) {
1415
+ return null;
1416
+ }
1417
+ const left = a;
1418
+ const right = b;
1419
+ if (!isFormValueEqual(left['value'], right['value'])) {
1420
+ return false;
1421
+ }
1422
+ const opLeft = get(left, 'operation.type');
1423
+ const opRight = get(right, 'operation.type');
1424
+ if (opLeft !== undefined || opRight !== undefined) {
1425
+ return opLeft === opRight;
1426
+ }
1427
+ return true;
1428
+ }
1429
+ function isReferenceScalar(value) {
1430
+ return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
1431
+ }
1432
+ /** Scalar id or `{ id }` identity used by lookup/select widgets. */
1433
+ function getReferenceId(value) {
1434
+ if (isNil(value)) {
1435
+ return undefined;
1436
+ }
1437
+ if (isReferenceScalar(value)) {
1438
+ return value;
1439
+ }
1440
+ if (isPlainObject(value)) {
1441
+ const id = get(value, 'id');
1442
+ if (!isNil(id)) {
1443
+ return id;
1444
+ }
1445
+ }
1446
+ return undefined;
1447
+ }
1448
+ /**
1449
+ * Compares scalar selection ids to full lookup/select items (`5` vs `{ id: 5, ... }`).
1450
+ * Does not apply when both sides are objects — those use structural compare so field edits stay dirty.
1451
+ */
1452
+ function compareReferenceFormValues(a, b) {
1453
+ const refA = getReferenceId(a);
1454
+ const refB = getReferenceId(b);
1455
+ if (refA === undefined || refB === undefined) {
1456
+ return null;
1457
+ }
1458
+ const aIsScalar = isReferenceScalar(a);
1459
+ const bIsScalar = isReferenceScalar(b);
1460
+ if (!aIsScalar && !bIsScalar) {
1461
+ return null;
1462
+ }
1463
+ return isEqual(normalizeFormValue(refA), normalizeFormValue(refB));
1464
+ }
1465
+ /**
1466
+ * Semantic equality for lookup/select values when restoring saved baseline shape.
1467
+ * Compares by selection identity (id), including two full items with the same id.
1468
+ */
1469
+ function isSelectionValueEqual(a, b) {
1470
+ const filterEqual = compareFilterFormValues(a, b);
1471
+ if (filterEqual !== null) {
1472
+ return filterEqual;
1473
+ }
1474
+ const refA = getReferenceId(a);
1475
+ const refB = getReferenceId(b);
1476
+ if (refA !== undefined && refB !== undefined) {
1477
+ return isEqual(normalizeFormValue(refA), normalizeFormValue(refB));
1478
+ }
1479
+ return isFormValueEqual(a, b);
1480
+ }
1481
+ /**
1482
+ * Stable sort key for order-insensitive array comparison (after normalization).
1483
+ */
1484
+ function formValueSortKey(value) {
1485
+ if (value === null) {
1486
+ return '\0';
1487
+ }
1488
+ if (typeof value === 'number') {
1489
+ return `n:${value}`;
1490
+ }
1491
+ if (typeof value === 'boolean') {
1492
+ return `b:${value}`;
1493
+ }
1494
+ if (typeof value === 'string') {
1495
+ return `s:${value}`;
1496
+ }
1497
+ try {
1498
+ return `j:${JSON.stringify(value)}`;
1499
+ }
1500
+ catch {
1501
+ return `u:${String(value)}`;
1502
+ }
1503
+ }
1504
+ /**
1505
+ * Sorts normalized array items so order does not affect dirty checks.
1506
+ */
1507
+ function sortNormalizedArrayItems(items) {
1508
+ return [...items].sort((a, b) => formValueSortKey(a).localeCompare(formValueSortKey(b)));
1509
+ }
1510
+ /**
1511
+ * Normalizes a form/context value for semantic baseline comparison.
1512
+ *
1513
+ * Rules:
1514
+ * - `null`, `undefined`, whitespace-only strings, and empty arrays → `null` (empty)
1515
+ * - Numeric strings → numbers (`"5"` and `5` match)
1516
+ * - Arrays → elements normalized; empty/all-empty → `null`; otherwise sorted (order ignored)
1517
+ * - Plain objects → keys sorted; `null`/empty nested values omitted
1518
+ * - `Date` → epoch milliseconds
1519
+ */
1520
+ function normalizeFormValue(value) {
1521
+ if (value === undefined || value === null) {
1522
+ return null;
1523
+ }
1524
+ if (typeof value === 'string') {
1525
+ const trimmed = value.trim();
1526
+ if (trimmed === '') {
1527
+ return null;
1528
+ }
1529
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
1530
+ const num = Number(trimmed);
1531
+ if (!Number.isNaN(num)) {
1532
+ return num;
1533
+ }
1534
+ }
1535
+ return trimmed;
1536
+ }
1537
+ if (typeof value === 'number') {
1538
+ return Number.isNaN(value) ? null : value;
1539
+ }
1540
+ if (typeof value === 'boolean') {
1541
+ return value;
1542
+ }
1543
+ if (value instanceof Date) {
1544
+ return value.getTime();
1545
+ }
1546
+ if (isArray(value)) {
1547
+ const normalizedItems = value
1548
+ .map((item) => normalizeFormValue(item))
1549
+ .filter((item) => item !== null);
1550
+ if (normalizedItems.length === 0) {
1551
+ return null;
1552
+ }
1553
+ return sortNormalizedArrayItems(normalizedItems);
1554
+ }
1555
+ if (isPlainObject(value)) {
1556
+ const record = value;
1557
+ if (isLocaleStringMap(record)) {
1558
+ return normalizeLocaleStringMap(record);
1559
+ }
1560
+ const normalized = {};
1561
+ for (const key of Object.keys(record).sort()) {
1562
+ const next = normalizeFormValue(record[key]);
1563
+ if (next !== null) {
1564
+ normalized[key] = next;
1565
+ }
1566
+ }
1567
+ return normalized;
1568
+ }
1569
+ return value;
1570
+ }
1571
+ /**
1572
+ * Semantic equality for dirty-state and baseline checks.
1573
+ * Prefer over lodash `isEqual` when comparing user-edited form/context data to a saved baseline.
1574
+ *
1575
+ * Arrays: `[]`, `null`, and all-empty lists are equivalent; non-empty arrays compare as multisets (order ignored).
1576
+ */
1577
+ function isFormValueEqual(a, b) {
1578
+ const multiLanguageEqual = compareMultiLanguageFormValues(a, b);
1579
+ if (multiLanguageEqual !== null) {
1580
+ return multiLanguageEqual;
1581
+ }
1582
+ const filterEqual = compareFilterFormValues(a, b);
1583
+ if (filterEqual !== null) {
1584
+ return filterEqual;
1585
+ }
1586
+ const referenceEqual = compareReferenceFormValues(a, b);
1587
+ if (referenceEqual !== null) {
1588
+ return referenceEqual;
1589
+ }
1590
+ if (isArray(a) && isArray(b)) {
1591
+ // Empty repeater rows normalize away; raw length must differ before multiset compare.
1592
+ if (a.length !== b.length) {
1593
+ return false;
1594
+ }
1595
+ return isEqual(normalizeFormValue(a), normalizeFormValue(b));
1596
+ }
1597
+ if (isPlainObject(a) && isPlainObject(b)) {
1598
+ const left = a;
1599
+ const right = b;
1600
+ const keys = new Set([...Object.keys(left), ...Object.keys(right)]);
1601
+ for (const key of keys) {
1602
+ if (!isFormValueEqual(left[key], right[key])) {
1603
+ return false;
1604
+ }
1605
+ }
1606
+ return true;
1607
+ }
1608
+ if (typeof a === 'string' && typeof b === 'string') {
1609
+ const htmlEqual = compareHtmlFormValues(a, b);
1610
+ if (htmlEqual !== null) {
1611
+ return htmlEqual;
1612
+ }
1613
+ }
1614
+ return isEqual(normalizeFormValue(a), normalizeFormValue(b));
1615
+ }
1616
+ /**
1617
+ * Returns whether `current` differs from the saved/clean `baseline` snapshot.
1618
+ */
1619
+ function isFormContextDirty(current, baseline) {
1620
+ return !isFormValueEqual(current, baseline);
1621
+ }
1622
+ /**
1623
+ * Lists paths where live context differs from baseline (for dirty-state trace logs).
1624
+ */
1625
+ function summarizeFormContextDirtyDiff(current, baseline, maxEntries = 12) {
1626
+ const diffs = [];
1627
+ const walk = (path, currentValue, baselineValue) => {
1628
+ if (diffs.length >= maxEntries) {
1629
+ return;
1630
+ }
1631
+ if (isFormValueEqual(currentValue, baselineValue)) {
1632
+ return;
1633
+ }
1634
+ const bothPlainObjects = isPlainObject(currentValue) &&
1635
+ isPlainObject(baselineValue) &&
1636
+ !isArray(currentValue) &&
1637
+ !isArray(baselineValue);
1638
+ if (bothPlainObjects) {
1639
+ const left = currentValue;
1640
+ const right = baselineValue;
1641
+ const keys = new Set([...Object.keys(left), ...Object.keys(right)]);
1642
+ for (const key of keys) {
1643
+ if (diffs.length >= maxEntries) {
1644
+ return;
1645
+ }
1646
+ const nextPath = path ? `${path}.${key}` : key;
1647
+ walk(nextPath, left[key], right[key]);
1648
+ }
1649
+ return;
1650
+ }
1651
+ diffs.push({
1652
+ path: path || '(root)',
1653
+ current: currentValue,
1654
+ baseline: baselineValue,
1655
+ selectionEqual: isSelectionValueEqual(currentValue, baselineValue),
1656
+ });
1657
+ };
1658
+ walk('', current, baseline);
1659
+ return diffs;
1660
+ }
1661
+ /**
1662
+ * Clones a context object for use as a dirty-tracking baseline.
1663
+ */
1664
+ function captureFormContextBaseline(context) {
1665
+ return cloneDeep(context);
1666
+ }
1667
+ //#endregion
1668
+
1669
+ //#region ---- Unwrapping ----
1670
+ /**
1671
+ * If `raw` is a plain non-array object with a `value` property, returns `value`; otherwise returns `raw`.
1672
+ */
1673
+ function unwrapValueProperty(raw) {
1674
+ if (raw && typeof raw === 'object' && !Array.isArray(raw) && !(raw instanceof Date) && 'value' in raw) {
1675
+ return raw.value;
1676
+ }
1677
+ return raw;
1678
+ }
1679
+ //#endregion
1680
+ //#region ---- Scalar coercion ----
1681
+ /**
1682
+ * Coerces to a trimmed string. Plain objects may carry `{ value }` from setting widgets or `{ id }` from select payloads using `valueField: 'id'`.
1683
+ */
1684
+ function coerceUnknownToTrimmedString(raw) {
1685
+ if (typeof raw === 'string') {
1686
+ return raw.trim();
1687
+ }
1688
+ if (raw && typeof raw === 'object' && !Array.isArray(raw) && !(raw instanceof Date)) {
1689
+ const r = raw;
1690
+ if ('value' in r && r['value'] != null) {
1691
+ return String(r['value']).trim();
1692
+ }
1693
+ if ('id' in r && r['id'] != null) {
1694
+ return String(r['id']).trim();
1695
+ }
1696
+ }
1697
+ return '';
1698
+ }
1699
+ /**
1700
+ * Coerces to boolean: direct booleans pass through; wrapped `{ value: true | 'true' }` is respected; otherwise false.
1701
+ */
1702
+ function coerceUnknownToBoolean(raw) {
1703
+ if (typeof raw === 'boolean') {
1704
+ return raw;
1705
+ }
1706
+ if (raw && typeof raw === 'object' && 'value' in raw) {
1707
+ const v = raw.value;
1708
+ return v === true || v === 'true';
1709
+ }
1710
+ return false;
1711
+ }
1712
+ /** Parses a finite number after optional `{ value }` unwrap; non-finite or empty string yields NaN. */
1713
+ function coerceUnknownToFiniteNumber(raw) {
1714
+ const v = unwrapValueProperty(raw);
1715
+ if (v === null || v === undefined) {
1716
+ return NaN;
1717
+ }
1718
+ if (typeof v === 'number') {
1719
+ return Number.isFinite(v) ? v : NaN;
1720
+ }
1721
+ if (typeof v === 'boolean') {
1722
+ return v ? 1 : 0;
1723
+ }
1724
+ if (typeof v === 'string') {
1725
+ const t = v.trim();
1726
+ if (t === '') {
1727
+ return NaN;
1728
+ }
1729
+ const n = Number(t);
1730
+ return Number.isFinite(n) ? n : NaN;
1731
+ }
1732
+ return NaN;
1733
+ }
1734
+ /** Parses a Date after optional `{ value }` unwrap; invalid input yields Invalid Date. */
1735
+ function coerceUnknownToDate(raw) {
1736
+ const v = unwrapValueProperty(raw);
1737
+ if (v === null || v === undefined) {
1738
+ return new Date(NaN);
1739
+ }
1740
+ if (v instanceof Date) {
1741
+ return new Date(v.getTime());
1742
+ }
1743
+ if (typeof v === 'number' && Number.isFinite(v)) {
1744
+ return new Date(v);
1745
+ }
1746
+ if (typeof v === 'string') {
1747
+ const t = v.trim();
1748
+ if (t === '') {
1749
+ return new Date(NaN);
1750
+ }
1751
+ return new Date(t);
1752
+ }
1753
+ return new Date(NaN);
1754
+ }
1755
+ //#endregion
1756
+
1757
+ function extractTextFromHtml(value) {
1758
+ const div = document.createElement('div');
1759
+ div.innerHTML = value;
1760
+ return div.textContent || div.innerText || '';
1761
+ }
1762
+ /**
1763
+ * True when the string likely contains HTML markup (e.g. `<p>`, `<ul>`), as opposed to plain text.
1764
+ * Used to choose innerHTML vs text interpolation for multilingual fields.
1765
+ */
1766
+ function containsHtmlMarkup(value) {
1767
+ if (value == null) {
1768
+ return false;
1769
+ }
1770
+ const t = value.trim();
1771
+ if (!t) {
1772
+ return false;
1773
+ }
1774
+ return /<\/?[a-z][\s\S]*?>/i.test(t);
1775
+ }
1776
+ /**
1777
+ * Generate kebab-case group name from title
1778
+ */
1779
+ function generateKebabCase(title) {
1780
+ return title
1781
+ .toLowerCase()
1782
+ .trim()
1783
+ .replace(/[^a-z0-9\s-]/g, '') // Remove special characters
1784
+ .replace(/\s+/g, '-') // Replace spaces with hyphens
1785
+ .replace(/-+/g, '-') // Replace multiple hyphens with single
1786
+ .replace(/^-+|-+$/g, ''); // Remove leading/trailing hyphens
1787
+ }
1788
+
1789
+ //#region ---- Shared utilities ----
1790
+ //#endregion
1791
+
1792
+ //#region ---- Imports ----
1793
+ //#endregion
1794
+ //#region ---- Resolve ----
1795
+ /**
1796
+ * Resolves {@link AXPMultiLanguageString} to a plain string for the given locale.
1797
+ */
1798
+ function resolveMultiLanguageString(value, locale) {
1799
+ if (value == null || value === '') {
1800
+ return '';
1801
+ }
1802
+ if (typeof value === 'string') {
1803
+ return value;
1804
+ }
1805
+ const direct = value[locale];
1806
+ if (typeof direct === 'string' && direct.length > 0) {
1807
+ return direct;
1808
+ }
1809
+ const enUS = value['en-US'];
1810
+ if (typeof enUS === 'string' && enUS.length > 0) {
1811
+ return enUS;
1812
+ }
1813
+ for (const entry of Object.values(value)) {
1814
+ if (typeof entry === 'string' && entry.length > 0) {
1815
+ return entry;
1816
+ }
1817
+ }
1818
+ return '';
1819
+ }
1820
+ //#endregion
1821
+
1822
+ //#region ---- Imports ----
1823
+ //#endregion
1824
+ //#region ---- Compare & sort ----
1825
+ const DEFAULT_COLLATOR_OPTIONS = { sensitivity: 'base' };
1826
+ /**
1827
+ * Locale-aware comparison of {@link AXPMultiLanguageString} values (plain string, `@scope:key`, or locale map).
1828
+ * Resolves each side with {@link resolveMultiLanguageString} for `locale`, then compares with `String#localeCompare`.
1829
+ */
1830
+ function compareMultiLanguageStrings(a, b, locale, collatorOptions = DEFAULT_COLLATOR_OPTIONS) {
1831
+ const sa = resolveMultiLanguageString(a ?? '', locale);
1832
+ const sb = resolveMultiLanguageString(b ?? '', locale);
1833
+ return sa.localeCompare(sb, locale, collatorOptions);
1834
+ }
1835
+ /**
1836
+ * Stable sort copy: orders items by resolved string for `getValue(item)` using the active `locale`.
1837
+ */
1838
+ function sortByMultiLanguageString(items, getValue, locale, collatorOptions) {
1839
+ return [...items].sort((x, y) => compareMultiLanguageStrings(getValue(x), getValue(y), locale, collatorOptions));
1840
+ }
1841
+ /**
1842
+ * True when the resolved value contains `query` (case-insensitive) for `locale`.
1843
+ * Useful for search/filter flows over {@link AXPMultiLanguageString}.
1844
+ */
1845
+ function searchInMultiLanguageString(value, query, locale) {
1846
+ const q = query.trim().toLocaleLowerCase(locale);
1847
+ if (!q) {
1848
+ return true;
1849
+ }
1850
+ const text = resolveMultiLanguageString(value ?? '', locale).toLocaleLowerCase(locale);
1851
+ return text.includes(q);
1852
+ }
1853
+ //#endregion
1854
+
1855
+ //#region ---- Multi-language string utilities ----
1856
+ //#endregion
1857
+
123
1858
  //#region ---- Category & entity operation types ----
124
1859
  //#endregion
125
1860
 
@@ -892,32 +2627,6 @@ function createMultiLanguageString(enUS, faIR) {
892
2627
  'fa-IR': faIR ?? enUS,
893
2628
  };
894
2629
  }
895
- /**
896
- * Resolves {@link AXPMultiLanguageString} to a plain string for the given locale.
897
- * Standalone copy for connectivity mocks — no dependency on @acorex/core/translation.
898
- */
899
- function resolveMultiLanguageString(value, locale) {
900
- if (value == null || value === '') {
901
- return '';
902
- }
903
- if (typeof value === 'string') {
904
- return value;
905
- }
906
- const direct = value[locale];
907
- if (typeof direct === 'string' && direct.length > 0) {
908
- return direct;
909
- }
910
- const enUS = value['en-US'];
911
- if (typeof enUS === 'string' && enUS.length > 0) {
912
- return enUS;
913
- }
914
- for (const entry of Object.values(value)) {
915
- if (typeof entry === 'string' && entry.length > 0) {
916
- return entry;
917
- }
918
- }
919
- return '';
920
- }
921
2630
  /**
922
2631
  * Lightweight data helpers for mock seed files.
923
2632
  * Standalone copy for connectivity mocks — no dependency on @acorex/platform/core.
@@ -1186,5 +2895,5 @@ class AXPIntegrationMissingScopeError extends Error {
1186
2895
  * Generated bundle index. Do not edit.
1187
2896
  */
1188
2897
 
1189
- export { AXPDataGenerator, AXPExportTemplateToken, AXPFileStorageStatus, AXPIntegrationExpiredError, AXPIntegrationMissingScopeError, AXPIntegrationNotConnectedError, AXPPlatformCoreDataSourceKeys, AXPPlatformScope, AXPRegionalSetting, AXPStatusProvider, AXPSystemActionType, AXPSystemStatusType, AXPSystemStatuses, AXPWidgetsCatalog, AXPWidgetsList, AXP_INTEGRATION_AUTH_METHOD_TYPE, AXP_INTEGRATION_CAPABILITY, AXP_INTEGRATION_CATEGORY, AXP_INTEGRATION_CONNECTION_SCOPE, AXP_INTEGRATION_CONNECTION_STATUS, AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY, createMultiLanguageString, getNestedKeys, getStatusInfo, getSystemStatus, normalizeDefinitionCategories, resolveMultiLanguageString, resolvePlatformScopeKey, resolvePlatformScopeName, resolveStatusLook, systemStatusToDefinition };
2898
+ export { AXPContextChangeEvent, AXPDataGenerator, AXPExportTemplateToken, AXPFileStorageStatus, AXPIntegrationExpiredError, AXPIntegrationMissingScopeError, AXPIntegrationNotConnectedError, AXPPlatformCoreDataSourceKeys, AXPPlatformScope, AXPRegionalSetting, AXPStatusProvider, AXPSystemActionType, AXPSystemActions, AXPSystemStatusType, AXPSystemStatuses, AXPWidgetsCatalog, AXPWidgetsList, AXP_INTEGRATION_AUTH_METHOD_TYPE, AXP_INTEGRATION_CAPABILITY, AXP_INTEGRATION_CATEGORY, AXP_INTEGRATION_CONNECTION_SCOPE, AXP_INTEGRATION_CONNECTION_STATUS, AXP_PREVIEW_WIDGET_FIELD_COMMAND_KEY, buildLocaleTextMapValue, captureFormContextBaseline, cleanDeep, coerceUnknownToBoolean, coerceUnknownToDate, coerceUnknownToFiniteNumber, coerceUnknownToTrimmedString, compareMultiLanguageStrings, containsHtmlMarkup, createMultiLanguageString, extractNestedFieldsWildcard, extractTextFromHtml, extractValue, generateKebabCase, getActionButton, getChangedPaths, getDetailedChanges, getEnumValues, getNestedKeys, getSmart, getStatusInfo, getSystemActions, getSystemStatus, isFormContextDirty, isFormValueEqual, isLocaleStringMap, isSelectionValueEqual, normalizeDefinitionCategories, resolveActionLook, resolveMultiLanguageString, resolvePlatformScopeKey, resolvePlatformScopeName, resolveStatusLook, searchInMultiLanguageString, setSmart, shouldRestoreSavedMultiLanguageShape, shouldUseLocaleMapShape, sortByMultiLanguageString, summarizeFormContextDirtyDiff, systemStatusToDefinition, unwrapValueProperty };
1190
2899
  //# sourceMappingURL=acorex-platform-contracts.mjs.map