@yomotech/view-toolkit 1.0.17 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yomotech/view-toolkit",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "peerDependencies": {
5
5
  "@angular/cdk": "^21.0.0",
6
6
  "@angular/common": "^21.0.0",
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, ElementRef, ChangeDetectorRef, NgZone, SimpleChanges, OnInit, OnChanges, AfterViewInit, OnDestroy, Injector } from '@angular/core';
2
+ import { EventEmitter, ElementRef, ChangeDetectorRef, NgZone, SimpleChanges, OnInit, OnChanges, AfterViewInit, OnDestroy, Injector, PipeTransform } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import * as rxjs from 'rxjs';
5
5
  import { Platform } from '@angular/cdk/platform';
@@ -195,8 +195,27 @@ interface CustomKeyboardSession {
195
195
  originalInputMode: string | null;
196
196
  originalInputType: string | null;
197
197
  }
198
+ /** Set on body while keyboard or calendar stand at the right edge instead of the bottom. */
199
+ declare const SIDE_DOCK_CLASS = "vl-side-dock";
200
+ /**
201
+ * Side or bottom, decided from the space at hand rather than a device or an orientation: docked at
202
+ * the bottom, a panel (keyboard or calendar, up to about half the height) must leave about two of
203
+ * the dialog's fields visible below its header. If it would not and the dialog still has room
204
+ * beside a panel, the panels dock at the right edge - and the dialog stands left of them for as
205
+ * long as it is open, so it never moves. Returns the width kept free at the right (panel plus its
206
+ * distance to the screen edge), or null for the bottom. Also used by the app to place the dialog.
207
+ */
208
+ declare function sideDockWidth(): number | null;
198
209
  declare class CustomKeyboardService {
199
210
  private openingSuspendedUntil;
211
+ private tapsTracked;
212
+ private lastPointerDownAt;
213
+ private lastClickAt;
214
+ /** Set by DateTimePickerService: closes the open picker when another field is tapped. */
215
+ private pickerCloser;
216
+ /** Watches the dialog a side-docked panel lines up with. */
217
+ private dialogObserver;
218
+ constructor();
200
219
  private lastKeyboardHeight;
201
220
  private pickerOverlayOpen;
202
221
  private pickerTriggerPressedUntil;
@@ -208,6 +227,31 @@ declare class CustomKeyboardService {
208
227
  private blockInitialInteraction;
209
228
  private scrollTargetIntoDialogView;
210
229
  private updateKeyboardHeight;
230
+ /**
231
+ * Runs once the tap that opened the keyboard is complete. The keyboard opens on touch-down; a
232
+ * scroll before the finger lifts makes the click land beside the field, which then loses its
233
+ * focus. Without a tap in progress it runs on the next frame.
234
+ */
235
+ private afterTap;
236
+ /**
237
+ * Height of the keyboard docked at the bottom: the last measured one, or the height its
238
+ * screen-relative key sizes give (see the stylesheet) before it was ever shown.
239
+ */
240
+ keyboardHeight(): number;
241
+ /** Hands the picker closer over; see pickerCloser. */
242
+ setPickerCloser(closer: () => void): void;
243
+ /**
244
+ * The keyboard opens on touch-down; under a field near the bottom it slides in under the
245
+ * finger and the click of the same tap lands on it, so the field never got its focus.
246
+ */
247
+ private refocusTarget;
248
+ private trackTaps;
249
+ /**
250
+ * Scrolls the dialog just far enough that the active field stands fully above the keyboard,
251
+ * or fully below the dialog header when it went up out of sight. A field already in view
252
+ * does not move.
253
+ */
254
+ private scrollTargetAboveKeyboard;
211
255
  private canProcessKeyboardAction;
212
256
  insert(character: string): void;
213
257
  backspace(): void;
@@ -224,6 +268,8 @@ declare class CustomKeyboardService {
224
268
  private readonly documentPointerDownHandler;
225
269
  private readonly activeTargetBlurHandler;
226
270
  private handleDocumentPointerDown;
271
+ /** Closes the keyboard when the outside press ends as a tap; a swipe (scrolling) keeps it. */
272
+ private closeOnTapNotSwipe;
227
273
  private handleActiveTargetBlur;
228
274
  private insertDateTimeDigit;
229
275
  private removeDateTimeDigit;
@@ -246,6 +292,25 @@ declare class CustomKeyboardService {
246
292
  */
247
293
  reserveBottomArea(panel: HTMLElement | null): void;
248
294
  releaseBottomArea(): void;
295
+ /** See sideDockWidth; keeps the width for the panels' styles. */
296
+ dockAtSide(): boolean;
297
+ /** A panel takes the side: the bottom area goes, the dialog stands beside it. */
298
+ useSideDock(): void;
299
+ /**
300
+ * The panel lines up with the dialog - the dialog keeps its own size and place. At the side the
301
+ * panel takes over its upper and lower edge, at the bottom its left and right edge, and follows
302
+ * when the dialog changes (an error message, a turn of the device).
303
+ */
304
+ private followDialog;
305
+ /**
306
+ * Keyboard and calendar look like the page behind them: its background colour - from the
307
+ * project's styles, the app or the theme - becomes --vl-page-background. Dialogs, masks and the
308
+ * panels themselves are looked through; transparent elements pass on their parent's colour.
309
+ */
310
+ applyPageBackground(): void;
311
+ /** Keyboard: side or bottom, the same decision as the calendar's. */
312
+ private applyDock;
313
+ private clearDock;
249
314
  getActiveValue(type: CustomKeyboardType, targetName?: string): string | null;
250
315
  static ɵfac: i0.ɵɵFactoryDeclaration<CustomKeyboardService, never>;
251
316
  static ɵprov: i0.ɵɵInjectableDeclaration<CustomKeyboardService>;
@@ -270,10 +335,21 @@ declare class DateTimePickerService {
270
335
  private activePicker;
271
336
  private activePickerRequest;
272
337
  private pickerOpening;
338
+ /** Whether the system keyboard is up; only then does an icon have to wait for it to hide. */
339
+ private systemKeyboardVisible;
273
340
  private lockedPickerInput;
274
341
  constructor(keyboard: CustomKeyboardService);
275
342
  /** (onShow) of a picker. */
276
343
  onShown(): void;
344
+ /**
345
+ * Side or bottom - the keyboard service decides from the space at hand, the same for the
346
+ * keyboard, so switching between calendar and keyboard never moves the dialog. At the side the
347
+ * calendar stands at the right edge over the full height with the dialog beside it; at the
348
+ * bottom it docks like a keyboard and the dialog ends above it. Decided again on every resize.
349
+ */
350
+ private placeDockedPanel;
351
+ /** Side dock: the field only has to be inside the dialog's visible part. */
352
+ private scrollFieldIntoDialog;
277
353
  /** (onClose) of a picker; pass the picker so a late close of a replaced one is ignored. */
278
354
  onClose(picker?: any): void;
279
355
  /** (pointerdown) of the calendar or clock icon inside a .picker-field. */
@@ -291,10 +367,18 @@ declare class DateTimePickerService {
291
367
  */
292
368
  closeIfWithin(container: HTMLElement): void;
293
369
  /**
294
- * A month has five or six week rows, so the docked calendar grew and shrank while paging
295
- * through the months and its upper edge went up and down. It keeps the height of six rows.
370
+ * The docked calendar is exactly as high as the keyboard, so switching between the two moves
371
+ * nothing; the day cells are sized to fit the header, the weekdays and always six week rows,
372
+ * so paging through months with five and six weeks does not change its height either.
296
373
  */
297
- private keepSixWeekHeight;
374
+ private fitToKeyboardHeight;
375
+ /** Day cells as large as the panel's height allows for its header, the weekdays and six weeks. */
376
+ private fitDays;
377
+ /**
378
+ * The time picker hangs below its field - upright there is room. Where there is not (a phone in
379
+ * landscape), the field scrolls up first; PrimeNG would put the picker above it otherwise.
380
+ */
381
+ private makeRoomBelow;
298
382
  /**
299
383
  * Scrolls the dialog so the field sits right above the docked picker: the eye and the thumb
300
384
  * move a short way from the value to the picker instead of across the whole screen.
@@ -326,6 +410,15 @@ declare class CardComponent {
326
410
  private notificationService;
327
411
  private oauthService;
328
412
  private requestService;
413
+ private readonly remoteLists;
414
+ /** Loaded lists by field reference. */
415
+ remoteData: Record<string, any[]>;
416
+ /** Current suggestions of an autocomplete by field reference. */
417
+ remoteSuggestions: Record<string, any[]>;
418
+ /** Loads every backend list the given layout nodes describe; dropdown/combobox get their items. */
419
+ loadRemoteLists(nodes: any[], propertySchema: any): Promise<void>;
420
+ /** (completeMethod) of an autocomplete with a backend list. */
421
+ completeRemote(event: any, node: any): void;
329
422
  /** Date and time picker behaviour shared by all containers. */
330
423
  readonly picker: DateTimePickerService;
331
424
  private readonly pickerHost;
@@ -422,6 +515,15 @@ declare class CardComponent {
422
515
  }
423
516
 
424
517
  declare class FormComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
518
+ private readonly remoteLists;
519
+ /** Loaded lists by field reference. */
520
+ remoteData: Record<string, any[]>;
521
+ /** Current suggestions of an autocomplete by field reference. */
522
+ remoteSuggestions: Record<string, any[]>;
523
+ /** Loads every backend list the given layout nodes describe; dropdown/combobox get their items. */
524
+ loadRemoteLists(nodes: any[], propertySchema: any): Promise<void>;
525
+ /** (completeMethod) of an autocomplete with a backend list. */
526
+ completeRemote(event: any, node: any): void;
425
527
  /** Date and time picker behaviour shared by all containers. */
426
528
  readonly picker: DateTimePickerService;
427
529
  private readonly host;
@@ -477,10 +579,25 @@ declare class GridComponent implements AfterViewInit, OnDestroy {
477
579
  private utilityService;
478
580
  private notificationService;
479
581
  private oktaAuthService;
582
+ private readonly remoteLists;
583
+ /** Loaded lists by field reference. */
584
+ remoteData: Record<string, any[]>;
585
+ /** Current suggestions of an autocomplete by field reference. */
586
+ remoteSuggestions: Record<string, any[]>;
587
+ /** Loads every backend list the given layout nodes describe; dropdown/combobox get their items. */
588
+ loadRemoteLists(nodes: any[], propertySchema: any): Promise<void>;
589
+ /** (completeMethod) of an autocomplete with a backend list. */
590
+ completeRemote(event: any, node: any): void;
480
591
  /** Date and time picker behaviour shared by all containers. */
481
592
  readonly picker: DateTimePickerService;
482
593
  private readonly host;
483
594
  ngOnDestroy(): void;
595
+ private sideHintObserver?;
596
+ /** Marks the table's scroll area while columns lie beyond its left or right edge. */
597
+ private updateSideHints;
598
+ private onSideScroll;
599
+ /** Watches size and content of the table, so the hints follow new data and a turn of the device. */
600
+ private startSideHints;
484
601
  /** New data objects use boolean; older projects may still use checkbox. */
485
602
  isLegacyCheckboxFieldType(type: string | undefined): boolean;
486
603
  isLogined: boolean;
@@ -615,6 +732,7 @@ declare class ModelComponent implements OnChanges, OnDestroy {
615
732
  private readonly dialogRef;
616
733
  private readonly dialogConfig;
617
734
  private utilityService;
735
+ private readonly remoteLists;
618
736
  /** Keep existing checkbox data objects usable; new objects use boolean. */
619
737
  renderFieldType(type: string | undefined): string | undefined;
620
738
  /** Date and time picker behaviour shared by all containers. */
@@ -643,22 +761,11 @@ declare class ModelComponent implements OnChanges, OnDestroy {
643
761
  getButtonCaption(formField: any): any;
644
762
  mapDataToPropertySchema(data: any, modalItemInfo: any): void;
645
763
  setAutoCompleteData(): Promise<void>;
646
- fetchAutocompleteData(formField: any): Promise<any>;
647
- resolveAutocompleteConfig(config: any, userInfo: any): {
648
- url: string;
649
- method: any;
650
- params: any;
651
- headers: {
652
- Authorization: string;
653
- Accept: string;
654
- } | {
655
- Authorization?: undefined;
656
- Accept?: undefined;
657
- };
658
- };
659
- private getAutocompleteRequestUrl;
660
- buildCompany(userInfo: any): string;
764
+ /** The field's backend list (RemoteListService - shared by every container). */
765
+ fetchAutocompleteData(formField: any): Promise<any[]>;
766
+ /** Resolves {{...}} against the user info (RemoteListService). */
661
767
  resolveToken(template: string, context: any): string;
768
+ buildCompany(userInfo: any): string;
662
769
  getScope(scope: any): string;
663
770
  autocompChangeEvent(event: any, formField: any): void;
664
771
  autocompFocusOutEvent(event: any, formField: any): void;
@@ -745,6 +852,12 @@ declare class MobileKeycloakService {
745
852
  getUserInfo(accessToken: any, issuer: any): Promise<any>;
746
853
  getAccessToken(): string | null;
747
854
  getRefreshToken(): string | null;
855
+ /**
856
+ * Ends the Keycloak session without a browser window: the refresh token goes to the logout
857
+ * endpoint directly (allowed for public clients). The browser variant left an empty in-app window
858
+ * that did not close, and its close button cancelled the new sign-in started behind it. The local
859
+ * sign-in is removed in any case - without network the session simply runs out at Keycloak.
860
+ */
748
861
  logout(): Promise<void>;
749
862
  static ɵfac: i0.ɵɵFactoryDeclaration<MobileKeycloakService, never>;
750
863
  static ɵprov: i0.ɵɵInjectableDeclaration<MobileKeycloakService>;
@@ -793,6 +906,8 @@ declare class SideMenuComponent implements AfterViewInit, OnChanges, OnDestroy {
793
906
  errorMessage: EventEmitter<any>;
794
907
  deleteProject: EventEmitter<any>;
795
908
  paginationType: EventEmitter<any>;
909
+ /** The language file in use ("de.json"); its menu entry has a check mark. */
910
+ activeLanguage: string | null;
796
911
  sideMenu: ElementRef<HTMLElement>;
797
912
  readonly PRIME_DE: {
798
913
  firstDayOfWeek: number;
@@ -824,6 +939,13 @@ declare class SideMenuComponent implements AfterViewInit, OnChanges, OnDestroy {
824
939
  getPaginationType(): Promise<void>;
825
940
  ngAfterViewInit(): Promise<void>;
826
941
  ngOnDestroy(): void;
942
+ /**
943
+ * Mobile menu (overlay when open, no width when closed, styles under :host(.sidemenu-mobile)):
944
+ * the app on iOS and Android - phones and tablets - and small browser windows.
945
+ */
946
+ mobileMode: boolean;
947
+ onResizeMobileMode(): void;
948
+ private computeMobileMode;
827
949
  onDocumentClick(event: MouseEvent): void;
828
950
  toggleCollapsed(): void;
829
951
  private isNativeMobile;
@@ -836,6 +958,8 @@ declare class SideMenuComponent implements AfterViewInit, OnChanges, OnDestroy {
836
958
  private clearLoginUser;
837
959
  getUserInfoFromToken(token: string): any | null;
838
960
  setLoginedUser(user: any): void;
961
+ /** The menu entry with action 'logout', at any depth of the menu. */
962
+ private findLogoutMenu;
839
963
  initializeProjects(): void;
840
964
  setProjectSetting(): Promise<void>;
841
965
  private setLanguageMenuImage;
@@ -935,7 +1059,7 @@ declare class Textbox {
935
1059
  };
936
1060
  /** The toolkit keyboard for this field, from option.keyboardType or the attribute type. */
937
1061
  keyboardTypeFor(formField: any): CustomKeyboardType | null;
938
- getPlaceholder(formField: any): any;
1062
+ getPlaceholder(formField: any): string;
939
1063
  static ɵfac: i0.ɵɵFactoryDeclaration<Textbox, never>;
940
1064
  static ɵcmp: i0.ɵɵComponentDeclaration<Textbox, "vl-textbox", never, { "formField": { "alias": "formField"; "required": false; }; "modalItemInfo": { "alias": "modalItemInfo"; "required": false; }; }, {}, never, never, true, never>;
941
1065
  }
@@ -961,8 +1085,17 @@ declare class AppVersionResetService {
961
1085
  static ɵprov: i0.ɵɵInjectableDeclaration<AppVersionResetService>;
962
1086
  }
963
1087
 
1088
+ /** True in the native app on iOS (iPhone and iPad) and Android; false in a browser. */
1089
+ declare function isNativeMobile(): boolean;
1090
+ /**
1091
+ * True in the native app on a phone - upright and in landscape alike (its shorter screen side is
1092
+ * below 600pt). Tablets get the tablet and desktop styles by width.
1093
+ */
1094
+ declare function isNativePhone(): boolean;
1095
+
964
1096
  declare class CustomKeyboardComponent {
965
1097
  readonly keyboard: CustomKeyboardService;
1098
+ /** Capital letters: on for the first letter of an empty field, then off - as on iOS. */
966
1099
  readonly uppercase: i0.WritableSignal<boolean>;
967
1100
  /** true while the ?123 page is shown instead of the letters. */
968
1101
  readonly symbols: i0.WritableSignal<boolean>;
@@ -997,5 +1130,86 @@ declare class CustomKeyboardDirective implements OnDestroy {
997
1130
  static ɵdir: i0.ɵɵDirectiveDeclaration<CustomKeyboardDirective, "[vlCustomKeyboard]", never, { "keyboardType": { "alias": "vlCustomKeyboard"; "required": false; }; }, {}, never, never, true, never>;
998
1131
  }
999
1132
 
1000
- export { AppVersionResetService, CardComponent, ConfigService, Couchdb, CustomKeyboardComponent, CustomKeyboardDirective, CustomKeyboardService, FormComponent, GridComponent, HeaderMenuComponent, LogsComponent, MobileKeycloakService, ModelComponent, NetworkLogService, NotificationService, PaginationComponent, RequestService, SideMenuComponent, UtilityService, ViewToolkitModule, normalizeCustomKeyboardType, resolveCustomKeyboardType };
1001
- export type { CustomKeyboardTarget, CustomKeyboardType, MobileAuthTokens };
1133
+ /**
1134
+ * The placeholder of the field `reference` in `propertySchema`, translated when the selected
1135
+ * language has an entry for it; empty when the project defines none.
1136
+ */
1137
+ declare function resolvePlaceholder(propertySchema: any, reference: string | null | undefined, translations?: Record<string, string> | null): string;
1138
+ /** Template form of resolvePlaceholder: [placeholder]="propertySchema | vlPlaceholder: reference". */
1139
+ declare class PlaceholderPipe implements PipeTransform {
1140
+ transform(propertySchema: any, reference: string | null | undefined, translations?: Record<string, string> | null): string;
1141
+ static ɵfac: i0.ɵɵFactoryDeclaration<PlaceholderPipe, never>;
1142
+ static ɵpipe: i0.ɵɵPipeDeclaration<PlaceholderPipe, "vlPlaceholder", true>;
1143
+ }
1144
+
1145
+ interface RequestTimeoutMessages {
1146
+ requestSlow: string;
1147
+ requestStillSlow: string;
1148
+ requestTimeout: string;
1149
+ }
1150
+ /** Thrown when a request was given up after the last stage. */
1151
+ declare class RequestTimeoutError extends Error {
1152
+ constructor();
1153
+ }
1154
+ /** Stages in ms: first hint, second hint, give up. */
1155
+ declare const REQUEST_STAGES: {
1156
+ readonly slow: 10000;
1157
+ readonly stillSlow: 30000;
1158
+ readonly timeout: 60000;
1159
+ };
1160
+ declare class RequestTimeoutService {
1161
+ private readonly notification;
1162
+ /** For code outside Angular's injection (stagedRequest). */
1163
+ static instance: RequestTimeoutService | null;
1164
+ private messages;
1165
+ /** When each message was shown last; several requests waiting at once show it only once. */
1166
+ private lastShown;
1167
+ constructor(notification: NotificationService);
1168
+ /** The texts in the current language (from the app's framework translation). */
1169
+ setMessages(messages: Partial<RequestTimeoutMessages> | null | undefined): void;
1170
+ /** Shows a stage's message, at most once per stage interval. */
1171
+ notify(stage: keyof RequestTimeoutMessages): void;
1172
+ /**
1173
+ * Runs one request under the waiting rule. `work` gets an AbortSignal (fetch can use it);
1174
+ * after the last stage the signal aborts and the promise rejects with RequestTimeoutError.
1175
+ */
1176
+ run<T>(work: (signal: AbortSignal) => Promise<T>): Promise<T>;
1177
+ static ɵfac: i0.ɵɵFactoryDeclaration<RequestTimeoutService, never>;
1178
+ static ɵprov: i0.ɵɵInjectableDeclaration<RequestTimeoutService>;
1179
+ }
1180
+ /** A request under the waiting rule (RequestTimeoutService.run); runs plainly before Angular is up. */
1181
+ declare function stagedRequest<T>(work: (signal: AbortSignal) => Promise<T>): Promise<T>;
1182
+
1183
+ declare class RemoteListService {
1184
+ /** The signed-in user (claims + token), set by the app; used when a caller has none. */
1185
+ private currentUser;
1186
+ setUser(userInfo: any): void;
1187
+ /** Lists already loaded, by request (url + params), so a page does not ask twice. */
1188
+ private readonly cache;
1189
+ /** Like load(), with the current user and one request per source while the app runs. */
1190
+ loadShared(config: any): Promise<any[]>;
1191
+ /** Loads the list a field's source describes (option.autocomplete: url, method, params). */
1192
+ load(config: any, userInfo?: any): Promise<any[]>;
1193
+ resolveAutocompleteConfig(config: any, userInfo: any): {
1194
+ url: string;
1195
+ method: any;
1196
+ params: any;
1197
+ headers: {
1198
+ Authorization: string;
1199
+ Accept: string;
1200
+ } | {
1201
+ Authorization?: undefined;
1202
+ Accept?: undefined;
1203
+ };
1204
+ };
1205
+ private getAutocompleteRequestUrl;
1206
+ buildCompany(userInfo: any): string;
1207
+ resolveToken(template: string, context: any): string;
1208
+ /** Suggestions of `list` whose `field` starts with the typed `query` (case-insensitive). */
1209
+ filter(list: any[] | undefined, field: string | undefined, query: string | undefined): any[];
1210
+ static ɵfac: i0.ɵɵFactoryDeclaration<RemoteListService, never>;
1211
+ static ɵprov: i0.ɵɵInjectableDeclaration<RemoteListService>;
1212
+ }
1213
+
1214
+ export { AppVersionResetService, CardComponent, ConfigService, Couchdb, CustomKeyboardComponent, CustomKeyboardDirective, CustomKeyboardService, FormComponent, GridComponent, HeaderMenuComponent, LogsComponent, MobileKeycloakService, ModelComponent, NetworkLogService, NotificationService, PaginationComponent, PlaceholderPipe, REQUEST_STAGES, RemoteListService, RequestService, RequestTimeoutError, RequestTimeoutService, SIDE_DOCK_CLASS, SideMenuComponent, UtilityService, ViewToolkitModule, isNativeMobile, isNativePhone, normalizeCustomKeyboardType, resolveCustomKeyboardType, resolvePlaceholder, sideDockWidth, stagedRequest };
1215
+ export type { CustomKeyboardTarget, CustomKeyboardType, MobileAuthTokens, RequestTimeoutMessages };