@ngxviewbuilder/runtime 0.12.2 → 0.12.4

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 (91) hide show
  1. package/fesm2022/ngxviewbuilder-runtime-autocomplete-element-DaMuvB5p.mjs +1 -0
  2. package/fesm2022/ngxviewbuilder-runtime-avatar-element-DCy3AEHW.mjs +1 -0
  3. package/fesm2022/ngxviewbuilder-runtime-badge-element-Ci2NV1MC.mjs +1 -0
  4. package/fesm2022/ngxviewbuilder-runtime-breadcrumbs-element-Bcq5oGI8.mjs +1 -0
  5. package/fesm2022/ngxviewbuilder-runtime-button-element-DzJfdCcx.mjs +1 -0
  6. package/fesm2022/ngxviewbuilder-runtime-chart-element-BCg3CI8N.mjs +1 -0
  7. package/fesm2022/ngxviewbuilder-runtime-checkbox-element-Cj3HQvkO.mjs +1 -0
  8. package/fesm2022/ngxviewbuilder-runtime-column-p1eNMy75.mjs +43 -0
  9. package/fesm2022/ngxviewbuilder-runtime-custom-html-element-BMdxXckt.mjs +3 -0
  10. package/fesm2022/ngxviewbuilder-runtime-date-range-element-BE_9Ba_-.mjs +1 -0
  11. package/fesm2022/ngxviewbuilder-runtime-datepicker-element-BFwwyRt-.mjs +1 -0
  12. package/fesm2022/{ngxviewbuilder-runtime-divider-element-Bit-YRpc.mjs → ngxviewbuilder-runtime-divider-element-CbCCZ1Qu.mjs} +1 -1
  13. package/fesm2022/ngxviewbuilder-runtime-element-wrapper-EBaWVZvf.mjs +1 -0
  14. package/fesm2022/ngxviewbuilder-runtime-file-upload-element-BYU3tLZw.mjs +1 -0
  15. package/fesm2022/ngxviewbuilder-runtime-icon-element-CLqWvjKL.mjs +1 -0
  16. package/fesm2022/ngxviewbuilder-runtime-iframe-element-Bl74Zm6Y.mjs +1 -0
  17. package/fesm2022/ngxviewbuilder-runtime-image-element-iDSaX41Y.mjs +1 -0
  18. package/fesm2022/ngxviewbuilder-runtime-list-box-element-DrDTjcW5.mjs +1 -0
  19. package/fesm2022/ngxviewbuilder-runtime-list-grid-element-CgiY-Lcy.mjs +1 -0
  20. package/fesm2022/ngxviewbuilder-runtime-mark-for-check-on-property-change-WxfEoWah.mjs +1 -0
  21. package/fesm2022/ngxviewbuilder-runtime-message-card-element-60xyNliB.mjs +1 -0
  22. package/fesm2022/ngxviewbuilder-runtime-multi-select-element-DHqMGyjB.mjs +1 -0
  23. package/fesm2022/ngxviewbuilder-runtime-ngx-view-builder-api.service-BYA8UfCA.mjs +4 -0
  24. package/fesm2022/ngxviewbuilder-runtime-number-element-CdhEZPYp.mjs +1 -0
  25. package/fesm2022/ngxviewbuilder-runtime-number-stepper-element-f9KrH_YF.mjs +1 -0
  26. package/fesm2022/ngxviewbuilder-runtime-nvb-select-Dkh4SIap.mjs +1 -0
  27. package/fesm2022/ngxviewbuilder-runtime-page-title-element-8T25QlMQ.mjs +1 -0
  28. package/fesm2022/ngxviewbuilder-runtime-phone-input-element-CZCkF7lo.mjs +1 -0
  29. package/fesm2022/ngxviewbuilder-runtime-progress-bar-element-BqCwBXpQ.mjs +1 -0
  30. package/fesm2022/ngxviewbuilder-runtime-radio-element-CvVAePSa.mjs +1 -0
  31. package/fesm2022/{ngxviewbuilder-runtime-rich-text-element-DAl3vSxG.mjs → ngxviewbuilder-runtime-rich-text-element-D4knphJa.mjs} +2 -2
  32. package/fesm2022/ngxviewbuilder-runtime-router-outlet-element-BzouCbdg.mjs +1 -0
  33. package/fesm2022/ngxviewbuilder-runtime-select-button-element-CtysP-cz.mjs +1 -0
  34. package/fesm2022/ngxviewbuilder-runtime-select-element-Be-lGWkG.mjs +1 -0
  35. package/fesm2022/ngxviewbuilder-runtime-signature-pad-element-CJqDTYnO.mjs +1 -0
  36. package/fesm2022/ngxviewbuilder-runtime-single-checkbox-element-DrJcESGd.mjs +1 -0
  37. package/fesm2022/ngxviewbuilder-runtime-slider-element-CsTb-3m4.mjs +1 -0
  38. package/fesm2022/{ngxviewbuilder-runtime-spacer-element-BGJ-ObOf.mjs → ngxviewbuilder-runtime-spacer-element-OAgkc5so.mjs} +1 -1
  39. package/fesm2022/ngxviewbuilder-runtime-stats-card-element-CzjJKd-Y.mjs +1 -0
  40. package/fesm2022/ngxviewbuilder-runtime-table-element-C25OdqZn.mjs +1 -0
  41. package/fesm2022/ngxviewbuilder-runtime-text-element-0eMB6sBj.mjs +1 -0
  42. package/fesm2022/ngxviewbuilder-runtime-textarea-element-BRJA5Lzb.mjs +1 -0
  43. package/fesm2022/ngxviewbuilder-runtime-time-picker-element-3qN3oxZF.mjs +1 -0
  44. package/fesm2022/ngxviewbuilder-runtime-toast-element-CzKIkQVY.mjs +1 -0
  45. package/fesm2022/ngxviewbuilder-runtime-toggle-switch-element-D9svjkSP.mjs +1 -0
  46. package/fesm2022/ngxviewbuilder-runtime-video-element-CliJnlMX.mjs +1 -0
  47. package/fesm2022/ngxviewbuilder-runtime.mjs +1 -1
  48. package/package.json +1 -1
  49. package/types/ngxviewbuilder-runtime.d.ts +254 -41
  50. package/fesm2022/ngxviewbuilder-runtime-autocomplete-element-DWbMobho.mjs +0 -1
  51. package/fesm2022/ngxviewbuilder-runtime-avatar-element-98vFX6ZL.mjs +0 -1
  52. package/fesm2022/ngxviewbuilder-runtime-badge-element-WdHbUp_X.mjs +0 -1
  53. package/fesm2022/ngxviewbuilder-runtime-breadcrumbs-element-qlHbgWfh.mjs +0 -1
  54. package/fesm2022/ngxviewbuilder-runtime-button-element-BWI56rGB.mjs +0 -1
  55. package/fesm2022/ngxviewbuilder-runtime-chart-element-wN98hSa2.mjs +0 -1
  56. package/fesm2022/ngxviewbuilder-runtime-checkbox-element-yAUJgMY7.mjs +0 -1
  57. package/fesm2022/ngxviewbuilder-runtime-column-CEOo23I_.mjs +0 -43
  58. package/fesm2022/ngxviewbuilder-runtime-custom-html-element-D7ezjkGw.mjs +0 -3
  59. package/fesm2022/ngxviewbuilder-runtime-date-range-element-kRoWWvXf.mjs +0 -1
  60. package/fesm2022/ngxviewbuilder-runtime-datepicker-element-Co2_JHM2.mjs +0 -1
  61. package/fesm2022/ngxviewbuilder-runtime-dynamic-text.pipe-BUJ4fCqt.mjs +0 -1
  62. package/fesm2022/ngxviewbuilder-runtime-element-wrapper-D0lfZvuW.mjs +0 -4
  63. package/fesm2022/ngxviewbuilder-runtime-file-upload-element-B1sGgTAJ.mjs +0 -1
  64. package/fesm2022/ngxviewbuilder-runtime-icon-element-BBV3IriU.mjs +0 -1
  65. package/fesm2022/ngxviewbuilder-runtime-iframe-element-DAKlSTTJ.mjs +0 -1
  66. package/fesm2022/ngxviewbuilder-runtime-image-element-Co9eNt6D.mjs +0 -1
  67. package/fesm2022/ngxviewbuilder-runtime-list-box-element-BkqVfq4H.mjs +0 -1
  68. package/fesm2022/ngxviewbuilder-runtime-list-grid-element-BsVooLf9.mjs +0 -1
  69. package/fesm2022/ngxviewbuilder-runtime-message-card-element-DOlB-FAw.mjs +0 -1
  70. package/fesm2022/ngxviewbuilder-runtime-multi-select-element-5YHKOX69.mjs +0 -1
  71. package/fesm2022/ngxviewbuilder-runtime-number-element-MNO3T8kR.mjs +0 -1
  72. package/fesm2022/ngxviewbuilder-runtime-number-stepper-element-Jl6DZNAb.mjs +0 -1
  73. package/fesm2022/ngxviewbuilder-runtime-nvb-select-DuPHFQk6.mjs +0 -1
  74. package/fesm2022/ngxviewbuilder-runtime-page-title-element-BdfBrnaW.mjs +0 -1
  75. package/fesm2022/ngxviewbuilder-runtime-phone-input-element-BDZkscMD.mjs +0 -1
  76. package/fesm2022/ngxviewbuilder-runtime-progress-bar-element-Dg7Y6-jq.mjs +0 -1
  77. package/fesm2022/ngxviewbuilder-runtime-radio-element-xscwN_Hs.mjs +0 -1
  78. package/fesm2022/ngxviewbuilder-runtime-router-outlet-element-BpGv-kkh.mjs +0 -1
  79. package/fesm2022/ngxviewbuilder-runtime-select-button-element-BPH_N-fd.mjs +0 -1
  80. package/fesm2022/ngxviewbuilder-runtime-select-element-B_FOlIzR.mjs +0 -1
  81. package/fesm2022/ngxviewbuilder-runtime-signature-pad-element-BxZMh4-H.mjs +0 -1
  82. package/fesm2022/ngxviewbuilder-runtime-single-checkbox-element-DZiHDP6i.mjs +0 -1
  83. package/fesm2022/ngxviewbuilder-runtime-slider-element-NBbgW-1w.mjs +0 -1
  84. package/fesm2022/ngxviewbuilder-runtime-stats-card-element-DUxzXyTC.mjs +0 -1
  85. package/fesm2022/ngxviewbuilder-runtime-table-element-yvDWlU-z.mjs +0 -1
  86. package/fesm2022/ngxviewbuilder-runtime-text-element-C9W3pPu7.mjs +0 -1
  87. package/fesm2022/ngxviewbuilder-runtime-textarea-element-55rqT93w.mjs +0 -1
  88. package/fesm2022/ngxviewbuilder-runtime-time-picker-element-C1p0lG_4.mjs +0 -1
  89. package/fesm2022/ngxviewbuilder-runtime-toast-element-Dc8tFqFS.mjs +0 -1
  90. package/fesm2022/ngxviewbuilder-runtime-toggle-switch-element-DEmC69ye.mjs +0 -1
  91. package/fesm2022/ngxviewbuilder-runtime-video-element-COR0eePU.mjs +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ngxviewbuilder/runtime",
3
- "version": "0.12.2",
3
+ "version": "0.12.4",
4
4
  "description": "Native Angular runtime for NGX View Builder: renders forms, dashboards, data tables and guided flows defined as JSON.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "homepage": "https://ngxviewbuilder.io",
@@ -955,6 +955,87 @@ export interface IDataSourceChangedEvent {
955
955
  result: unknown;
956
956
  dataSource: DataSourceModel;
957
957
  }
