@rdlabo/ionic-angular-kit 0.0.12 → 0.0.14
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.
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, EnvironmentProviders, OnInit, ElementRef } from '@angular/core';
|
|
3
|
-
import { ModalOptions, PopoverOptions, ToastOptions, AlertController } from '@ionic/angular/standalone';
|
|
2
|
+
import { InjectionToken, EnvironmentProviders, InputSignalWithTransform, OnInit, ElementRef, WritableSignal } from '@angular/core';
|
|
3
|
+
import { ModalOptions, PopoverOptions, ToastOptions, LoadingOptions, AlertController, ActionSheetController } from '@ionic/angular/standalone';
|
|
4
4
|
import { PluginListenerHandle } from '@capacitor/core';
|
|
5
|
+
import { BehaviorSubject, Observable } from 'rxjs';
|
|
6
|
+
import { BRLMPrinterModelName, BRLMPrinterLabelName, BRLMPrintOptions } from '@rdlabo/capacitor-brotherprint';
|
|
5
7
|
import { RouterStateSnapshot, UrlTree, CanActivateFn } from '@angular/router';
|
|
6
|
-
import { Observable } from 'rxjs';
|
|
7
8
|
import { HttpRequest, HttpResponse, HttpErrorResponse, HttpEvent, HttpInterceptorFn } from '@angular/common/http';
|
|
8
9
|
import { ImpactStyle } from '@capacitor/haptics';
|
|
9
10
|
|
|
@@ -142,6 +143,83 @@ interface KitModalPresentOptions extends Omit<ModalOptions, 'component' | 'compo
|
|
|
142
143
|
*/
|
|
143
144
|
watchKeyboard?: boolean;
|
|
144
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Optional static metadata a modal component may declare to make {@link KitOverlayController.presentModal}
|
|
148
|
+
* type-safe in its dismiss data: the value passed to `dismiss()` is inferred from `modalReturn`.
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* Props do *not* need to be declared here — {@link KitOverlayController.presentModal} infers them directly
|
|
152
|
+
* from the component's `input()` fields (see {@link ModalPropsOf}), so `input()` stays the single source of
|
|
153
|
+
* truth and can never drift from a hand-written declaration. Only the dismiss-data shape, which has no
|
|
154
|
+
* counterpart on the component, is declared — as a `declare static modalReturn` phantom type with no runtime
|
|
155
|
+
* value, so it adds nothing to the bundle.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* export class EditPage {
|
|
160
|
+
* declare static modalReturn: { saved: boolean };
|
|
161
|
+
* readonly id = input.required<number>(); // props are inferred from here
|
|
162
|
+
* readonly note = input<string>(); // default-less input() → optional prop
|
|
163
|
+
* }
|
|
164
|
+
*
|
|
165
|
+
* // Caller — `id` is required (input.required), `note` optional; result is `{ saved: boolean } | undefined`:
|
|
166
|
+
* const result = await overlay.presentModal(EditPage, { id: 1 });
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
interface ModalMetadata<R = unknown> {
|
|
170
|
+
/** Shape of the data the modal resolves with when dismissed. */
|
|
171
|
+
modalReturn?: R;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Write type of a signal `input()` field (unwraps `input.required`, `input()` and transform inputs).
|
|
175
|
+
*
|
|
176
|
+
* @remarks
|
|
177
|
+
* Matched with `any` (not `unknown`): `InputSignalWithTransform`'s `TransformT` is contravariant, so
|
|
178
|
+
* `InputSignal<number>` is not assignable to `InputSignalWithTransform<unknown, unknown>`.
|
|
179
|
+
*/
|
|
180
|
+
type InputWriteType<F> = F extends InputSignalWithTransform<any, infer W> ? W : never;
|
|
181
|
+
/** Instance type of a component constructor; `never` for non-class components (string / HTMLElement refs). */
|
|
182
|
+
type InstanceOf<C> = C extends abstract new (...args: never[]) => infer I ? I : never;
|
|
183
|
+
/** Keys of the `input()` signal fields on a component instance. */
|
|
184
|
+
type InputFieldKeys<I> = {
|
|
185
|
+
[K in keyof I]-?: I[K] extends InputSignalWithTransform<any, any> ? K : never;
|
|
186
|
+
}[keyof I];
|
|
187
|
+
/**
|
|
188
|
+
* Props object inferred from a component's `input()` fields. Required vs. optional is decided by the write
|
|
189
|
+
* type: `input.required<T>()` / `input<T>(default)` yield `T` (no `undefined`) → required prop, while a
|
|
190
|
+
* default-less `input<T>()` yields `T | undefined` → optional prop.
|
|
191
|
+
*
|
|
192
|
+
* @remarks
|
|
193
|
+
* Angular's types cannot distinguish `input.required<T>()` from a defaulted `input<T>(default)` — both are
|
|
194
|
+
* `InputSignal<T>` — so a defaulted input is (safely) treated as required. Declare inputs you want to omit at
|
|
195
|
+
* the call site as default-less `input<T>()`.
|
|
196
|
+
*/
|
|
197
|
+
type ModalPropsOf<I> = {
|
|
198
|
+
[K in InputFieldKeys<I> as undefined extends InputWriteType<I[K]> ? never : K]: InputWriteType<I[K]>;
|
|
199
|
+
} & {
|
|
200
|
+
[K in InputFieldKeys<I> as undefined extends InputWriteType<I[K]> ? K : never]?: InputWriteType<I[K]>;
|
|
201
|
+
};
|
|
202
|
+
/** `input()` keys whose write type excludes `undefined` (required / defaulted inputs). Empty when none. */
|
|
203
|
+
type RequiredInputKeys<I> = {
|
|
204
|
+
[K in InputFieldKeys<I>]: undefined extends InputWriteType<I[K]> ? never : K;
|
|
205
|
+
}[InputFieldKeys<I>];
|
|
206
|
+
/**
|
|
207
|
+
* Dismiss-data type inferred from a component's static {@link ModalMetadata.modalReturn}. A component that
|
|
208
|
+
* declares no `modalReturn` resolves to `void`: it is treated as returning no dismiss data, so the compiler
|
|
209
|
+
* rejects any attempt to read the result. Declare `modalReturn` on modals that do resolve with data.
|
|
210
|
+
*/
|
|
211
|
+
type ModalReturnOf<C> = C extends {
|
|
212
|
+
modalReturn: infer R;
|
|
213
|
+
} ? R : void;
|
|
214
|
+
/** Loose trailing args (optional, untyped props) — used when a component exposes no signal `input()` fields. */
|
|
215
|
+
type LooseModalPresentArgs = [componentProps?: ModalOptions['componentProps'], options?: KitModalPresentOptions];
|
|
216
|
+
/**
|
|
217
|
+
* Trailing `presentModal` args derived from a component's `input()` fields: props are inferred and typed via
|
|
218
|
+
* {@link ModalPropsOf}. When the component declares at least one required input the props argument is required;
|
|
219
|
+
* when every input is optional the props argument itself is optional. Components with no signal inputs (plain
|
|
220
|
+
* classes, `@Input()`-decorator components, or non-class refs) fall back to loose, untyped props.
|
|
221
|
+
*/
|
|
222
|
+
type ModalPresentArgs<C, I = InstanceOf<C>> = [I] extends [never] ? LooseModalPresentArgs : [InputFieldKeys<I>] extends [never] ? LooseModalPresentArgs : [RequiredInputKeys<I>] extends [never] ? [componentProps?: ModalPropsOf<I>, options?: KitModalPresentOptions] : [componentProps: ModalPropsOf<I>, options?: KitModalPresentOptions];
|
|
145
223
|
/**
|
|
146
224
|
* Options for {@link KitOverlayController.alertClose}.
|
|
147
225
|
*/
|
|
@@ -181,7 +259,7 @@ interface KitAlertConfirmOptions extends KitAlertCloseOptions {
|
|
|
181
259
|
* constructor(private readonly overlay: KitOverlayController) {}
|
|
182
260
|
*
|
|
183
261
|
* async edit(): Promise<void> {
|
|
184
|
-
* const result = await this.overlay.presentModal
|
|
262
|
+
* const result = await this.overlay.presentModal(EditPage, { id: 1 });
|
|
185
263
|
* if (result) {
|
|
186
264
|
* await this.overlay.presentToast({ message: 'Saved' });
|
|
187
265
|
* }
|
|
@@ -201,12 +279,18 @@ declare class KitOverlayController {
|
|
|
201
279
|
* @remarks
|
|
202
280
|
* Presenting a modal triggers light native haptic feedback as an intentional kit UX choice,
|
|
203
281
|
* consistent with {@link presentPopover} and {@link presentToast}.
|
|
282
|
+
*
|
|
283
|
+
* Props are inferred from the component's `input()` fields (see {@link ModalPropsOf}): required inputs
|
|
284
|
+
* become required props, so the compiler rejects a call that omits them. The return type is inferred from
|
|
285
|
+
* a static `modalReturn` (see {@link ModalMetadata}); a component with no `modalReturn` resolves to `void`
|
|
286
|
+
* — the modal is treated as returning no dismiss data.
|
|
204
287
|
* @example
|
|
205
288
|
* ```ts
|
|
206
|
-
*
|
|
289
|
+
* // Inferred — `id` required (input.required), `note` optional; result is `{ saved: boolean } | undefined`:
|
|
290
|
+
* const result = await overlay.presentModal(EditPage, { id: 1 });
|
|
207
291
|
* ```
|
|
208
292
|
*/
|
|
209
|
-
presentModal<
|
|
293
|
+
presentModal<C extends ModalOptions['component']>(component: C, ...args: ModalPresentArgs<C>): Promise<ModalReturnOf<C> | undefined>;
|
|
210
294
|
/**
|
|
211
295
|
* Present a popover and resolve with the data passed to its dismissal.
|
|
212
296
|
*
|
|
@@ -286,6 +370,59 @@ declare class KitOverlayController {
|
|
|
286
370
|
static ɵprov: i0.ɵɵInjectableDeclaration<KitOverlayController>;
|
|
287
371
|
}
|
|
288
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Reference-counted wrapper around Ionic's `LoadingController` that keeps at most one loading
|
|
375
|
+
* indicator on screen across concurrent async work.
|
|
376
|
+
*
|
|
377
|
+
* @remarks
|
|
378
|
+
* Each {@link presentLoading} increments a counter and each {@link dismissLoading} decrements it; the
|
|
379
|
+
* indicator is presented on the `0 → 1` transition and dismissed on the `N → 0` transition. This
|
|
380
|
+
* removes the flicker / "stuck spinner" bugs that come from every service calling
|
|
381
|
+
* `LoadingController.create/dismiss` independently.
|
|
382
|
+
*
|
|
383
|
+
* All operations are serialized through an internal promise chain, so a `create → present` sequence
|
|
384
|
+
* can never interleave with a concurrent `dismiss`. That is what makes the counter race-safe: a
|
|
385
|
+
* dismiss that arrives while the indicator is still being presented runs *after* `present()` settles
|
|
386
|
+
* and therefore tears the element down instead of leaving it orphaned on screen.
|
|
387
|
+
*
|
|
388
|
+
* Always pair every `presentLoading()` with exactly one `dismissLoading()` — a `try/finally` is the
|
|
389
|
+
* safest shape.
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```ts
|
|
393
|
+
* constructor(private readonly loading: KitLoadingController) {}
|
|
394
|
+
*
|
|
395
|
+
* async save(): Promise<void> {
|
|
396
|
+
* await this.loading.presentLoading({ message: 'Saving…' });
|
|
397
|
+
* try {
|
|
398
|
+
* await this.api.save();
|
|
399
|
+
* } finally {
|
|
400
|
+
* await this.loading.dismissLoading();
|
|
401
|
+
* }
|
|
402
|
+
* }
|
|
403
|
+
* ```
|
|
404
|
+
*/
|
|
405
|
+
declare class KitLoadingController {
|
|
406
|
+
#private;
|
|
407
|
+
/**
|
|
408
|
+
* Show the loading indicator, or join the one already on screen.
|
|
409
|
+
*
|
|
410
|
+
* @param options - Ionic loading options; only applied by the call that actually creates the
|
|
411
|
+
* indicator (the `0 → 1` transition). Ignored while an indicator is already present.
|
|
412
|
+
* @returns a Promise that resolves once the indicator is on screen (or immediately when one already is)
|
|
413
|
+
*/
|
|
414
|
+
presentLoading(options?: LoadingOptions): Promise<void>;
|
|
415
|
+
/**
|
|
416
|
+
* Release one reference; dismiss the indicator once the last reference is gone.
|
|
417
|
+
*
|
|
418
|
+
* @returns a Promise that resolves once the reference is released (and the indicator dismissed if
|
|
419
|
+
* this was the last one). No-ops when the counter is already at zero.
|
|
420
|
+
*/
|
|
421
|
+
dismissLoading(): Promise<void>;
|
|
422
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<KitLoadingController, never>;
|
|
423
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<KitLoadingController>;
|
|
424
|
+
}
|
|
425
|
+
|
|
289
426
|
/**
|
|
290
427
|
* Content for {@link KitReloadAlertController.present}.
|
|
291
428
|
*/
|
|
@@ -402,6 +539,70 @@ interface KitAuthFailedAlertOptions {
|
|
|
402
539
|
*/
|
|
403
540
|
declare const kitPresentAuthFailedAlert: (alertCtrl: AlertController, options: KitAuthFailedAlertOptions) => Promise<void>;
|
|
404
541
|
|
|
542
|
+
/** One selectable language in {@link kitPresentLanguageActionSheet}. */
|
|
543
|
+
interface KitLanguageOption {
|
|
544
|
+
/** Button label shown to the user (e.g. `English`, `日本語`). */
|
|
545
|
+
readonly text: string;
|
|
546
|
+
/** Locale identifier returned when this option is chosen (e.g. `en-US`, `ja`). */
|
|
547
|
+
readonly data: string;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Options for {@link kitPresentLanguageActionSheet}.
|
|
551
|
+
*
|
|
552
|
+
* @remarks
|
|
553
|
+
* The kit ships no strings or URLs of its own: labels, the locale list, and the redirect-URL mapping
|
|
554
|
+
* are all supplied by the caller, so a multilingual app passes `$localize`-resolved text and its own
|
|
555
|
+
* per-locale build paths.
|
|
556
|
+
*/
|
|
557
|
+
interface KitLanguageActionSheetOptions {
|
|
558
|
+
/** Action-sheet header text. */
|
|
559
|
+
readonly header: string;
|
|
560
|
+
/** Selectable languages, in display order. */
|
|
561
|
+
readonly locales: readonly KitLanguageOption[];
|
|
562
|
+
/** Text for the cancel button. */
|
|
563
|
+
readonly cancelText: string;
|
|
564
|
+
/** The currently active locale; selecting the same value is a no-op. Normalize before passing. */
|
|
565
|
+
readonly currentLocale: string;
|
|
566
|
+
/** The current in-app path (e.g. `router.url`), stashed so the app can restore it after the reload. */
|
|
567
|
+
readonly currentPath: string;
|
|
568
|
+
/** `sessionStorage` key under which {@link currentPath} is stored. */
|
|
569
|
+
readonly pathnameStorageKey: string;
|
|
570
|
+
/** Maps a chosen locale to the URL to navigate to (the app's per-locale build entry point). */
|
|
571
|
+
readonly buildRedirectUrl: (locale: string) => string;
|
|
572
|
+
/** Gate for the redirect — pass `false` (e.g. outside production) to present without navigating. */
|
|
573
|
+
readonly enabled: boolean;
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Present a language picker and, on a new selection, reload the app at that locale's entry point.
|
|
577
|
+
*
|
|
578
|
+
* @remarks
|
|
579
|
+
* A plain function (the `ActionSheetController` is passed in, so nothing is injected) that unifies the
|
|
580
|
+
* language-switch flow duplicated across apps. On a changed selection while {@link enabled} it stashes
|
|
581
|
+
* the current path in `sessionStorage` (so the app can return the user to where they were), records the
|
|
582
|
+
* chosen locale in `localStorage` under `'locale'`, and calls `window.location.replace()` with the
|
|
583
|
+
* app-provided URL. Because it performs navigation, it is a standalone helper rather than part of a
|
|
584
|
+
* controller (mirroring `kitPresentReloadAlert` / `kitPresentAuthFailedAlert`). Centralizing it means a
|
|
585
|
+
* future improvement to the switch flow lands in every app at once.
|
|
586
|
+
*
|
|
587
|
+
* @param actionSheetCtrl - the Ionic `ActionSheetController`
|
|
588
|
+
* @param options - labels, locale list, and redirect configuration; see {@link KitLanguageActionSheetOptions}
|
|
589
|
+
* @returns a Promise that resolves once presented (and, on a new selection, after the reload is triggered)
|
|
590
|
+
* @example
|
|
591
|
+
* ```ts
|
|
592
|
+
* await kitPresentLanguageActionSheet(inject(ActionSheetController), {
|
|
593
|
+
* header: $localize`言語設定`,
|
|
594
|
+
* locales: [{ text: 'English', data: 'en-US' }, { text: '日本語', data: 'ja' }],
|
|
595
|
+
* cancelText: $localize`キャンセル`,
|
|
596
|
+
* currentLocale: normalizedLocale,
|
|
597
|
+
* currentPath: this.#router.url,
|
|
598
|
+
* pathnameStorageKey: StorageKeyEnum.pathnameBeforeRedirect,
|
|
599
|
+
* buildRedirectUrl: (locale) => location.origin + (localePath[locale.toLowerCase()] ?? '/index.html'),
|
|
600
|
+
* enabled: environment.production,
|
|
601
|
+
* });
|
|
602
|
+
* ```
|
|
603
|
+
*/
|
|
604
|
+
declare const kitPresentLanguageActionSheet: (actionSheetCtrl: ActionSheetController, options: KitLanguageActionSheetOptions) => Promise<void>;
|
|
605
|
+
|
|
405
606
|
/**
|
|
406
607
|
* Work around iOS `ion-input` autofill values not propagating to the Angular form model.
|
|
407
608
|
*
|
|
@@ -485,6 +686,236 @@ type KitKeyboardAdjust = 'transform' | 'offset' | 'keyboard-offset';
|
|
|
485
686
|
*/
|
|
486
687
|
declare const kitKeyboardInit: (elementRef: ElementRef, type: KitKeyboardAdjust) => Promise<PluginListenerHandle[]>;
|
|
487
688
|
|
|
689
|
+
/**
|
|
690
|
+
* Theme configuration injected via `provideKitTheme()` and consumed by `KitThemeController`.
|
|
691
|
+
*
|
|
692
|
+
* @remarks
|
|
693
|
+
* All fields are required; the consuming application supplies a complete configuration so every app
|
|
694
|
+
* in the fleet has the same shape. The class lists absorb the per-app CSS drift: the kit toggles
|
|
695
|
+
* `darkClasses` on when dark and `lightClasses` on when light, so an app that only uses Ionic's
|
|
696
|
+
* palette passes `darkClasses: ['ion-palette-dark'], lightClasses: []`, while an app with an extra
|
|
697
|
+
* design-system palette adds its own classes (e.g. `darkClasses: ['ion-palette-dark', 'a2ui-dark']`,
|
|
698
|
+
* `lightClasses: ['a2ui-light']`).
|
|
699
|
+
*/
|
|
700
|
+
interface KitThemeConfig {
|
|
701
|
+
/** Key under which the chosen theme (`'light'` | `'dark'`) is persisted via `KitStorageService`. */
|
|
702
|
+
readonly storageKey: string;
|
|
703
|
+
/** Classes toggled **on** the document element when the dark theme is active. */
|
|
704
|
+
readonly darkClasses: readonly string[];
|
|
705
|
+
/** Classes toggled **on** the document element when the light theme is active. */
|
|
706
|
+
readonly lightClasses: readonly string[];
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Injection token carrying the {@link KitThemeConfig} for `KitThemeController`.
|
|
710
|
+
*
|
|
711
|
+
* @remarks
|
|
712
|
+
* Provide it through {@link provideKitTheme} rather than registering it directly.
|
|
713
|
+
*/
|
|
714
|
+
declare const KIT_THEME_CONFIG: InjectionToken<KitThemeConfig>;
|
|
715
|
+
/**
|
|
716
|
+
* Wire `KitThemeController` into the application.
|
|
717
|
+
*
|
|
718
|
+
* @param config - theme configuration: the storage key and the light/dark class lists
|
|
719
|
+
* @returns environment providers to add to the application's provider list
|
|
720
|
+
* @example
|
|
721
|
+
* ```ts
|
|
722
|
+
* bootstrapApplication(AppComponent, {
|
|
723
|
+
* providers: [
|
|
724
|
+
* provideKitTheme({
|
|
725
|
+
* storageKey: StorageKeyEnum.theme,
|
|
726
|
+
* darkClasses: ['ion-palette-dark', 'a2ui-dark'],
|
|
727
|
+
* lightClasses: ['a2ui-light'],
|
|
728
|
+
* }),
|
|
729
|
+
* ],
|
|
730
|
+
* });
|
|
731
|
+
* ```
|
|
732
|
+
*/
|
|
733
|
+
declare const provideKitTheme: (config: KitThemeConfig) => EnvironmentProviders;
|
|
734
|
+
|
|
735
|
+
/** The active theme mode. */
|
|
736
|
+
type KitThemeMode = 'light' | 'dark';
|
|
737
|
+
/**
|
|
738
|
+
* Light/dark theme controller: persists the user's choice, follows the OS setting until the user
|
|
739
|
+
* overrides it, toggles the configured palette classes, and syncs the native Android status bar.
|
|
740
|
+
*
|
|
741
|
+
* @remarks
|
|
742
|
+
* Consolidates the theme logic that had drifted across the fleet into one behavior. Notably it fixes
|
|
743
|
+
* a latent leak in one variant where the system-theme listener stayed registered after a manual
|
|
744
|
+
* toggle: {@link changeTheme} always detaches the listener via {@link removeEventListener} before
|
|
745
|
+
* applying the forced theme, so a later OS change can no longer silently flip an app the user pinned.
|
|
746
|
+
*
|
|
747
|
+
* - **Persistence** — the chosen mode is stored via {@link KitStorageService} under the configured key.
|
|
748
|
+
* - **Follow OS until overridden** — on boot with nothing stored, it tracks
|
|
749
|
+
* `prefers-color-scheme` (idempotent registration); once the user calls {@link changeTheme} it stops
|
|
750
|
+
* following and honors the explicit choice.
|
|
751
|
+
* - **Class toggling** — toggles {@link KitThemeConfig.darkClasses} on when dark and
|
|
752
|
+
* {@link KitThemeConfig.lightClasses} on when light, absorbing per-app CSS differences via config.
|
|
753
|
+
* - **Native status bar** — on Android native only, mirrors the Ionic behavior of setting the status
|
|
754
|
+
* bar style to match (iOS derives it from the web content, so it is intentionally left untouched).
|
|
755
|
+
*
|
|
756
|
+
* Subscribe to {@link themeSubject} to reflect the current mode in the UI (e.g. a settings toggle).
|
|
757
|
+
*
|
|
758
|
+
* @example
|
|
759
|
+
* ```ts
|
|
760
|
+
* // On boot (app.component):
|
|
761
|
+
* inject(KitThemeController).setDefaultThemeMode();
|
|
762
|
+
*
|
|
763
|
+
* // From a settings toggle:
|
|
764
|
+
* const theme = inject(KitThemeController);
|
|
765
|
+
* theme.themeSubject.subscribe((mode) => this.isDark.set(mode === 'dark'));
|
|
766
|
+
* theme.changeTheme(true);
|
|
767
|
+
* ```
|
|
768
|
+
*/
|
|
769
|
+
declare class KitThemeController {
|
|
770
|
+
#private;
|
|
771
|
+
/**
|
|
772
|
+
* Emits the active theme, seeded with `'light'`.
|
|
773
|
+
*
|
|
774
|
+
* @remarks
|
|
775
|
+
* A `BehaviorSubject`, so a late subscriber immediately receives the current mode; it emits again
|
|
776
|
+
* on every {@link setDefaultThemeMode} / {@link changeTheme} and on OS theme changes while following.
|
|
777
|
+
*/
|
|
778
|
+
readonly themeSubject: BehaviorSubject<KitThemeMode>;
|
|
779
|
+
/**
|
|
780
|
+
* Apply the persisted theme, or start following the OS setting when nothing is stored yet.
|
|
781
|
+
*
|
|
782
|
+
* @remarks
|
|
783
|
+
* Call once on boot (e.g. from `app.component`).
|
|
784
|
+
*
|
|
785
|
+
* @returns a Promise that resolves once the initial theme has been applied
|
|
786
|
+
*/
|
|
787
|
+
setDefaultThemeMode(): Promise<void>;
|
|
788
|
+
/**
|
|
789
|
+
* Force a theme, persist it, and stop following the OS setting.
|
|
790
|
+
*
|
|
791
|
+
* @param isDark - `true` for the dark theme, `false` for light
|
|
792
|
+
* @returns a Promise that resolves once the theme has been persisted and applied
|
|
793
|
+
*/
|
|
794
|
+
changeTheme(isDark: boolean): Promise<void>;
|
|
795
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<KitThemeController, never>;
|
|
796
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<KitThemeController>;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Options for {@link kitRequestReview}.
|
|
801
|
+
*/
|
|
802
|
+
interface KitRequestReviewOptions {
|
|
803
|
+
/**
|
|
804
|
+
* Key under which the timestamp of the last review request is stored (via `@capacitor/preferences`).
|
|
805
|
+
*
|
|
806
|
+
* @remarks
|
|
807
|
+
* Supplied by the caller so the kit ships no storage keys of its own; each app passes its own enum
|
|
808
|
+
* value.
|
|
809
|
+
*/
|
|
810
|
+
readonly storageKey: string;
|
|
811
|
+
/**
|
|
812
|
+
* Minimum number of months between review prompts.
|
|
813
|
+
*
|
|
814
|
+
* @remarks
|
|
815
|
+
* A prompt is only shown when this much time has elapsed since the last one (or when there is no
|
|
816
|
+
* record yet), so the OS review dialog is never nagged repeatedly.
|
|
817
|
+
*/
|
|
818
|
+
readonly throttleMonths: number;
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Request the native in-app review dialog, throttled so the user is prompted at most once per window.
|
|
822
|
+
*
|
|
823
|
+
* @remarks
|
|
824
|
+
* A plain function — no DI needed (`@capacitor/preferences`, `@capacitor-community/in-app-review` and
|
|
825
|
+
* `Capacitor` are all static), so the caller invokes it directly and passes its own config rather
|
|
826
|
+
* than injecting a controller. A no-op on non-native platforms. When enough time has elapsed since
|
|
827
|
+
* the last prompt (per {@link KitRequestReviewOptions.throttleMonths}, tracked under
|
|
828
|
+
* {@link KitRequestReviewOptions.storageKey}), it briefly waits for the app to settle, calls
|
|
829
|
+
* `InAppReview.requestReview()`, and records the new timestamp. The wait/throttle/record sequence
|
|
830
|
+
* was previously copy-pasted verbatim across the fleet; centralizing it means a single place to tune
|
|
831
|
+
* the prompt cadence.
|
|
832
|
+
*
|
|
833
|
+
* @param options - the storage key and throttle window; see {@link KitRequestReviewOptions}
|
|
834
|
+
* @returns a Promise that resolves once the request has been made (or immediately if throttled / on web)
|
|
835
|
+
* @example
|
|
836
|
+
* ```ts
|
|
837
|
+
* await kitRequestReview({ storageKey: StorageEnum.lastRequestRate, throttleMonths: 3 });
|
|
838
|
+
* ```
|
|
839
|
+
*/
|
|
840
|
+
declare const kitRequestReview: (options: KitRequestReviewOptions) => Promise<void>;
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Rotate a base64 image 90°, returning a new base64 data URL of the same MIME type.
|
|
844
|
+
*
|
|
845
|
+
* @remarks
|
|
846
|
+
* Pure DOM/canvas work — no DI. Used before sending a label to the printer when the artwork must be
|
|
847
|
+
* turned to match the tape orientation. Extracted verbatim from the fleet's printer services so the
|
|
848
|
+
* canvas handling lives in one place.
|
|
849
|
+
*
|
|
850
|
+
* @param imageData - a base64 data URL (e.g. `data:image/png;base64,...`)
|
|
851
|
+
* @returns a Promise resolving to the rotated image as a base64 data URL
|
|
852
|
+
*/
|
|
853
|
+
declare const kitRotationImage: (imageData: string) => Promise<string>;
|
|
854
|
+
/** Options for {@link kitDomToPng}. */
|
|
855
|
+
interface KitDomToPngOptions {
|
|
856
|
+
/** When `true`, the rendered PNG is rotated 90° via {@link kitRotationImage}. Defaults to `false`. */
|
|
857
|
+
readonly rotate?: boolean;
|
|
858
|
+
/** Rendering scale passed to `dom-to-image-more`. Defaults to `3` (the fleet's print resolution). */
|
|
859
|
+
readonly scale?: number;
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Render a DOM element to a base64 PNG for label printing, with the fleet's device-specific fixes.
|
|
863
|
+
*
|
|
864
|
+
* @remarks
|
|
865
|
+
* Pure function — no DI (reads the platform from `Capacitor`, uses the global `document`), so the
|
|
866
|
+
* caller presents its own loading UI around it. Centralizes the hard-won device quirks: on iOS it
|
|
867
|
+
* pads width/height by 2px (otherwise the bottom is clipped), on Android it does not (the padding
|
|
868
|
+
* introduces a black line). Retries the `dom-to-image-more` render up to 10 times because the first
|
|
869
|
+
* pass can occasionally return empty. This is exactly the kind of plumbing where a future fix should
|
|
870
|
+
* land in every app at once.
|
|
871
|
+
*
|
|
872
|
+
* @param element - the element to rasterize (e.g. the label preview host)
|
|
873
|
+
* @param options - rendering options; see {@link KitDomToPngOptions}
|
|
874
|
+
* @returns a Promise resolving to the PNG as a base64 data URL (empty string if every attempt failed)
|
|
875
|
+
* @example
|
|
876
|
+
* ```ts
|
|
877
|
+
* const loading = await this.#loadingCtrl.create({ message: this.text.generating });
|
|
878
|
+
* await loading.present();
|
|
879
|
+
* const png = await kitDomToPng(this.preview().nativeElement, { rotate: true });
|
|
880
|
+
* await loading.dismiss();
|
|
881
|
+
* ```
|
|
882
|
+
*/
|
|
883
|
+
declare const kitDomToPng: (element: HTMLElement, options?: KitDomToPngOptions) => Promise<string>;
|
|
884
|
+
/** Parameters for {@link kitBuildBrotherPrintSettings}. */
|
|
885
|
+
interface KitBrotherPrintSettingsParams {
|
|
886
|
+
/** The target printer model. */
|
|
887
|
+
readonly modelName: BRLMPrinterModelName;
|
|
888
|
+
/** The label artwork as a base64 data URL (the `data:...,` prefix is stripped internally). */
|
|
889
|
+
readonly printBase64: string;
|
|
890
|
+
/** The selected label/paper (its `W<width>H<height>` code drives the tape dimensions). */
|
|
891
|
+
readonly label: BRLMPrinterLabelName;
|
|
892
|
+
/** Number of copies to print. Passed by the caller (apps differ: some use the print option, some fix 1). */
|
|
893
|
+
readonly numberOfCopies: number;
|
|
894
|
+
/** Halftone threshold for the print. */
|
|
895
|
+
readonly halftoneThreshold: number;
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Assemble the Brother `BRLMPrintOptions` for a die-cut label print, minus the transport fields.
|
|
899
|
+
*
|
|
900
|
+
* @remarks
|
|
901
|
+
* Pure function — no DI. Centralizes the fleet's canonical print settings (fit-page scale, centered,
|
|
902
|
+
* best quality, threshold halftone, 2mm/1mm margins, `gapLength` 2.0) and the tape sizing derived
|
|
903
|
+
* from the label's `W<width>H<height>` code. The caller merges the printer's `port` / `channelInfo`
|
|
904
|
+
* onto the result before calling `BrotherPrint.printImage()`, so channel selection and loading UI stay
|
|
905
|
+
* in the app.
|
|
906
|
+
*
|
|
907
|
+
* @param params - model, artwork, label, copies, and halftone threshold; see {@link KitBrotherPrintSettingsParams}
|
|
908
|
+
* @returns the `BRLMPrintOptions` ready to be spread with `{ port, channelInfo }`
|
|
909
|
+
* @example
|
|
910
|
+
* ```ts
|
|
911
|
+
* const settings = kitBuildBrotherPrintSettings({
|
|
912
|
+
* modelName, printBase64, label, numberOfCopies: printOptions.printNum, halftoneThreshold: printOptions.halftoneThreshold,
|
|
913
|
+
* });
|
|
914
|
+
* await BrotherPrint.printImage({ ...settings, port: channel.port, channelInfo: channel.channelInfo });
|
|
915
|
+
* ```
|
|
916
|
+
*/
|
|
917
|
+
declare const kitBuildBrotherPrintSettings: (params: KitBrotherPrintSettingsParams) => BRLMPrintOptions;
|
|
918
|
+
|
|
488
919
|
/**
|
|
489
920
|
* Discriminated set of authentication states the guards react to.
|
|
490
921
|
*
|
|
@@ -996,5 +1427,45 @@ declare const objectEqual: (a: object, b: object) => boolean;
|
|
|
996
1427
|
*/
|
|
997
1428
|
declare const disableHandler: (event: Event, work: Promise<void | boolean>) => Promise<void>;
|
|
998
1429
|
|
|
999
|
-
|
|
1000
|
-
|
|
1430
|
+
/**
|
|
1431
|
+
* Toggle the `disabled` flag of a signal-held `ion-infinite-scroll` / `ion-refresher` element.
|
|
1432
|
+
*
|
|
1433
|
+
* @remarks
|
|
1434
|
+
* A tiny pure helper for the common pattern of stashing the completing scroll/refresher element in a
|
|
1435
|
+
* signal (e.g. captured from the event) and later enabling/disabling it — for instance disabling
|
|
1436
|
+
* infinite scroll once the last page has loaded. A no-op when the signal holds no element.
|
|
1437
|
+
*
|
|
1438
|
+
* @param completeEvent - a writable signal holding the infinite-scroll / refresher element (or nullish)
|
|
1439
|
+
* @param disabled - the value to set on the element's `disabled` property
|
|
1440
|
+
* @example
|
|
1441
|
+
* ```ts
|
|
1442
|
+
* const infinite = signal<HTMLIonInfiniteScrollElement | null>(null);
|
|
1443
|
+
* // ...on ionInfinite: infinite.set(ev.target); ...when no more pages:
|
|
1444
|
+
* kitChangeEventDisabled(infinite, true);
|
|
1445
|
+
* ```
|
|
1446
|
+
*/
|
|
1447
|
+
declare const kitChangeEventDisabled: (completeEvent: WritableSignal<HTMLIonInfiniteScrollElement | HTMLIonRefresherElement | null | undefined>, disabled: boolean) => void;
|
|
1448
|
+
|
|
1449
|
+
/**
|
|
1450
|
+
* Observe an Ionic page's "is currently entered" state from its lifecycle DOM events.
|
|
1451
|
+
*
|
|
1452
|
+
* @remarks
|
|
1453
|
+
* Emits `true` on `ionViewDidEnter` and `false` on `ionViewWillEnter` / `ionViewWillLeave`, seeded
|
|
1454
|
+
* with `false` via `startWith`. Useful to pause/resume work (timers, video, expensive rendering)
|
|
1455
|
+
* while a page is off-screen in Ionic's stack navigation, without wiring the four lifecycle hooks by
|
|
1456
|
+
* hand. The listeners are removed when the Observable is unsubscribed.
|
|
1457
|
+
*
|
|
1458
|
+
* @param el - an `ElementRef` for the page host element (the `ion-page`)
|
|
1459
|
+
* @returns an Observable that emits whether the page is currently entered
|
|
1460
|
+
* @example
|
|
1461
|
+
* ```ts
|
|
1462
|
+
* export class FeedPage {
|
|
1463
|
+
* readonly #host = inject(ElementRef);
|
|
1464
|
+
* readonly isEntered = toSignal(kitCreateDidEnter(this.#host), { initialValue: false });
|
|
1465
|
+
* }
|
|
1466
|
+
* ```
|
|
1467
|
+
*/
|
|
1468
|
+
declare const kitCreateDidEnter: (el: ElementRef) => Observable<boolean>;
|
|
1469
|
+
|
|
1470
|
+
export { KIT_AUTH_CONFIG, KIT_HTTP_CONFIG, KIT_OVERLAY_CONFIG, KIT_THEME_CONFIG, KitAutofillDirective, KitLoadingController, KitOverlayController, KitReloadAlertController, KitStorageService, KitThemeController, arrayConcatById, disableHandler, kitAuthInterceptor, kitBuildBrotherPrintSettings, kitChangeEventDisabled, kitCreateDidEnter, kitDomToPng, kitImpact, kitKeyboardInit, kitPresentAuthFailedAlert, kitPresentLanguageActionSheet, kitRequestReview, kitRequireAuthorizedGuard, kitRequireConfirmingGuard, kitRequiredUnauthorizedGuard, kitRotationImage, objectEqual, provideKitAuth, provideKitHttp, provideKitOverlay, provideKitTheme };
|
|
1471
|
+
export type { KitAlertCloseOptions, KitAlertConfirmOptions, KitAuthConfig, KitAuthFailedAlertOptions, KitAuthRedirects, KitAuthState, KitBrotherPrintSettingsParams, KitDomToPngOptions, KitHttpConfig, KitKeyboardAdjust, KitLabels, KitLanguageActionSheetOptions, KitLanguageOption, KitModalPresentOptions, KitOverlayConfig, KitReloadAlertOptions, KitRequestReviewOptions, KitThemeConfig, KitThemeMode, ModalMetadata };
|