958
+ export interface ITranslationEntry {
959
+ key: string;
960
+ label: string;
961
+ sourceValue: string;
962
+ structurePath?: string;
963
+ }
964
+ /** One translatable text of a view, as `api.getContentTranslationKeys()` lists it. */
965
+ export interface INgxViewBuilderContentTranslationKey {
966
+ key: string;
967
+ label: string;
968
+ /** The text in the view's default language. */
969
+ source: string;
970
+ /** What each other language has for it so far. */
971
+ translations: Record<string, string>;
972
+ /** The view's other languages that have no text for it yet. */
973
+ missing: string[];
974
+ }
975
+ export declare class LocalizationService {
976
+ private templateEngineService;
977
+ /**
978
+ * Translations the host supplies through `api.setContentTranslations`, kept apart from
979
+ * the structure so they survive a view loaded later or replaced. Same shape and keys
980
+ * as `localization.texts`; on a key both define, the host's text wins.
981
+ */
982
+ private hostTexts;
983
+ /**
984
+ * The language the host asked for with `api.setLanguage` (or the runtime's `language`
985
+ * input). It beats the view's own `settings.language`, which is only the default: a view
986
+ * that arrives after the host picked a language still renders in that language.
987
+ */
988
+ private activeLanguage;
989
+ setActiveLanguage(language: string | null | undefined): void;
990
+ getActiveLanguage(): string;
991
+ setHostTexts(texts: Record<string, Record<string, string>>, merge?: boolean): void;
992
+ getHostTexts(): Record<string, Record<string, string>>;
993
+ /** The structure's own texts with the host's on top, per language. */
994
+ getEffectiveTexts(structure: IStructure | null | undefined): Record<string, Record<string, string>>;
995
+ /**
996
+ * Keeps translations on the item they belong to when a list is reordered or shortened.
997
+ * Keys are index paths (`elements.orders.columnsConfig[2].label`), so moving the third
998
+ * column to the front would otherwise hand its translation to whatever column landed at
999
+ * index 2. Items match by `id`, then by position when only fields changed, then by
1000
+ * `key`, `value` or `name`. A removed item's translations are dropped.
1001
+ */
1002
+ remapListTranslations(structure: IStructure | null | undefined, listPath: string, previous: unknown, next: unknown): boolean;
1003
+ private matchListItems;
1004
+ ensureLocalization(structure: IStructure | null | undefined): ILocalization;
1005
+ getTranslationEntries(structure: IStructure | null | undefined): ITranslationEntry[];
1006
+ applyTranslations(structure: IStructure): IStructure;
1007
+ /**
1008
+ * Texts an element only has as a default of its model (the two tabs a new tabs element
1009
+ * starts with, a table's empty message) are not in the saved JSON, so `applyTranslations`
1010
+ * had nothing to write their translation into. The translations editor lists them from
1011
+ * the live models, so they are translated here, on the models, once those exist.
1012
+ * `structure` is the one `applyTranslations` returned.
1013
+ */
1014
+ applyTranslationsToModels(structure: IStructure, models: Record<string, unknown> | null | undefined): void;
1015
+ private resolveDictionary;
1016
+ private collectElementEntries;
1017
+ private collectManualListEntries;
1018
+ private collectActionEntries;
1019
+ private collectTableColumnEntries;
1020
+ private collectTemplateDictionaryEntries;
1021
+ private collectStoredTemplateEntries;
1022
+ private collectNestedLocalizableEntries;
1023
+ private collectTemplateTokensFromUnknown;
1024
+ private pushTemplateTranslationEntries;
1025
+ private pushDictionaryEntry;
1026
+ private isLocalizableFieldName;
1027
+ private humanizeFieldName;
1028
+ /**
1029
+ * The built-in strings ship in English only. A view that wants another language
1030
+ * supplies it through its own localization entries, so there is nothing to branch on
1031
+ * here.
1032
+ */
1033
+ private resolveTotalTemplateFallback;
1034
+ private pushStringEntry;
1035
+ private pushStringEntryWithFallback;
1036
+ static ɵfac: i0.ɵɵFactoryDeclaration<LocalizationService, never>;
1037
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
1038
+ }
958
1039
  export type UiDictionary = Record<string, string>;
959
1040
  export type UiDictionaries = Record<string, UiDictionary>;
960
1041
  export declare class UiTranslationService {
@@ -2080,6 +2161,8 @@ export declare class NgxViewBuilderApiService {
2080
2161
  onTableSavedFiltersRequested: EventEmitter$1<INgxViewBuilderTableSavedFiltersRequestEvent>;
2081
2162
  onTableSavedFilterSaveRequested: EventEmitter$1<INgxViewBuilderTableSavedFilterSaveRequestedEvent>;
2082
2163
  onElementDefaultsChanged: EventEmitter$1<INgxViewBuilderElementDefaultsEvent>;
2164
+ private readonly isValidationSandbox;
2165
+ private readonly environmentInjector;
2083
2166
  constructor();
2084
2167
  attachBuilderAdapter(adapter: INgxViewBuilderBuilderAdapter | null | undefined): void;
2085
2168
  /**
@@ -2106,6 +2189,12 @@ export declare class NgxViewBuilderApiService {
2106
2189
  getTableCellElementTypes(): ITableCellElementType[];
2107
2190
  getLanguage(): string;
2108
2191
  setLanguage(language: string): void;
2192
+ /**
2193
+ * A view's own `settings.language` is its default. It is applied only while the host
2194
+ * has not picked a language: otherwise loading a view would switch the host back.
2195
+ */
2196
+ applyViewDefaultLanguage(language: string): void;
2197
+ private applyLanguage;
2109
2198
  resolveHostLanguage(options?: INgxViewBuilderLanguageResolveOptions): INgxViewBuilderResolvedLanguage;
2110
2199
  applyHostLanguage(options?: INgxViewBuilderLanguageResolveOptions): INgxViewBuilderResolvedLanguage;
2111
2200
  startLanguageSync(options?: INgxViewBuilderLanguageSyncOptions): INgxViewBuilderLanguageSyncHandle;
@@ -2145,8 +2234,26 @@ export declare class NgxViewBuilderApiService {
2145
2234
  */
2146
2235
  setWebsocketAuthorizer(authorizer: NgxViewBuilderWebsocketAuthorizer | null | undefined): void;
2147
2236
  setDefaultDataSources(dataSources: IDataSource[] | null | undefined, overwriteExisting?: boolean): void;
2237
+ private readonly hostDefaultDataSources;
2238
+ private applyDefaultDataSourcesTo;
2148
2239
  setAiAssistantConfig(config: INgxViewBuilderAiAssistantConfig | null | undefined): void;
2149
2240
  getAiAssistantConfig(): INgxViewBuilderAiAssistantConfig;
2241
+ /**
2242
+ * Every text of the current view that can be translated: the key to translate it under,
2243
+ * a readable label, the text in the view's default language, and what each language has
2244
+ * for it so far (the view's own translations with the host's on top). `missing` lists the
2245
+ * view's languages that have no text yet.
2246
+ */
2247
+ getContentTranslationKeys(): INgxViewBuilderContentTranslationKey[];
2248
+ /** The view's translations with the host's on top, per language. */
2249
+ getContentTranslations(): Record<string, Record<string, string>>;
2250
+ /**
2251
+ * Content translations from the host, `{ lv: { 'elements.orders.columnsConfig[0].label': 'Vārds' } }`.
2252
+ *
2253
+ * They are kept apart from the view as well as written into it, so they can be supplied
2254
+ * before the view loads and still apply after it is replaced. On a key the view also
2255
+ * translates, the host's text wins. `getContentTranslationKeys()` lists the keys.
2256
+ */
2150
2257
  setContentTranslations(translations: Record<string, Record<string, string>>, merge?: boolean): void;
2151
2258
  requestTabChange(tab: NgxViewBuilderBuilderTabCode): void;
2152
2259
  notifyTabChanged(tab: NgxViewBuilderBuilderTabCode): void;
@@ -2154,7 +2261,14 @@ export declare class NgxViewBuilderApiService {
2154
2261
  notifyDialogClosed(pageIndex: number, pageName: string | null, dialogTitle?: string | null, reason?: NgxViewBuilderDialogCloseReason): void;
2155
2262
  notifyValidationResult(isValid: boolean, issues: INgxViewBuilderValidationIssue[]): void;
2156
2263
  showToast(payload: INgxViewBuilderToastPayload): void;
2157
- validateData(formJson: IStructure | string, dataJson: Record<string, unknown> | string | null | undefined, options?: INgxViewBuilderValidateDataOptions): Promise<INgxViewBuilderValidationEvent>;
2264
+ /**
2265
+ * `validateData()` or `validateData(options)` validates the view on screen and shows its
2266
+ * messages, like the Validate button. `validateData(structure, data, options?)` validates
2267
+ * a given structure headlessly, without touching the view.
2268
+ */
2269
+ validateData(formJson?: IStructure | string | INgxViewBuilderValidateDataOptions | null, dataJson?: Record<string, unknown> | string | null, options?: INgxViewBuilderValidateDataOptions): Promise<INgxViewBuilderValidationEvent>;
2270
+ private isValidateOptionsObject;
2271
+ private validateCurrentView;
2158
2272
  notifyComplete(isValid: boolean, data: Record<string, unknown>, issues: INgxViewBuilderValidationIssue[]): void;
2159
2273
  notifySaveRequested(source?: NgxViewBuilderSaveRequestedSource): void;
2160
2274
  registerRenderRoot(root: HTMLElement | ShadowRoot | null): void;
@@ -2181,7 +2295,14 @@ export declare class NgxViewBuilderApiService {
2181
2295
  replaceSettings(settings: IStructure['settings'] | null | undefined): boolean;
2182
2296
  updateSettings(updater: (settings: IStructure['settings']) => void): boolean;
2183
2297
  setData(data: Record<string, unknown>): void;
2184
- getData(): Record<string, unknown>;
2298
+ /**
2299
+ * The view's data as the host sees it. The library keeps its own state next to it under
2300
+ * `__` keys (`__variables`, `__route`, `__external`); those are left out unless
2301
+ * `includeInternal` asks for them, e.g. to build an expression context.
2302
+ */
2303
+ getData(options?: {
2304
+ includeInternal?: boolean;
2305
+ }): Record<string, unknown>;
2185
2306
  setTableSettings(identifier: string, settings: INgxViewBuilderTableColumnSetting[], options?: {
2186
2307
  tableName?: string | null;
2187
2308
  elementName?: string | null;
@@ -2208,12 +2329,33 @@ export declare class NgxViewBuilderApiService {
2208
2329
  markPristine(): void;
2209
2330
  isDirty(): boolean;
2210
2331
  private registerScopedChildApi;
2332
+ private replayInheritedRegistrationsInto;
2333
+ /**
2334
+ * Two kinds of root calls have to reach the instance-scoped services a runtime view or
2335
+ * <nvb-scope> creates for itself:
2336
+ *
2337
+ * - registrations and host-wide settings (functions, validator types, elements, context,
2338
+ * theme…) are recorded, applied to every live child and replayed into later ones;
2339
+ * - calls about "the view" (structure, values, lookup, validation…) go to the active
2340
+ * child view whenever the root does not own a view itself, which only the designer does.
2341
+ */
2342
+ private readonly inheritedRegistrations;
2343
+ private bridgedCallDepth;
2344
+ private installScopeBridging;
2345
+ /**
2346
+ * A setting the host changes again (the language every time a person switches it)
2347
+ * would otherwise pile up one replay entry per call. Only its last value matters, and a
2348
+ * full replace of the content translations makes the earlier ones irrelevant too.
2349
+ */
2350
+ private recordInheritedRegistration;
2351
+ private invokeBridgedMethod;
2352
+ private resolveViewDelegateApi;
2211
2353
  private unregisterScopedChildApi;
2212
2354
  private resolveScopedChildApi;
2213
2355
  /**
2214
- * Structure calls on the root go to the runtime view only when the root has nothing of
2215
- * its own: in the designer the root owns the edited view, and a preview runtime inside
2216
- * it must not take over getStructure().
2356
+ * In the designer the root owns the edited view, and a preview runtime inside it must
2357
+ * not take over getStructure(). A root setStructure() made while a runtime view is on
2358
+ * screen goes to that view, so it no longer pins the root to a structure of its own.
2217
2359
  */
2218
2360
  private resolveStructureDelegateApi;
2219
2361
  reloadDataSource(elementNameOrPath: string, dataSourceName?: string, runtimeContext?: Record<string, unknown>): Promise<unknown | null>;
@@ -2233,7 +2375,8 @@ export declare class NgxViewBuilderApiService {
2233
2375
  setElementErrors(elementNameOrPath: string, errors: string | readonly string[] | null | undefined): boolean;
2234
2376
  clearElementErrors(elementNameOrPath: string): boolean;
2235
2377
  getElementErrors(elementNameOrPath: string): string[];
2236
- setElementsData(data: Record<string, unknown>): void;
2378
+ /** Merges values into the current data; every key goes through the same path as setValue. */
2379
+ setElementsData(data: Record<string, unknown>): Promise<void>;
2237
2380
  setApplicationLocale(locale: string): void;
2238
2381
  getApplicationLocale(): string;
2239
2382
  setLocale(locale: string): void;
@@ -2287,6 +2430,15 @@ export declare class NgxViewBuilderApiService {
2287
2430
  saveTemplate(template: INgxViewBuilderTemplateInput, previousCode?: string): void;
2288
2431
  removeTemplate(name: string): void;
2289
2432
  deleteTemplate(code: string): void;
2433
+ /** The structure templates are read from and written to: the builder's live one if any. */
2434
+ private getTemplateStructure;
2435
+ /**
2436
+ * In the builder the template list is changed on the live structure the canvas and the
2437
+ * Templates tab edit. Rebuilding it from getStructure() would go through an export that
2438
+ * keeps only the templates an element uses, and every other template would be lost. A
2439
+ * runtime view rebuilds from its captured source, which keeps them all.
2440
+ */
2441
+ private mutateStructureTemplates;
2290
2442
  setSidebarTemplates(templates: INgxViewBuilderSidebarLibraryItem[], replace?: boolean): void;
2291
2443
  loadSidebarGroups(groups: INgxViewBuilderSidebarGroupInput[], replace?: boolean): void;
2292
2444
  setSidebarGroups(groups: INgxViewBuilderSidebarGroupInput[], replace?: boolean): void;
@@ -2318,6 +2470,7 @@ export declare class NgxViewBuilderApiService {
2318
2470
  * decides whether anything actually changed.
2319
2471
  */
2320
2472
  notifyStructureChanged(): void;
2473
+ private scheduleStructureChanged;
2321
2474
  private emitStructureChanged;
2322
2475
  getElement(nameOrPath: string): unknown;
2323
2476
  getElementModel(nameOrPath: string): ElementBaseModel | null;
@@ -2336,6 +2489,11 @@ export declare class NgxViewBuilderApiService {
2336
2489
  setElementProperties(nameOrPath: string, propertyPatch: Record<string, unknown> | null | undefined): boolean;
2337
2490
  updateElement(nameOrPath: string, updater: (element: ElementBaseModel) => void): boolean;
2338
2491
  refreshElement(nameOrPath: string): boolean;
2492
+ /** Comparable per-key snapshot of an element's own properties (no parent links). */
2493
+ private snapshotElementProperties;
2494
+ private diffElementProperties;
2495
+ /** Runs the same notifications a setElementProperty() write does, for keys written directly. */
2496
+ private announceElementPropertyChanges;
2339
2497
  /**
2340
2498
  * Live handle for one element: values, properties, per element subscriptions
2341
2499
  * and - for a dynamicTable / dynamicPanel - row and column control.
@@ -2475,6 +2633,20 @@ export declare class NgxViewBuilderApiService {
2475
2633
  * replaced.
2476
2634
  */
2477
2635
  private flushElementPropertyChanges;
2636
+ /**
2637
+ * Containers, repeaters and logic cache an element's own disabled / read-only state as
2638
+ * its "base" and recompute the visible state from it (base || parent || logic). A host
2639
+ * write is a new base, otherwise the next recompute puts the old one back.
2640
+ */
2641
+ private syncInteractionBaseState;
2642
+ /**
2643
+ * A runtime renders from a captured copy of the structure, which is also what
2644
+ * getStructure() and onStructureChanged report. A property written on the live model is
2645
+ * written there too, so a host that saves the structure after an API change keeps it.
2646
+ * Row instances of a repeater are per-row copies and stay out of the definition.
2647
+ */
2648
+ private mirrorPropertyToSource;
2649
+ private findSourceElementDefinition;
2478
2650
  /** True for a model that a dynamicTable / dynamicPanel built for one of its rows. */
2479
2651
  private isRepeaterRowInstanceModel;
2480
2652
  private getElementPropertyChangeCacheKey;
@@ -2519,6 +2691,8 @@ export declare class NgxViewBuilderApiService {
2519
2691
  private isElementModel;
2520
2692
  private resolveElementModel;
2521
2693
  private getBuilderStructureModel;
2694
+ /** Every model the lookups may match, the builder's first whenever it is attached. */
2695
+ private orderedModelCandidates;
2522
2696
  private getBuilderFlatModelMap;
2523
2697
  private getStructureSourceValue;
2524
2698
  private getMutableStructureSource;
@@ -2690,6 +2864,11 @@ export interface INgxViewBuilderMigrationConfig {
2690
2864
  migrations?: IStructureMigration[];
2691
2865
  }
2692
2866
  export declare class BuilderModel {
2867
+ /**
2868
+ * Goes up on every `setJson`, so a builder that is already on screen can tell a view
2869
+ * was loaded into the model after it started (a view fetched over HTTP, say).
2870
+ */
2871
+ readonly revision: import("@angular/core").WritableSignal<number>;
2693
2872
  private _structureJson;
2694
2873
  private _sourceJson;
2695
2874
  private _migrationResult;
@@ -2698,6 +2877,7 @@ export declare class BuilderModel {
2698
2877
  private _defaultStructure;
2699
2878
  constructor();
2700
2879
  setJson(json: string): void;
2880
+ private applyJson;
2701
2881
  getJson(): IStructure;
2702
2882
  /**
2703
2883
  * True when the loaded structure declares a newer schema version than this runtime
@@ -3415,6 +3595,11 @@ interface INgxViewBuilderValidatorValidateOptions {
3415
3595
  }
3416
3596
  export declare class NgxViewBuilderValidator {
3417
3597
  private readonly http;
3598
+ private readonly api;
3599
+ /**
3600
+ * Remote mode: the request goes to a validation service at this url. Left empty, the
3601
+ * component validates in the page itself with the same rules the runtime uses.
3602
+ */
3418
3603
  backendUrl: import("@angular/core").InputSignal<string>;
3419
3604
  validatePath: import("@angular/core").InputSignal<string>;
3420
3605
  appUrl: import("@angular/core").InputSignal<string>;
@@ -3436,6 +3621,8 @@ export declare class NgxViewBuilderValidator {
3436
3621
  validationError: import("@angular/core").OutputEmitterRef<INgxViewBuilderValidatorError>;
3437
3622
  ngOnInit(): void;
3438
3623
  validate(overrides?: INgxViewBuilderValidatorValidateOptions | null): Promise<INgxViewBuilderValidatorResponse>;
3624
+ private isLocalMode;
3625
+ private validateLocally;
3439
3626
  private resolveRequest;
3440
3627
  private resolveValidateUrl;
3441
3628
  private buildHeaders;
@@ -3551,6 +3738,15 @@ export declare class DataService {
3551
3738
  private _data;
3552
3739
  private dirtyState;
3553
3740
  private baselineSnapshot;
3741
+ /**
3742
+ * Right after data is loaded, default values, expressions and load events still write
3743
+ * into it. Those writes are part of the loaded state, not edits, so until the view has
3744
+ * been quiet for a moment (or a person types) they move the baseline instead of making
3745
+ * the form dirty.
3746
+ */
3747
+ private settlingInitialValues;
3748
+ private settlingTimer;
3749
+ private settlingDeadline;
3554
3750
  onValueChanging: EventEmitter$1<IValueChangingEvent>;
3555
3751
  onValueChanged: EventEmitter$1<IValueChangedEvent>;
3556
3752
  onDataMutated: EventEmitter$1<IValueMutationEvent>;
@@ -3563,6 +3759,9 @@ export declare class DataService {
3563
3759
  /** The language the view is rendered in, as `api.getLanguage()` reports it. */
3564
3760
  getActiveLanguage(): string;
3565
3761
  setData(data: Record<string, unknown>): void;
3762
+ private startInitialSettling;
3763
+ private restartSettlingTimer;
3764
+ private endInitialSettling;
3566
3765
  setValue(path: string, value: unknown, options?: {
3567
3766
  sender?: unknown;
3568
3767
  trigger?: ValueChangeTrigger;
@@ -4993,6 +5192,7 @@ export declare class ElementActionService {
4993
5192
  private structureService;
4994
5193
  private uiTranslationService;
4995
5194
  private markupSecurityService;
5195
+ private eventService;
4996
5196
  private injector;
4997
5197
  private router;
4998
5198
  private debounceTimers;
@@ -5033,6 +5233,12 @@ export declare class ElementActionService {
5033
5233
  private executeReloadElements;
5034
5234
  private executeValidate;
5035
5235
  private executeSubmit;
5236
+ /**
5237
+ * The `submit` trigger: when the form is submitted, every element's submit actions run
5238
+ * before the data is handed to the host. A button's own submit actions already run on
5239
+ * its click, so buttons are left out here.
5240
+ */
5241
+ runFormSubmitTriggers(): Promise<void>;
5036
5242
  private getApiService;
5037
5243
  private handleActionResponse;
5038
5244
  private reloadCurrentElementIfNeeded;
@@ -5052,6 +5258,13 @@ export declare class ElementActionService {
5052
5258
  private assignActionResponseValue;
5053
5259
  private resolveSetValuePayload;
5054
5260
  private resolveSetOptionsPayload;
5261
+ /**
5262
+ * Parses a JSON literal before any token replacement (its own braces would otherwise read
5263
+ * as a {token}), then fills tokens inside its strings. A string that is exactly one token
5264
+ * keeps the value's type. With `stringsArePaths`, a plain string naming a context path is
5265
+ * replaced by that value. Returns undefined when the text is not JSON.
5266
+ */
5267
+ private resolveJsonWithTokens;
5055
5268
  private resolveContextValue;
5056
5269
  private resolveActionTargetPaths;
5057
5270
  private getRuntimeVariableDefinitions;
@@ -5080,6 +5293,12 @@ export declare class ElementActionService {
5080
5293
  static ɵfac: i0.ɵɵFactoryDeclaration<ElementActionService, never>;
5081
5294
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
5082
5295
  }
5296
+ /**
5297
+ * Events the API instance already fires on its parent itself (it does that for `<nvb-scope>`,
5298
+ * which has no bridge). Bridging them again made a host subscribed on the root API get each
5299
+ * of them twice.
5300
+ */
5301
+ export declare const NGX_VIEW_BUILDER_PARENT_FORWARDED_EVENTS: ReadonlySet<string>;
5083
5302
  /**
5084
5303
  * Forwards every event fired on an isolated (component-provided) API instance to
5085
5304
  * another instance typically the root singleton the host application injects.
@@ -5651,6 +5870,7 @@ export interface INgxViewBuilderAiSurface {
5651
5870
  */
5652
5871
  export declare class NgxViewBuilderAiApiService {
5653
5872
  private readonly ngxViewBuilderApiService;
5873
+ private readonly localizationService;
5654
5874
  private readonly elementFocusService;
5655
5875
  private readonly eventService;
5656
5876
  private selection;
@@ -6313,7 +6533,8 @@ export interface INgxViewBuilderHeadlessValidateRequest {
6313
6533
  options?: INgxViewBuilderValidateDataOptions;
6314
6534
  }
6315
6535
  export interface INgxViewBuilderHeadlessApi {
6316
- validateData: (request: INgxViewBuilderHeadlessValidateRequest) => Promise<INgxViewBuilderValidationEvent>;
6536
+ /** `validateData({ formJson, dataJson, options })` or `validateData(formJson, dataJson, options)`. */
6537
+ validateData: (request: INgxViewBuilderHeadlessValidateRequest | IStructure | string, dataJson?: Record<string, unknown> | string | null, options?: INgxViewBuilderValidateDataOptions) => Promise<INgxViewBuilderValidationEvent>;
6317
6538
  ping: () => 'ok';
6318
6539
  }
6319
6540
  export interface INgxViewBuilderHeadlessOptions {
@@ -6663,6 +6884,8 @@ export declare class ExpressionService {
6663
6884
  private readonly pendingAffectedPathEvaluations;
6664
6885
  /** Property changes queued while one element's logic keys are being applied. */
6665
6886
  private readonly propertyChangeBatches;
6887
+ /** How many passes are running for an element; its batch flushes when the last ends. */
6888
+ private readonly propertyChangePassDepth;
6666
6889
  private static readonly DATA_SOURCE_REFRESH_WINDOW_MS;
6667
6890
  private readonly dataSourceExpressionCache;
6668
6891
  private readonly dataSourceExpressionRefreshedAt;
@@ -6737,6 +6960,12 @@ export declare class ExpressionService {
6737
6960
  private applyPropertyChangeNotification;
6738
6961
  private evaluateAndSet;
6739
6962
  private resolveElementExpressionKey;
6963
+ /**
6964
+ * The element's own state, before any `readonlyIf` / `disableIf`. It is recorded here,
6965
+ * the first time a condition is applied: the preview recorded it lazily, after the first
6966
+ * evaluation had already switched the element off, so the condition's result became the
6967
+ * element's permanent base and the element never came back on.
6968
+ */
6740
6969
  private resolveElementBaseReadonly;
6741
6970
  private resolveElementBaseDisabled;
6742
6971
  private applyResetIfState;
@@ -7376,9 +7605,17 @@ export declare class NvbScope implements OnDestroy {
7376
7605
  translations: import("@angular/core").InputSignal<Record<string, Record<string, string>>>;
7377
7606
  private readonly context;
7378
7607
  private readonly dataService;
7608
+ /**
7609
+ * Created eagerly: constructing the scope's API instance is what replays the host's
7610
+ * registrations (expression functions, validator types, custom elements) into the
7611
+ * scope's own services.
7612
+ */
7613
+ private readonly api;
7379
7614
  private readonly disposeDataSubscription;
7380
7615
  constructor();
7381
7616
  ngOnDestroy(): void;
7617
+ /** The scope's data as the host sees it: without the library's own `__` keys. */
7618
+ private publicData;
7382
7619
  static ɵfac: i0.ɵɵFactoryDeclaration<NvbScope, never>;
7383
7620
  static ɵcmp: i0.ɵɵComponentDeclaration<NvbScope, "nvb-scope", never, {
7384
7621
  "data": {
@@ -7425,6 +7662,7 @@ export declare class NvbElementContextService {
7425
7662
  private readonly structureService;
7426
7663
  private readonly dataService;
7427
7664
  private readonly uiTranslationService;
7665
+ private readonly eventService;
7428
7666
  private readonly entries;
7429
7667
  private readonly entryNames;
7430
7668
  private readonly entryRows;
@@ -8166,6 +8404,7 @@ export declare class ElementContentBox implements OnInit, OnDestroy {
8166
8404
  private readonly onElementFocusHandler;
8167
8405
  private readonly onElementContextMenuRequestedHandler;
8168
8406
  private readonly onDropHandler;
8407
+ private readonly changeDetectorRef;
8169
8408
  private readonly onAfterPropertyChangedHandler;
8170
8409
  ngOnInit(): void;
8171
8410
  ngOnDestroy(): void;
@@ -10140,40 +10379,14 @@ export declare class DomInstrumentationService {
10140
10379
  static ɵfac: i0.ɵɵFactoryDeclaration<DomInstrumentationService, never>;
10141
10380
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
10142
10381
  }
10143
- export interface ITranslationEntry {
10144
- key: string;
10145
- label: string;
10146
- sourceValue: string;
10147
- structurePath?: string;
10148
- }
10149
- export declare class LocalizationService {
10150
- private templateEngineService;
10151
- ensureLocalization(structure: IStructure | null | undefined): ILocalization;
10152
- getTranslationEntries(structure: IStructure | null | undefined): ITranslationEntry[];
10153
- applyTranslations(structure: IStructure): IStructure;
10154
- private collectElementEntries;
10155
- private collectManualListEntries;
10156
- private collectActionEntries;
10157
- private collectTableColumnEntries;
10158
- private collectTemplateDictionaryEntries;
10159
- private collectStoredTemplateEntries;
10160
- private collectNestedLocalizableEntries;
10161
- private collectTemplateTokensFromUnknown;
10162
- private pushTemplateTranslationEntries;
10163
- private pushDictionaryEntry;
10164
- private isLocalizableFieldName;
10165
- private humanizeFieldName;
10166
- /**
10167
- * The built-in strings ship in English only. A view that wants another language
10168
- * supplies it through its own localization entries, so there is nothing to branch on
10169
- * here.
10170
- */
10171
- private resolveTotalTemplateFallback;
10172
- private pushStringEntry;
10173
- private pushStringEntryWithFallback;
10174
- static ɵfac: i0.ɵɵFactoryDeclaration<LocalizationService, never>;
10175
- static ɵprov: i0.ɵɵInjectableDeclaration<any>;
10176
- }
10382
+ /**
10383
+ * Drops the translations of elements the view no longer has. Content translation keys
10384
+ * start with the element's name, so deleting an element left its rows behind in every
10385
+ * language and the translations table kept listing them.
10386
+ */
10387
+ export declare function pruneElementTranslations(localization: ILocalization | null | undefined, elements: Record<string, unknown> | null | undefined): boolean;
10388
+ /** Moves an element's translations to its new name when it is renamed. */
10389
+ export declare function renameElementTranslations(localization: ILocalization | null | undefined, oldName: string, newName: string): boolean;
10177
10390
  export declare class MarkupSecurityService {
10178
10391
  private sanitizer;
10179
10392
  private documentRef;
@@ -1 +0,0 @@
1
- import{t as f}from"./ngxviewbuilder-runtime-rolldown-runtime-DpJrqANO.mjs";import{an as p,c as y,d as x,g as L,n as m,on as z,p as _,t as g,yt as w}from"./ngxviewbuilder-runtime-dynamic-text.pipe-BUJ4fCqt.mjs";import{ft as O,r as C,rt as T,t as v}from"./ngxviewbuilder-runtime-element-wrapper-D0lfZvuW.mjs";import*as r from"@angular/core";import{ChangeDetectionStrategy as I,Component as V,HostListener as D,ViewChild as M,computed as c,inject as l,input as k,signal as o}from"@angular/core";import{NgClass as b}from"@angular/common";import{cloneDeep as R,get as u,isEqual as N}from"lodash-es";var B=f({AutocompleteElement:()=>d});const A=["items","data.items","data.rows","data.records","data.results","data.content","records","rows","results","content","result","data"];var d=class h{model=k.required(...ngDevMode?[{debugName:"model"}]:[]);tid=C(this.model,"nvb-autocomplete","autocomplete");containerRef;inputValue=o("",...ngDevMode?[{debugName:"inputValue"}]:[]);isOpen=o(false,...ngDevMode?[{debugName:"isOpen"}]:[]);highlightedIndex=o(0,...ngDevMode?[{debugName:"highlightedIndex"}]:[]);dataSourceLoaded=o(false,...ngDevMode?[{debugName:"dataSourceLoaded"}]:[]);isEditorView=o(p.isEditor(),...ngDevMode?[{debugName:"isEditorView"}]:[]);useCompactStyle=o(false,...ngDevMode?[{debugName:"useCompactStyle"}]:[]);isLoading=o(false,...ngDevMode?[{debugName:"isLoading"}]:[]);dataVersion=o(0,...ngDevMode?[{debugName:"dataVersion"}]:[]);blurTimer=null;lazySearchTimer=null;lazySearchSubscription=null;lazySearchRequestId=0;lazyLastRemoteQuery="";lazyLocalBaseQuery=o("",...ngDevMode?[{debugName:"lazyLocalBaseQuery"}]:[]);lazyLocalResultComplete=o(false,...ngDevMode?[{debugName:"lazyLocalResultComplete"}]:[]);searchItems=o([],...ngDevMode?[{debugName:"searchItems"}]:[]);searchBaseQuery=o("",...ngDevMode?[{debugName:"searchBaseQuery"}]:[]);searchComplete=o(false,...ngDevMode?[{debugName:"searchComplete"}]:[]);selectedSearchOption=null;elementActionService=l(T);dataService=l(z);eventService=l(L);expressionService=l(x);dataSourceService=l(y);visibleOptions=c(()=>{this.dataVersion();return this.computeVisibleOptions()},...ngDevMode?[{debugName:"visibleOptions"}]:[]);suggestionOptions=c(()=>{const e=this.visibleOptions();const t=this.inputValue().trim().toLowerCase();if(!t)return[];const n=this.normalizeMaxSuggestions(this.model().maxSuggestions);if(this.isSearchMode())return this.filterSearchOptions(e,t).slice(0,n);let a=e;if(!this.model().lazyLoad||this.shouldFilterLazyOptionsLocally(t))a=e.filter(i=>this.optionMatchesSearch(i,t));return a.slice(0,n)},...ngDevMode?[{debugName:"suggestionOptions"}]:[]);dropdownHasContent=c(()=>this.isLoading()||this.suggestionOptions().length>0||this.canShowEmptyState(),...ngDevMode?[{debugName:"dropdownHasContent"}]:[]);dataSourceLoading=c(()=>Boolean(this.model().dataSource)&&!this.dataSourceLoaded()&&!this.model().lazyLoad&&!this.isSearchMode()&&!this.isEditorView(),...ngDevMode?[{debugName:"dataSourceLoading"}]:[]);onDataSourceLoadedHandler=()=>{this.dataSourceLoaded.set(true);this.dataVersion.update(e=>e+1);this.syncInputFromModelValue()};onDataValueChangedHandler=()=>{this.dataVersion.update(e=>e+1);this.syncInputFromModelValue()};ngOnInit(){const e=!this.model().dataSource||Boolean(this.model().dataSourceLoaded)||Boolean(this.model().lazyLoad)||this.isSearchMode();this.dataSourceLoaded.set(e);this.model().afterDataSourceLoad.add(this.onDataSourceLoadedHandler);this.dataService.onValueChanged.add(this.onDataValueChangedHandler);this.eventService.afterPropertyChanged.add(this.onDataValueChangedHandler);this.isEditorView.set(p.isEditor());if(this.model()?.parentElement&&this.model()?.parentElement instanceof w)this.useCompactStyle.set(this.model()?.parentElement["useCompactStyle"]);this.syncInputFromModelValue()}ngOnDestroy(){this.model().afterDataSourceLoad.remove(this.onDataSourceLoadedHandler);this.dataService.onValueChanged.remove(this.onDataValueChangedHandler);this.eventService.afterPropertyChanged.remove(this.onDataValueChangedHandler);this.clearBlurTimer();this.clearLazySearchTimer();this.clearLazySearchSubscription()}onInput(e){if(this.isInteractionLocked())return;this.clearBlurTimer();const t=e.target;if(!t)return;const n=String(t.value??"");this.inputValue.set(n);this.highlightedIndex.set(0);this.isOpen.set(n.trim().length>0);if(!this.model().forceSelection)this.model().setValue(n,"input");this.runActions("input",n);if(this.isSearchMode())this.scheduleRemoteSearch(n);else if(this.model().lazyLoad&&this.model().dataSource)this.scheduleLazySearch(n)}onFocus(){if(this.isInteractionLocked())return;this.clearBlurTimer();this.runActions("focus",this.model().value);this.isOpen.set(false)}onBlur(){this.clearBlurTimer();this.blurTimer=setTimeout(()=>{this.applyBlurBehavior();this.isOpen.set(false);this.runActions("blur",this.model().value)},120)}onKeyDown(e){if(!this.isOpen()&&e.key==="ArrowDown"){this.isOpen.set(true);return}const t=this.suggestionOptions();if(!t.length){if(e.key==="Escape")this.isOpen.set(false);return}if(e.key==="ArrowDown"){e.preventDefault();const n=(this.highlightedIndex()+1)%t.length;this.highlightedIndex.set(n);return}if(e.key==="ArrowUp"){e.preventDefault();const n=(this.highlightedIndex()-1+t.length)%t.length;this.highlightedIndex.set(n);return}if(e.key==="Enter"){e.preventDefault();const n=t[this.highlightedIndex()]??null;if(n)this.selectOption(n);return}if(e.key==="Escape"){e.preventDefault();this.isOpen.set(false)}}onOptionMouseDown(e,t){t.preventDefault();if(this.isInteractionLocked())return;this.clearBlurTimer();this.selectOption(e)}clear(e){e.preventDefault();e.stopPropagation();if(this.isInteractionLocked())return;this.clearLazySearchTimer();this.clearLazySearchSubscription();this.resetLazySearchState();this.resetRemoteSearchState();this.isLoading.set(false);this.inputValue.set("");this.isOpen.set(false);this.highlightedIndex.set(0);this.model().setValue(null,"change");this.runActions("change",null)}isHighlighted(e){return this.highlightedIndex()===e}isSelected(e){return this.isSameValue(e.value,this.model().value)}trackSuggestion(e,t){return`${String(e.value??"")}-${t}`}hasSearchTerm(){return this.inputValue().trim().length>0}canShowEmptyState(){if(!this.hasSearchTerm())return false;if(this.isSearchMode())return this.searchAnswerCovers(this.inputValue());if(!this.model().lazyLoad)return true;const e=this.normalizeMinSearchLength(this.model().minSearchLength);return this.inputValue().trim().length>=e}onDocumentClick(e){if(!this.isOpen())return;const t=this.containerRef?.nativeElement;if(!t){this.isOpen.set(false);return}const n=e.target;const a=typeof e.composedPath==="function"?e.composedPath():[];if(!((n?t.contains(n):false)||a.includes(t))){this.applyBlurBehavior();this.isOpen.set(false)}}selectOption(e){const t=e.value!==null&&typeof e.value==="object"?R(e.value):e.value;if(this.isSearchMode())this.selectedSearchOption={...e,value:t};this.inputValue.set(e.label);this.isOpen.set(false);this.highlightedIndex.set(0);this.model().setValue(t,"change");this.runActions("change",t)}applyBlurBehavior(){if(!this.model().forceSelection)return;const e=this.inputValue().trim();const t=this.model().value;if(!e){this.model().setValue(null,"change");if(!Object.is(t,this.model().value))this.runActions("change",this.model().value);return}const n=this.visibleOptions().find(a=>a.label.toLowerCase()===e.toLowerCase());if(n){this.inputValue.set(n.label);this.model().setValue(n.value,"change")}else{this.inputValue.set("");this.model().setValue(null,"change")}if(!Object.is(t,this.model().value))this.runActions("change",this.model().value)}isSearchMode(){return String(this.model().searchDataSourceName??"").trim().length>0}scheduleRemoteSearch(e){const t=String(e??"").trim();const n=this.normalizeMinSearchLength(this.model().minSearchLength);this.clearLazySearchTimer();if(t.length<n){this.cancelRemoteSearch();return}if(this.canNarrowSearchLocally(t)||this.isAnsweredQuery(t)){this.cancelRemoteSearch();this.highlightedIndex.set(0);this.isOpen.set(true);return}this.isLoading.set(true);const a=this.normalizeDebounceMs(this.model().debounceMs);this.lazySearchTimer=setTimeout(()=>{this.lazySearchTimer=null;this.executeRemoteSearch(t)},a)}executeRemoteSearch(e){const t=String(this.model().searchDataSourceName??"").trim();if(!t||this.canNarrowSearchLocally(e)){this.cancelRemoteSearch();return}this.clearLazySearchSubscription();const n=++this.lazySearchRequestId;this.isLoading.set(true);this.lazySearchSubscription=this.dataSourceService.getData$(t,true,this.model(),this.buildLazyRuntimeContext(e)).subscribe({next:a=>{if(n!==this.lazySearchRequestId)return;const i=this.resolveSearchItems(a);const s=this.resolveSearchResultLimit();this.searchItems.set(i);this.searchBaseQuery.set(e);this.searchComplete.set(s!==null&&i.length<s);this.dataVersion.update(S=>S+1);this.highlightedIndex.set(0);this.isOpen.set(this.hasSearchTerm());this.isLoading.set(this.lazySearchTimer!==null)},error:()=>{if(n!==this.lazySearchRequestId)return;this.searchItems.set([]);this.searchBaseQuery.set(e);this.searchComplete.set(false);this.dataVersion.update(a=>a+1);this.isLoading.set(this.lazySearchTimer!==null)}})}cancelRemoteSearch(){this.clearLazySearchTimer();this.clearLazySearchSubscription();this.lazySearchRequestId+=1;this.isLoading.set(false)}resetRemoteSearchState(){this.cancelRemoteSearch();this.searchItems.set([]);this.searchBaseQuery.set("");this.searchComplete.set(false);this.dataVersion.update(e=>e+1)}canNarrowSearchLocally(e){return this.searchComplete()&&this.searchAnswerCovers(e)}isAnsweredQuery(e){const t=this.normalizeSearchText(this.searchBaseQuery());return Boolean(t)&&this.normalizeSearchText(e)===t}searchAnswerCovers(e){const t=this.normalizeSearchText(this.searchBaseQuery());return Boolean(t)&&this.normalizeSearchText(e).startsWith(t)}filterSearchOptions(e,t){if(this.isAnsweredQuery(t))return e;if(!this.searchAnswerCovers(t))return[];return e.filter(n=>this.searchOptionMatches(n,t))}searchOptionMatches(e,t){if(this.optionMatchesSearch(e,t))return true;const n=e.raw;if(!n||typeof n!=="object")return false;const a=this.normalizeSearchText(t);return Object.values(n).some(i=>(typeof i==="string"||typeof i==="number")&&this.normalizeSearchText(i).includes(a))}computeSearchOptions(){return this.searchItems().map(e=>this.toSearchOption(e)).filter(e=>e!==null)}toSearchOption(e){const t=this.resolveSearchLabel(e);if(!t)return null;const n=String(this.model().searchValueKey??"").trim();return{label:t,value:n&&e!==null&&typeof e==="object"?u(e,n):e,raw:e}}resolveSearchLabel(e){if(e===null||e===void 0)return"";if(typeof e!=="object")return String(e).trim();const t=e;const n=String(this.model().searchLabelKey??"").trim();const a=n?u(t,n):t["label"]??t["name"]??t["title"]??t["text"];if(a===null||a===void 0)return"";return typeof a==="object"?JSON.stringify(a):String(a).trim()}resolveSearchItems(e){const t=String(this.model().searchItemsPath??"").trim();if(t){const n=u(e,t);return Array.isArray(n)?n:[]}if(Array.isArray(e))return e;if(!e||typeof e!=="object")return[];for(const n of A){const a=u(e,n);if(Array.isArray(a))return a}return[]}resolveSearchResultLimit(){const e=this.model().searchResultLimit;if(e===null||e===void 0||String(e).trim()==="")return null;const t=Number(e);return Number.isFinite(t)&&t>0?Math.floor(t):null}scheduleLazySearch(e){const t=String(e??"").trim();const n=this.normalizeMinSearchLength(this.model().minSearchLength);this.clearLazySearchTimer();if(t.length<n){this.clearLazySearchSubscription();this.resetLazySearchState();this.isLoading.set(false);this.model().options=[];this.dataVersion.update(i=>i+1);return}if(this.tryUseLocalLazySearch(t))return;if(this.normalizeSearchText(t)===this.normalizeSearchText(this.lazyLastRemoteQuery)&&this.flattenOptions(this.model().options??[]).length>0){this.isLoading.set(false);this.highlightedIndex.set(0);this.isOpen.set(true);return}const a=this.normalizeDebounceMs(this.model().debounceMs);this.lazySearchTimer=setTimeout(()=>{this.executeLazySearch(t)},a)}executeLazySearch(e){if(!this.model().dataSource)return;this.clearLazySearchSubscription();const t=++this.lazySearchRequestId;this.lazyLastRemoteQuery=e;this.isLoading.set(true);this.lazySearchSubscription=this.dataSourceService.getData$(this.model().dataSource,true,this.model(),this.buildLazyRuntimeContext(e)).subscribe({next:n=>{if(t!==this.lazySearchRequestId)return;this.model().setOptions(n);this.model().dataSourceLoaded=true;this.dataSourceLoaded.set(true);this.updateLazySearchCompletionState(e);this.dataVersion.update(a=>a+1);this.highlightedIndex.set(0);this.isOpen.set(true);this.isLoading.set(false)},error:()=>{if(t!==this.lazySearchRequestId)return;this.model().options=[];this.resetLazySearchState();this.dataVersion.update(n=>n+1);this.isLoading.set(false)}})}buildLazyRuntimeContext(e){const t=String(this.model().name??"").trim();const n=String(this.model().queryContextKey??"").trim()||"query";const a=(this.isSearchMode()?this.resolveSearchResultLimit():null)??this.normalizeMaxSuggestions(this.model().maxSuggestions);const i={[n]:e,query:e,filterValue:e,filterValueModified4Search:null,term:e,search:e,recordCount:a,rowLimit:a,limit:a,take:a,maxSuggestions:a,value:this.model().value,item:null,row:null};if(t){i[t]=this.model().value;i["__autocomplete"]={[t]:{query:e,term:e,recordCount:a,value:this.model().value}}}return _(this.model(),s=>this.dataService.getValue(s),i)??i}tryUseLocalLazySearch(e){if(!this.shouldFilterLazyOptionsLocally(e))return false;this.clearLazySearchSubscription();this.isLoading.set(false);this.highlightedIndex.set(0);this.isOpen.set(true);this.dataVersion.update(t=>t+1);return true}updateLazySearchCompletionState(e){const t=this.flattenOptions(this.model().options??[]).length;const n=this.normalizeMaxSuggestions(this.model().maxSuggestions);this.lazyLocalBaseQuery.set(e);this.lazyLocalResultComplete.set(t<n)}resetLazySearchState(){this.lazySearchRequestId+=1;this.lazyLastRemoteQuery="";this.lazyLocalBaseQuery.set("");this.lazyLocalResultComplete.set(false)}shouldFilterLazyOptionsLocally(e){if(!this.model().lazyLoad)return false;if(!this.lazyLocalResultComplete())return false;const t=this.normalizeSearchText(e);const n=this.normalizeSearchText(this.lazyLocalBaseQuery());return Boolean(n)&&t.startsWith(n)}computeVisibleOptions(){if(this.isSearchMode())return this.computeSearchOptions();return this.flattenOptions(this.model().options??[]).filter(e=>this.passesOptionFilters(e)&&this.isOptionVisible(e))}flattenOptions(e){if(!Array.isArray(e))return[];const t=[];e.forEach(n=>{const a=n;if(Array.isArray(a?.["items"])){a["items"].forEach(i=>{const s=i;t.push({label:String(s?.["label"]??"").trim(),value:s?.["value"],visibleIf:String(s?.["visibleIf"]??"").trim()||void 0})});return}t.push({label:String(a?.["label"]??"").trim(),value:a?.["value"],visibleIf:String(a?.["visibleIf"]??"").trim()||void 0})});return t.filter(n=>n.label.length>0)}optionMatchesSearch(e,t){const n=this.normalizeSearchText(t);if(!n)return true;return this.normalizeSearchText(e.label).includes(n)}normalizeSearchText(e){return String(e??"").trim().toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"")}passesOptionFilters(e){const t=String(this.model().filterOptionsBy??"").trim()||String(this.model().dataSource?.filterOptionsBy??"").trim();const n=String(this.model().filterIfEqual??"").trim();const a=String(this.model().filterIfNotEqual??"").trim();if(!t&&!n&&!a)return true;const i=this.dataService.getData()??{};return O([e],t,i,{valuePath:"value",filterIfEqual:n,filterIfNotEqual:a}).length>0}isOptionVisible(e){const t=String(e?.visibleIf??"").trim();if(!t)return true;try{const n=this.normalizeOptionCondition(t);const a=this.expressionService.runPropertyConditionSync(this.dataService.getData(),n);return Boolean(a)}catch{return true}}normalizeOptionCondition(e){const t=e.replace(/{/g,"").replace(/}/g,"").trim();if(!t)return"";return this.expressionService.applyContextToExpression(t,this.model())}syncInputFromModelValue(){const e=this.model().value;if(e===null||e===void 0){this.inputValue.set("");return}if(this.isSearchMode()){this.inputValue.set(this.resolveSearchInputText(e));return}if(!this.model().forceSelection){if(typeof e==="string"&&!this.visibleOptions().some(n=>this.isSameValue(n.value,e))){this.inputValue.set(e);return}}const t=this.visibleOptions().find(n=>this.isSameValue(n.value,e));if(t){this.inputValue.set(t.label);return}this.inputValue.set(String(e))}resolveSearchInputText(e){const t=this.visibleOptions().find(n=>this.isSameValue(n.value,e))??(this.selectedSearchOption&&this.isSameValue(this.selectedSearchOption.value,e)?this.selectedSearchOption:null);if(t)return t.label;if(typeof e==="object")return this.resolveSearchLabel(e);return String(e)}runActions(e,t){const n=t!==void 0?t:this.model().value;const a=String(this.model().name??"").trim();const i={value:n,item:null,row:null};if(a)i[a]=n;this.elementActionService.runActions(this.model(),this.model().events??[],e,i)}isInteractionLocked(){const e=this.model();if(!e)return false;if(Boolean(e["__pfInteractionLocked"]))return true;if(this.dataSourceLoading())return true;return Boolean(e.disabled)||Boolean(e.readOnly)}isSameValue(e,t){if(e!==null&&typeof e==="object"||t!==null&&typeof t==="object")return N(e,t);return String(e??"")===String(t??"")}clearBlurTimer(){if(!this.blurTimer)return;clearTimeout(this.blurTimer);this.blurTimer=null}clearLazySearchTimer(){if(!this.lazySearchTimer)return;clearTimeout(this.lazySearchTimer);this.lazySearchTimer=null}clearLazySearchSubscription(){if(!this.lazySearchSubscription)return;this.lazySearchSubscription.unsubscribe();this.lazySearchSubscription=null}normalizeMaxSuggestions(e){const t=Number(e);if(!Number.isFinite(t))return 20;return Math.max(1,Math.min(500,Math.floor(t)))}normalizeMinSearchLength(e){const t=Number(e);if(!Number.isFinite(t))return 1;return Math.max(0,Math.min(10,Math.floor(t)))}normalizeDebounceMs(e){const t=Number(e);if(!Number.isFinite(t)||String(e??"").trim()==="")return 1e3;return Math.max(0,Math.min(1e4,Math.floor(t)))}static ɵfac=r.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.2.1",ngImport:r,type:h,deps:[],target:r.ɵɵFactoryTarget.Component});static ɵcmp=r.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.2.1",type:h,isStandalone:true,selector:"autocomplete-element",inputs:{model:{classPropertyName:"model",publicName:"model",isSignal:true,isRequired:true,transformFunction:null}},host:{listeners:{"document:click":"onDocumentClick($event)"}},viewQueries:[{propertyName:"containerRef",first:true,predicate:["container"],descendants:true}],ngImport:r,template:"<element-wrapper [model]=\"model()\">\n @if (model().dataSource && !dataSourceLoaded() && !model().lazyLoad && isEditorView()) {\n <div class=\"nvb-empty-element-wrapper\">\n <div class=\"nvb-control__text-input nvb-empty-select-placeholder\"></div>\n <small class=\"nvb-element-title\">\n <span class=\"material-symbols-outlined\">database</span>\n {{ model()?.dataSource?.source?.title || model()?.dataSource?.name }}\n </small>\n </div>\n } @else {\n <div\n class=\"nvb-autocomplete\"\n [class.nvb-autocomplete--open]=\"isOpen()\"\n [class.nvb-autocomplete--loading]=\"dataSourceLoading()\"\n #container\n [attr.data-testid]=\"tid('root')\"\n [attr.aria-busy]=\"dataSourceLoading() ? 'true' : null\"\n >\n <div class=\"nvb-autocomplete__control\">\n <span class=\"material-symbols-outlined nvb-autocomplete__icon\">search</span>\n <input [attr.data-testid]=\"tid('input')\"\n [id]=\"model().name\"\n [ngClass]=\"useCompactStyle() ? 'nvb-control__column-input' : 'nvb-control__text-input'\"\n class=\"nvb-autocomplete__input\"\n type=\"text\"\n [placeholder]=\"\n dataSourceLoading()\n ? ('autocomplete.loading' | uiT: 'Loading...')\n : model().placeholder\n ? (model().placeholder | dynamicText: model())\n : ('autocomplete.placeholder' | uiT: 'Search...')\n \"\n [disabled]=\"model().disabled || dataSourceLoading()\"\n [readOnly]=\"model().readOnly\"\n [value]=\"inputValue()\"\n autocomplete=\"off\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\"\n />\n\n @if (dataSourceLoading()) {\n <span class=\"nvb-autocomplete__spinner\" aria-hidden=\"true\"></span>\n } @else if (inputValue()) {\n <button [attr.data-testid]=\"tid('clear')\"\n type=\"button\"\n class=\"nvb-autocomplete__clear\"\n [attr.title]=\"'autocomplete.clear' | uiT: 'Clear'\"\n [attr.aria-label]=\"'autocomplete.clear' | uiT: 'Clear'\"\n (mousedown)=\"clear($event)\"\n >\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n }\n </div>\n\n @if (isOpen() && !dataSourceLoading() && dropdownHasContent()) {\n <div class=\"nvb-autocomplete__dropdown\" [attr.data-testid]=\"tid('options')\">\n @if (isLoading()) {\n <div class=\"nvb-autocomplete__status\">\n {{ 'autocomplete.loading' | uiT: 'Loading...' }}\n </div>\n }\n\n @for (\n option of suggestionOptions();\n track trackSuggestion(option, $index);\n let i = $index\n ) {\n <button [attr.data-testid]=\"tid('option', i)\"\n type=\"button\"\n class=\"nvb-autocomplete__option\"\n [ngClass]=\"{\n 'nvb-autocomplete__option--highlighted': isHighlighted(i),\n 'nvb-autocomplete__option--selected': isSelected(option),\n }\"\n (mousedown)=\"onOptionMouseDown(option, $event)\"\n >\n {{ option.label }}\n </button>\n }\n\n @if (!isLoading() && suggestionOptions().length === 0 && canShowEmptyState()) {\n <div class=\"nvb-autocomplete__status\">\n {{ 'autocomplete.empty' | uiT: 'No results found' }}\n </div>\n }\n </div>\n }\n </div>\n }\n</element-wrapper>\n",styles:[":host{display:block;width:100%}.nvb-autocomplete{position:relative;width:100%;overflow:visible}.nvb-autocomplete--open{z-index:var(--nvb-floating-overlay-container-z-index, 2147482990)}.nvb-autocomplete--loading{cursor:progress}.nvb-autocomplete__control{position:relative;display:flex;align-items:center}.nvb-autocomplete__input{padding-left:34px;padding-right:30px}.nvb-autocomplete--loading .nvb-autocomplete__input{background:linear-gradient(90deg,transparent 0%,color-mix(in oklab,var(--nvb-color-neutral-000) 72%,transparent) 48%,transparent 100%),color-mix(in oklab,var(--nvb-color-neutral-050) 78%,var(--nvb-color-neutral-000));background-size:220% 100%;animation:nvb-autocomplete-loading-shimmer 1.35s ease-in-out infinite}.nvb-autocomplete__icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);font-size:18px;color:var(--nvb-color-neutral-500);pointer-events:none;z-index:1}.nvb-autocomplete__clear{position:absolute;right:6px;top:50%;transform:translateY(-50%);border:none;background:transparent;color:var(--nvb-color-neutral-500);width:24px;height:24px;border-radius:var(--nvb-radius-md);cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.nvb-autocomplete__clear:hover{background:var(--nvb-color-neutral-100);color:var(--nvb-color-neutral-700)}.nvb-autocomplete__clear span{font-size:16px}.nvb-autocomplete__spinner{position:absolute;right:10px;top:50%;width:14px;height:14px;border:2px solid color-mix(in oklab,var(--nvb-color-neutral-400) 45%,transparent);border-top-color:var(--nvb-color-primary-500);border-radius:var(--nvb-radius-full);transform:translateY(-50%);animation:nvb-autocomplete-loading-spin .8s linear infinite}.nvb-autocomplete__dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;max-height:280px;overflow-y:auto;border:1px solid var(--nvb-color-neutral-300);border-radius:var(--nvb-menu-radius, var(--nvb-input-radius));background:var(--nvb-color-neutral-000);box-shadow:var(--nvb-shadow-8);z-index:var(--nvb-floating-overlay-z-index, 2147483000);padding:4px}.nvb-autocomplete__option{display:block;width:100%;border:none;background:transparent;text-align:left;min-height:32px;padding:0 10px;border-radius:var(--nvb-control-radius);font-size:13px;color:var(--nvb-color-neutral-700);cursor:pointer;transition:background-color .12s ease}.nvb-autocomplete__option:hover,.nvb-autocomplete__option--highlighted{background:var(--nvb-color-neutral-100)}.nvb-autocomplete__option--selected{background:var(--nvb-color-primary-050);color:var(--nvb-color-primary-700);font-weight:600}.nvb-autocomplete__status{padding:10px 12px;font-size:12px;color:var(--nvb-color-neutral-500)}@keyframes nvb-autocomplete-loading-shimmer{0%{background-position:180% 0}to{background-position:-80% 0}}@keyframes nvb-autocomplete-loading-spin{to{transform:translateY(-50%) rotate(360deg)}}\n"],dependencies:[{kind:"component",type:v,selector:"element-wrapper",inputs:["model","controlIdInput","labelForInput","groupRole","showTextWrapperInput"],exportAs:["elementWrapper"]},{kind:"directive",type:b,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"pipe",type:g,name:"dynamicText"},{kind:"pipe",type:m,name:"uiT"}],changeDetection:r.ChangeDetectionStrategy.OnPush})};r.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.2.1",ngImport:r,type:d,decorators:[{type:V,args:[{selector:"autocomplete-element",changeDetection:I.OnPush,imports:[v,g,b,m],template:"<element-wrapper [model]=\"model()\">\n @if (model().dataSource && !dataSourceLoaded() && !model().lazyLoad && isEditorView()) {\n <div class=\"nvb-empty-element-wrapper\">\n <div class=\"nvb-control__text-input nvb-empty-select-placeholder\"></div>\n <small class=\"nvb-element-title\">\n <span class=\"material-symbols-outlined\">database</span>\n {{ model()?.dataSource?.source?.title || model()?.dataSource?.name }}\n </small>\n </div>\n } @else {\n <div\n class=\"nvb-autocomplete\"\n [class.nvb-autocomplete--open]=\"isOpen()\"\n [class.nvb-autocomplete--loading]=\"dataSourceLoading()\"\n #container\n [attr.data-testid]=\"tid('root')\"\n [attr.aria-busy]=\"dataSourceLoading() ? 'true' : null\"\n >\n <div class=\"nvb-autocomplete__control\">\n <span class=\"material-symbols-outlined nvb-autocomplete__icon\">search</span>\n <input [attr.data-testid]=\"tid('input')\"\n [id]=\"model().name\"\n [ngClass]=\"useCompactStyle() ? 'nvb-control__column-input' : 'nvb-control__text-input'\"\n class=\"nvb-autocomplete__input\"\n type=\"text\"\n [placeholder]=\"\n dataSourceLoading()\n ? ('autocomplete.loading' | uiT: 'Loading...')\n : model().placeholder\n ? (model().placeholder | dynamicText: model())\n : ('autocomplete.placeholder' | uiT: 'Search...')\n \"\n [disabled]=\"model().disabled || dataSourceLoading()\"\n [readOnly]=\"model().readOnly\"\n [value]=\"inputValue()\"\n autocomplete=\"off\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\"\n />\n\n @if (dataSourceLoading()) {\n <span class=\"nvb-autocomplete__spinner\" aria-hidden=\"true\"></span>\n } @else if (inputValue()) {\n <button [attr.data-testid]=\"tid('clear')\"\n type=\"button\"\n class=\"nvb-autocomplete__clear\"\n [attr.title]=\"'autocomplete.clear' | uiT: 'Clear'\"\n [attr.aria-label]=\"'autocomplete.clear' | uiT: 'Clear'\"\n (mousedown)=\"clear($event)\"\n >\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n }\n </div>\n\n @if (isOpen() && !dataSourceLoading() && dropdownHasContent()) {\n <div class=\"nvb-autocomplete__dropdown\" [attr.data-testid]=\"tid('options')\">\n @if (isLoading()) {\n <div class=\"nvb-autocomplete__status\">\n {{ 'autocomplete.loading' | uiT: 'Loading...' }}\n </div>\n }\n\n @for (\n option of suggestionOptions();\n track trackSuggestion(option, $index);\n let i = $index\n ) {\n <button [attr.data-testid]=\"tid('option', i)\"\n type=\"button\"\n class=\"nvb-autocomplete__option\"\n [ngClass]=\"{\n 'nvb-autocomplete__option--highlighted': isHighlighted(i),\n 'nvb-autocomplete__option--selected': isSelected(option),\n }\"\n (mousedown)=\"onOptionMouseDown(option, $event)\"\n >\n {{ option.label }}\n </button>\n }\n\n @if (!isLoading() && suggestionOptions().length === 0 && canShowEmptyState()) {\n <div class=\"nvb-autocomplete__status\">\n {{ 'autocomplete.empty' | uiT: 'No results found' }}\n </div>\n }\n </div>\n }\n </div>\n }\n</element-wrapper>\n",styles:[":host{display:block;width:100%}.nvb-autocomplete{position:relative;width:100%;overflow:visible}.nvb-autocomplete--open{z-index:var(--nvb-floating-overlay-container-z-index, 2147482990)}.nvb-autocomplete--loading{cursor:progress}.nvb-autocomplete__control{position:relative;display:flex;align-items:center}.nvb-autocomplete__input{padding-left:34px;padding-right:30px}.nvb-autocomplete--loading .nvb-autocomplete__input{background:linear-gradient(90deg,transparent 0%,color-mix(in oklab,var(--nvb-color-neutral-000) 72%,transparent) 48%,transparent 100%),color-mix(in oklab,var(--nvb-color-neutral-050) 78%,var(--nvb-color-neutral-000));background-size:220% 100%;animation:nvb-autocomplete-loading-shimmer 1.35s ease-in-out infinite}.nvb-autocomplete__icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);font-size:18px;color:var(--nvb-color-neutral-500);pointer-events:none;z-index:1}.nvb-autocomplete__clear{position:absolute;right:6px;top:50%;transform:translateY(-50%);border:none;background:transparent;color:var(--nvb-color-neutral-500);width:24px;height:24px;border-radius:var(--nvb-radius-md);cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.nvb-autocomplete__clear:hover{background:var(--nvb-color-neutral-100);color:var(--nvb-color-neutral-700)}.nvb-autocomplete__clear span{font-size:16px}.nvb-autocomplete__spinner{position:absolute;right:10px;top:50%;width:14px;height:14px;border:2px solid color-mix(in oklab,var(--nvb-color-neutral-400) 45%,transparent);border-top-color:var(--nvb-color-primary-500);border-radius:var(--nvb-radius-full);transform:translateY(-50%);animation:nvb-autocomplete-loading-spin .8s linear infinite}.nvb-autocomplete__dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;max-height:280px;overflow-y:auto;border:1px solid var(--nvb-color-neutral-300);border-radius:var(--nvb-menu-radius, var(--nvb-input-radius));background:var(--nvb-color-neutral-000);box-shadow:var(--nvb-shadow-8);z-index:var(--nvb-floating-overlay-z-index, 2147483000);padding:4px}.nvb-autocomplete__option{display:block;width:100%;border:none;background:transparent;text-align:left;min-height:32px;padding:0 10px;border-radius:var(--nvb-control-radius);font-size:13px;color:var(--nvb-color-neutral-700);cursor:pointer;transition:background-color .12s ease}.nvb-autocomplete__option:hover,.nvb-autocomplete__option--highlighted{background:var(--nvb-color-neutral-100)}.nvb-autocomplete__option--selected{background:var(--nvb-color-primary-050);color:var(--nvb-color-primary-700);font-weight:600}.nvb-autocomplete__status{padding:10px 12px;font-size:12px;color:var(--nvb-color-neutral-500)}@keyframes nvb-autocomplete-loading-shimmer{0%{background-position:180% 0}to{background-position:-80% 0}}@keyframes nvb-autocomplete-loading-spin{to{transform:translateY(-50%) rotate(360deg)}}\n"]}]}],propDecorators:{model:[{type:r.Input,args:[{isSignal:true,alias:"model",required:true}]}],containerRef:[{type:M,args:["container"]}],onDocumentClick:[{type:D,args:["document:click",["$event"]]}]}});export{B as n,d as t};
@@ -1 +0,0 @@
1
- import{t as o}from"./ngxviewbuilder-runtime-dynamic-text.pipe-BUJ4fCqt.mjs";import{r as v,rt as m,t as s}from"./ngxviewbuilder-runtime-element-wrapper-D0lfZvuW.mjs";import*as a from"@angular/core";import{ChangeDetectionStrategy as u,Component as g,computed as l,inject as b,input as f,signal as p}from"@angular/core";import{NgStyle as d}from"@angular/common";var c=class r{model=f.required(...ngDevMode?[{debugName:"model"}]:[]);tid=v(this.model,"nvb-avatar","avatar");previewOpen=p(false,...ngDevMode?[{debugName:"previewOpen"}]:[]);previewSrc=p("",...ngDevMode?[{debugName:"previewSrc"}]:[]);elementActionService=b(m);avatarStyle=l(()=>{const e=Number(this.model()?.size);const n=Number.isFinite(e)&&e>0?Math.floor(e):48;const t=String(this.model()?.shape??"circle").trim().toLowerCase();return{width:`${n}px`,height:`${n}px`,"border-radius":t==="square"?"10px":"999px","background-color":String(this.model()?.backgroundColor??"#dfe6ff").trim()||"#dfe6ff",color:String(this.model()?.textColor??"#1b2d6b").trim()||"#1b2d6b",border:this.model().showBorder?"1px solid var(--nvb-color-neutral-300)":"none"}},...ngDevMode?[{debugName:"avatarStyle"}]:[]);initials=l(()=>{const e=String(this.model()?.nameText??"").trim();if(!e)return"U";const n=e.split(/\s+/).map(t=>t.trim()).filter(t=>t.length>0);if(!n.length)return"U";return n.slice(0,2).map(t=>t[0].toUpperCase()).join("")},...ngDevMode?[{debugName:"initials"}]:[]);onAvatarClick(e,n){n.preventDefault();n.stopPropagation();const t={value:e||this.initials(),item:null,row:null};const i=String(this.model().name??"").trim();if(i)t[i]=t["value"];this.elementActionService.runActions(this.model(),this.model().events??[],"click",t);if(!this.model().showPreview||!e)return;this.previewSrc.set(e);this.previewOpen.set(true)}closePreview(e){e?.preventDefault();e?.stopPropagation();this.previewOpen.set(false);this.previewSrc.set("")}static ɵfac=a.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.2.1",ngImport:a,type:r,deps:[],target:a.ɵɵFactoryTarget.Component});static ɵcmp=a.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.2.1",type:r,isStandalone:true,selector:"avatar-element",inputs:{model:{classPropertyName:"model",publicName:"model",isSignal:true,isRequired:true,transformFunction:null}},ngImport:a,template:"<element-wrapper [model]=\"model()\">\n @let avatarSrc = model().src | dynamicText: model();\n @let avatarName = model().nameText | dynamicText: model();\n\n <div class=\"nvb-avatar-wrap\" [attr.data-testid]=\"tid('root')\">\n <button [attr.data-testid]=\"tid('avatar')\"\n type=\"button\"\n class=\"nvb-avatar\"\n [ngStyle]=\"avatarStyle()\"\n (click)=\"onAvatarClick(avatarSrc, $event)\"\n >\n @if (avatarSrc) {\n <img [src]=\"avatarSrc\" [alt]=\"avatarName\" />\n } @else {\n <span>{{ initials() }}</span>\n }\n </button>\n </div>\n\n @if (previewOpen()) {\n <div [attr.data-testid]=\"tid('close-preview')\" class=\"nvb-avatar-preview\" (click)=\"closePreview()\">\n <button [attr.data-testid]=\"tid('close')\" type=\"button\" class=\"nvb-avatar-preview__close\" (click)=\"closePreview($event)\">\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n <img [src]=\"previewSrc()\" [alt]=\"avatarName\" />\n </div>\n }\n</element-wrapper>\n",styles:[":host{display:block;width:100%}.nvb-avatar-wrap{width:100%;display:flex;justify-content:flex-start;align-items:center}.nvb-avatar{border:none;padding:0;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;font-weight:700;font-size:14px;line-height:1}.nvb-avatar img{width:100%;height:100%;object-fit:cover;display:block}.nvb-avatar-preview{position:fixed;inset:0;background:#000000b8;z-index:1300;display:grid;place-items:center;padding:20px}.nvb-avatar-preview img{width:min(300px,100vw - 40px);height:min(300px,100vw - 40px);object-fit:cover;border-radius:14px;box-shadow:0 16px 32px #0000004d;background:#fff}.nvb-avatar-preview__close{position:absolute;top:12px;right:12px;width:36px;height:36px;border:none;border-radius:var(--nvb-radius-lg);background:#ffffff2e;color:#fff;cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.nvb-avatar-preview__close span{font-size:20px}\n"],dependencies:[{kind:"component",type:s,selector:"element-wrapper",inputs:["model","controlIdInput","labelForInput","groupRole","showTextWrapperInput"],exportAs:["elementWrapper"]},{kind:"directive",type:d,selector:"[ngStyle]",inputs:["ngStyle"]},{kind:"pipe",type:o,name:"dynamicText"}],changeDetection:a.ChangeDetectionStrategy.OnPush})};a.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.2.1",ngImport:a,type:c,decorators:[{type:g,args:[{selector:"avatar-element",changeDetection:u.OnPush,imports:[s,d,o],template:"<element-wrapper [model]=\"model()\">\n @let avatarSrc = model().src | dynamicText: model();\n @let avatarName = model().nameText | dynamicText: model();\n\n <div class=\"nvb-avatar-wrap\" [attr.data-testid]=\"tid('root')\">\n <button [attr.data-testid]=\"tid('avatar')\"\n type=\"button\"\n class=\"nvb-avatar\"\n [ngStyle]=\"avatarStyle()\"\n (click)=\"onAvatarClick(avatarSrc, $event)\"\n >\n @if (avatarSrc) {\n <img [src]=\"avatarSrc\" [alt]=\"avatarName\" />\n } @else {\n <span>{{ initials() }}</span>\n }\n </button>\n </div>\n\n @if (previewOpen()) {\n <div [attr.data-testid]=\"tid('close-preview')\" class=\"nvb-avatar-preview\" (click)=\"closePreview()\">\n <button [attr.data-testid]=\"tid('close')\" type=\"button\" class=\"nvb-avatar-preview__close\" (click)=\"closePreview($event)\">\n <span class=\"material-symbols-outlined\">close</span>\n </button>\n <img [src]=\"previewSrc()\" [alt]=\"avatarName\" />\n </div>\n }\n</element-wrapper>\n",styles:[":host{display:block;width:100%}.nvb-avatar-wrap{width:100%;display:flex;justify-content:flex-start;align-items:center}.nvb-avatar{border:none;padding:0;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;font-weight:700;font-size:14px;line-height:1}.nvb-avatar img{width:100%;height:100%;object-fit:cover;display:block}.nvb-avatar-preview{position:fixed;inset:0;background:#000000b8;z-index:1300;display:grid;place-items:center;padding:20px}.nvb-avatar-preview img{width:min(300px,100vw - 40px);height:min(300px,100vw - 40px);object-fit:cover;border-radius:14px;box-shadow:0 16px 32px #0000004d;background:#fff}.nvb-avatar-preview__close{position:absolute;top:12px;right:12px;width:36px;height:36px;border:none;border-radius:var(--nvb-radius-lg);background:#ffffff2e;color:#fff;cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.nvb-avatar-preview__close span{font-size:20px}\n"]}]}],propDecorators:{model:[{type:a.Input,args:[{isSignal:true,alias:"model",required:true}]}]}});export{c as AvatarElement};
@@ -1 +0,0 @@
1
- import{t as b}from"./ngxviewbuilder-runtime-rolldown-runtime-DpJrqANO.mjs";import{d,t as l}from"./ngxviewbuilder-runtime-dynamic-text.pipe-BUJ4fCqt.mjs";import{r as v,t as s}from"./ngxviewbuilder-runtime-element-wrapper-D0lfZvuW.mjs";import*as o from"@angular/core";import{ChangeDetectionStrategy as m,Component as g,computed as n,inject as p,input as u}from"@angular/core";import{NgClass as c}from"@angular/common";var x=b({BadgeElement:()=>i});var i=class t{expressionService=p(d);model=u.required(...ngDevMode?[{debugName:"model"}]:[]);tid=v(this.model,"nvb-badge","badge");resolvedVariant=n(()=>this.resolveVariant(),...ngDevMode?[{debugName:"resolvedVariant"}]:[]);badgeClass=n(()=>{const e=this.resolvedVariant();const r=this.resolveSize();return{[`nvb-badge--${e}`]:true,[`nvb-badge--${r}`]:true,"nvb-badge--square":!Boolean(this.model()?.pill)}},...ngDevMode?[{debugName:"badgeClass"}]:[]);iconName=n(()=>{const e=String(this.model()?.icon??"").trim();if(e)return e;switch(this.resolvedVariant()){case"success":return"check_circle";case"warn":return"warning";case"risk":return"error";case"primary":return"bolt";case"neutral":return"radio_button_checked";default:return"info"}},...ngDevMode?[{debugName:"iconName"}]:[]);resolveVariant(){const e=this.resolveConditionalVariant()||this.resolveExpressionValue(this.model()?.variantExpression)||this.model()?.variant;const r=String(e??"info").trim().toLowerCase();if(r==="warn"||r==="warning")return"warn";if(r==="risk"||r==="danger"||r==="error")return"risk";if(r==="success"||r==="succes"||r==="completed")return"success";if(r==="neutral"||r==="archived")return"neutral";if(r==="primary"||r==="new")return"primary";if(r==="info"||r==="inprogress"||r==="in_progress"||r==="in-progress"||r==="blocked")return"info";return"info"}resolveConditionalVariant(){if(String(this.model()?.variantMode??"static").trim().toLowerCase()!=="conditional")return"";const e=Array.isArray(this.model()?.variantRules)?this.model().variantRules:[];for(const r of e){const a=String(r?.condition??"").trim();if(!a)continue;if(Boolean(this.expressionService.evaluateInlineExpression(a,this.model())))return String(r?.variant??"").trim()}return""}resolveText(){const e=String(this.model()?.text??"").trim();if(e)return e;const r=String(this.model()?.label??"").trim();if(r)return r;return"Badge"}resolveSize(){const e=String(this.model()?.size??"md").trim().toLowerCase();if(e==="sm"||e==="lg")return e;return"md"}resolveExpressionValue(e){const r=String(e??"").trim();if(!r)return"";const a=this.expressionService.evaluateInlineExpression(r,this.model());return String(a??"").trim()}static ɵfac=o.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.2.1",ngImport:o,type:t,deps:[],target:o.ɵɵFactoryTarget.Component});static ɵcmp=o.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.2.1",type:t,isStandalone:true,selector:"badge-element",inputs:{model:{classPropertyName:"model",publicName:"model",isSignal:true,isRequired:true,transformFunction:null}},ngImport:o,template:"<element-wrapper [model]=\"model()\">\n <span class=\"nvb-badge\" [ngClass]=\"badgeClass()\" [attr.data-testid]=\"tid('root')\">\n @if (model().showIcon) {\n <span class=\"material-symbols-outlined nvb-badge__icon\">{{ iconName() }}</span>\n }\n <span class=\"nvb-badge__text\">{{ resolveText() | dynamicText: model() }}</span>\n </span>\n</element-wrapper>\n",styles:[":host{display:block;width:100%}.nvb-badge{display:inline-flex;align-items:center;gap:5px;border-radius:var(--nvb-radius-full);border:1px solid var(--nvb-color-neutral-300);background:var(--nvb-color-neutral-100);color:var(--nvb-color-neutral-700);line-height:1.4;max-width:100%;vertical-align:middle}.nvb-badge__icon{font-size:14px;line-height:1}.nvb-badge__text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.nvb-badge--sm{min-height:20px;padding:2px 7px;font-size:11px}.nvb-badge--md{min-height:24px;padding:3px 9px;font-size:12px}.nvb-badge--lg{min-height:28px;padding:4px 11px;font-size:13px}.nvb-badge--square{border-radius:var(--nvb-radius-md)}.nvb-badge--info{border-color:color-mix(in oklab,var(--nvb-color-primary-500) 30%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-primary-500) 14%,var(--nvb-color-surface-mix-target, white));color:var(--nvb-color-primary-700)}.nvb-badge--success{border-color:color-mix(in oklab,var(--nvb-color-success-500) 34%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-success-500) 14%,var(--nvb-color-surface-mix-target, white));color:color-mix(in oklab,var(--nvb-color-success-500) 75%,black)}.nvb-badge--warn,.nvb-badge--warning{border-color:color-mix(in oklab,var(--nvb-color-warning-500) 40%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-warning-500) 16%,var(--nvb-color-surface-mix-target, white));color:color-mix(in oklab,var(--nvb-color-warning-500) 78%,black)}.nvb-badge--risk,.nvb-badge--danger{border-color:color-mix(in oklab,var(--nvb-color-risk-500) 38%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-risk-500) 14%,var(--nvb-color-surface-mix-target, white));color:var(--nvb-color-risk-700)}.nvb-badge--primary,.nvb-badge--new{border-color:color-mix(in oklab,var(--nvb-color-primary-500) 36%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-primary-500) 12%,var(--nvb-color-surface-mix-target, white));color:var(--nvb-color-primary-700)}\n"],dependencies:[{kind:"component",type:s,selector:"element-wrapper",inputs:["model","controlIdInput","labelForInput","groupRole","showTextWrapperInput"],exportAs:["elementWrapper"]},{kind:"directive",type:c,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"pipe",type:l,name:"dynamicText"}],changeDetection:o.ChangeDetectionStrategy.OnPush})};o.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.2.1",ngImport:o,type:i,decorators:[{type:g,args:[{selector:"badge-element",changeDetection:m.OnPush,imports:[s,c,l],template:"<element-wrapper [model]=\"model()\">\n <span class=\"nvb-badge\" [ngClass]=\"badgeClass()\" [attr.data-testid]=\"tid('root')\">\n @if (model().showIcon) {\n <span class=\"material-symbols-outlined nvb-badge__icon\">{{ iconName() }}</span>\n }\n <span class=\"nvb-badge__text\">{{ resolveText() | dynamicText: model() }}</span>\n </span>\n</element-wrapper>\n",styles:[":host{display:block;width:100%}.nvb-badge{display:inline-flex;align-items:center;gap:5px;border-radius:var(--nvb-radius-full);border:1px solid var(--nvb-color-neutral-300);background:var(--nvb-color-neutral-100);color:var(--nvb-color-neutral-700);line-height:1.4;max-width:100%;vertical-align:middle}.nvb-badge__icon{font-size:14px;line-height:1}.nvb-badge__text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.nvb-badge--sm{min-height:20px;padding:2px 7px;font-size:11px}.nvb-badge--md{min-height:24px;padding:3px 9px;font-size:12px}.nvb-badge--lg{min-height:28px;padding:4px 11px;font-size:13px}.nvb-badge--square{border-radius:var(--nvb-radius-md)}.nvb-badge--info{border-color:color-mix(in oklab,var(--nvb-color-primary-500) 30%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-primary-500) 14%,var(--nvb-color-surface-mix-target, white));color:var(--nvb-color-primary-700)}.nvb-badge--success{border-color:color-mix(in oklab,var(--nvb-color-success-500) 34%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-success-500) 14%,var(--nvb-color-surface-mix-target, white));color:color-mix(in oklab,var(--nvb-color-success-500) 75%,black)}.nvb-badge--warn,.nvb-badge--warning{border-color:color-mix(in oklab,var(--nvb-color-warning-500) 40%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-warning-500) 16%,var(--nvb-color-surface-mix-target, white));color:color-mix(in oklab,var(--nvb-color-warning-500) 78%,black)}.nvb-badge--risk,.nvb-badge--danger{border-color:color-mix(in oklab,var(--nvb-color-risk-500) 38%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-risk-500) 14%,var(--nvb-color-surface-mix-target, white));color:var(--nvb-color-risk-700)}.nvb-badge--primary,.nvb-badge--new{border-color:color-mix(in oklab,var(--nvb-color-primary-500) 36%,var(--nvb-color-surface-mix-target, white));background:color-mix(in oklab,var(--nvb-color-primary-500) 12%,var(--nvb-color-surface-mix-target, white));color:var(--nvb-color-primary-700)}\n"]}]}],propDecorators:{model:[{type:o.Input,args:[{isSignal:true,alias:"model",required:true}]}]}});export{x as n,i as t};