@rdlabo/ionic-angular-kit 0.0.13 → 0.0.15

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": "@rdlabo/ionic-angular-kit",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.0.0",
6
6
  "@angular/core": "^21.0.0",
@@ -18,6 +18,23 @@
18
18
  "dom-to-image-more": "^3.0.0",
19
19
  "rxjs": "^7.8.0"
20
20
  },
21
+ "peerDependenciesMeta": {
22
+ "@capacitor/preferences": {
23
+ "optional": true
24
+ },
25
+ "@capacitor/status-bar": {
26
+ "optional": true
27
+ },
28
+ "@capacitor-community/in-app-review": {
29
+ "optional": true
30
+ },
31
+ "@rdlabo/capacitor-brotherprint": {
32
+ "optional": true
33
+ },
34
+ "dom-to-image-more": {
35
+ "optional": true
36
+ }
37
+ },
21
38
  "dependencies": {
22
39
  "tslib": "^2.3.0"
23
40
  },
@@ -31,6 +48,18 @@
31
48
  ".": {
32
49
  "types": "./types/rdlabo-ionic-angular-kit.d.ts",
33
50
  "default": "./fesm2022/rdlabo-ionic-angular-kit.mjs"
51
+ },
52
+ "./printer": {
53
+ "types": "./types/rdlabo-ionic-angular-kit-printer.d.ts",
54
+ "default": "./fesm2022/rdlabo-ionic-angular-kit-printer.mjs"
55
+ },
56
+ "./review": {
57
+ "types": "./types/rdlabo-ionic-angular-kit-review.d.ts",
58
+ "default": "./fesm2022/rdlabo-ionic-angular-kit-review.mjs"
59
+ },
60
+ "./theme": {
61
+ "types": "./types/rdlabo-ionic-angular-kit-theme.d.ts",
62
+ "default": "./fesm2022/rdlabo-ionic-angular-kit-theme.mjs"
34
63
  }
35
64
  },
36
65
  "type": "module"
@@ -0,0 +1,81 @@
1
+ import { BRLMPrinterModelName, BRLMPrinterLabelName, BRLMPrintOptions } from '@rdlabo/capacitor-brotherprint';
2
+
3
+ /**
4
+ * Rotate a base64 image 90°, returning a new base64 data URL of the same MIME type.
5
+ *
6
+ * @remarks
7
+ * Pure DOM/canvas work — no DI. Used before sending a label to the printer when the artwork must be
8
+ * turned to match the tape orientation. Extracted verbatim from the fleet's printer services so the
9
+ * canvas handling lives in one place.
10
+ *
11
+ * @param imageData - a base64 data URL (e.g. `data:image/png;base64,...`)
12
+ * @returns a Promise resolving to the rotated image as a base64 data URL
13
+ */
14
+ declare const kitRotationImage: (imageData: string) => Promise<string>;
15
+ /** Options for {@link kitDomToPng}. */
16
+ interface KitDomToPngOptions {
17
+ /** When `true`, the rendered PNG is rotated 90° via {@link kitRotationImage}. Defaults to `false`. */
18
+ readonly rotate?: boolean;
19
+ /** Rendering scale passed to `dom-to-image-more`. Defaults to `3` (the fleet's print resolution). */
20
+ readonly scale?: number;
21
+ }
22
+ /**
23
+ * Render a DOM element to a base64 PNG for label printing, with the fleet's device-specific fixes.
24
+ *
25
+ * @remarks
26
+ * Pure function — no DI (reads the platform from `Capacitor`, uses the global `document`), so the
27
+ * caller presents its own loading UI around it. Centralizes the hard-won device quirks: on iOS it
28
+ * pads width/height by 2px (otherwise the bottom is clipped), on Android it does not (the padding
29
+ * introduces a black line). Retries the `dom-to-image-more` render up to 10 times because the first
30
+ * pass can occasionally return empty. This is exactly the kind of plumbing where a future fix should
31
+ * land in every app at once.
32
+ *
33
+ * @param element - the element to rasterize (e.g. the label preview host)
34
+ * @param options - rendering options; see {@link KitDomToPngOptions}
35
+ * @returns a Promise resolving to the PNG as a base64 data URL (empty string if every attempt failed)
36
+ * @example
37
+ * ```ts
38
+ * const loading = await this.#loadingCtrl.create({ message: this.text.generating });
39
+ * await loading.present();
40
+ * const png = await kitDomToPng(this.preview().nativeElement, { rotate: true });
41
+ * await loading.dismiss();
42
+ * ```
43
+ */
44
+ declare const kitDomToPng: (element: HTMLElement, options?: KitDomToPngOptions) => Promise<string>;
45
+ /** Parameters for {@link kitBuildBrotherPrintSettings}. */
46
+ interface KitBrotherPrintSettingsParams {
47
+ /** The target printer model. */
48
+ readonly modelName: BRLMPrinterModelName;
49
+ /** The label artwork as a base64 data URL (the `data:...,` prefix is stripped internally). */
50
+ readonly printBase64: string;
51
+ /** The selected label/paper (its `W<width>H<height>` code drives the tape dimensions). */
52
+ readonly label: BRLMPrinterLabelName;
53
+ /** Number of copies to print. Passed by the caller (apps differ: some use the print option, some fix 1). */
54
+ readonly numberOfCopies: number;
55
+ /** Halftone threshold for the print. */
56
+ readonly halftoneThreshold: number;
57
+ }
58
+ /**
59
+ * Assemble the Brother `BRLMPrintOptions` for a die-cut label print, minus the transport fields.
60
+ *
61
+ * @remarks
62
+ * Pure function — no DI. Centralizes the fleet's canonical print settings (fit-page scale, centered,
63
+ * best quality, threshold halftone, 2mm/1mm margins, `gapLength` 2.0) and the tape sizing derived
64
+ * from the label's `W<width>H<height>` code. The caller merges the printer's `port` / `channelInfo`
65
+ * onto the result before calling `BrotherPrint.printImage()`, so channel selection and loading UI stay
66
+ * in the app.
67
+ *
68
+ * @param params - model, artwork, label, copies, and halftone threshold; see {@link KitBrotherPrintSettingsParams}
69
+ * @returns the `BRLMPrintOptions` ready to be spread with `{ port, channelInfo }`
70
+ * @example
71
+ * ```ts
72
+ * const settings = kitBuildBrotherPrintSettings({
73
+ * modelName, printBase64, label, numberOfCopies: printOptions.printNum, halftoneThreshold: printOptions.halftoneThreshold,
74
+ * });
75
+ * await BrotherPrint.printImage({ ...settings, port: channel.port, channelInfo: channel.channelInfo });
76
+ * ```
77
+ */
78
+ declare const kitBuildBrotherPrintSettings: (params: KitBrotherPrintSettingsParams) => BRLMPrintOptions;
79
+
80
+ export { kitBuildBrotherPrintSettings, kitDomToPng, kitRotationImage };
81
+ export type { KitBrotherPrintSettingsParams, KitDomToPngOptions };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Options for {@link kitRequestReview}.
3
+ */
4
+ interface KitRequestReviewOptions {
5
+ /**
6
+ * Key under which the timestamp of the last review request is stored (via `@capacitor/preferences`).
7
+ *
8
+ * @remarks
9
+ * Supplied by the caller so the kit ships no storage keys of its own; each app passes its own enum
10
+ * value.
11
+ */
12
+ readonly storageKey: string;
13
+ /**
14
+ * Minimum number of months between review prompts.
15
+ *
16
+ * @remarks
17
+ * A prompt is only shown when this much time has elapsed since the last one (or when there is no
18
+ * record yet), so the OS review dialog is never nagged repeatedly.
19
+ */
20
+ readonly throttleMonths: number;
21
+ }
22
+ /**
23
+ * Request the native in-app review dialog, throttled so the user is prompted at most once per window.
24
+ *
25
+ * @remarks
26
+ * A plain function — no DI needed (`@capacitor/preferences`, `@capacitor-community/in-app-review` and
27
+ * `Capacitor` are all static), so the caller invokes it directly and passes its own config rather
28
+ * than injecting a controller. A no-op on non-native platforms. When enough time has elapsed since
29
+ * the last prompt (per {@link KitRequestReviewOptions.throttleMonths}, tracked under
30
+ * {@link KitRequestReviewOptions.storageKey}), it briefly waits for the app to settle, calls
31
+ * `InAppReview.requestReview()`, and records the new timestamp. The wait/throttle/record sequence
32
+ * was previously copy-pasted verbatim across the fleet; centralizing it means a single place to tune
33
+ * the prompt cadence.
34
+ *
35
+ * @param options - the storage key and throttle window; see {@link KitRequestReviewOptions}
36
+ * @returns a Promise that resolves once the request has been made (or immediately if throttled / on web)
37
+ * @example
38
+ * ```ts
39
+ * await kitRequestReview({ storageKey: StorageEnum.lastRequestRate, throttleMonths: 3 });
40
+ * ```
41
+ */
42
+ declare const kitRequestReview: (options: KitRequestReviewOptions) => Promise<void>;
43
+
44
+ export { kitRequestReview };
45
+ export type { KitRequestReviewOptions };
@@ -0,0 +1,116 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, EnvironmentProviders } from '@angular/core';
3
+ import { BehaviorSubject } from 'rxjs';
4
+
5
+ /**
6
+ * Theme configuration injected via `provideKitTheme()` and consumed by `KitThemeController`.
7
+ *
8
+ * @remarks
9
+ * All fields are required; the consuming application supplies a complete configuration so every app
10
+ * in the fleet has the same shape. The class lists absorb the per-app CSS drift: the kit toggles
11
+ * `darkClasses` on when dark and `lightClasses` on when light, so an app that only uses Ionic's
12
+ * palette passes `darkClasses: ['ion-palette-dark'], lightClasses: []`, while an app with an extra
13
+ * design-system palette adds its own classes (e.g. `darkClasses: ['ion-palette-dark', 'a2ui-dark']`,
14
+ * `lightClasses: ['a2ui-light']`).
15
+ */
16
+ interface KitThemeConfig {
17
+ /** Key under which the chosen theme (`'light'` | `'dark'`) is persisted via `KitStorageService`. */
18
+ readonly storageKey: string;
19
+ /** Classes toggled **on** the document element when the dark theme is active. */
20
+ readonly darkClasses: readonly string[];
21
+ /** Classes toggled **on** the document element when the light theme is active. */
22
+ readonly lightClasses: readonly string[];
23
+ }
24
+ /**
25
+ * Injection token carrying the {@link KitThemeConfig} for `KitThemeController`.
26
+ *
27
+ * @remarks
28
+ * Provide it through {@link provideKitTheme} rather than registering it directly.
29
+ */
30
+ declare const KIT_THEME_CONFIG: InjectionToken<KitThemeConfig>;
31
+ /**
32
+ * Wire `KitThemeController` into the application.
33
+ *
34
+ * @param config - theme configuration: the storage key and the light/dark class lists
35
+ * @returns environment providers to add to the application's provider list
36
+ * @example
37
+ * ```ts
38
+ * bootstrapApplication(AppComponent, {
39
+ * providers: [
40
+ * provideKitTheme({
41
+ * storageKey: StorageKeyEnum.theme,
42
+ * darkClasses: ['ion-palette-dark', 'a2ui-dark'],
43
+ * lightClasses: ['a2ui-light'],
44
+ * }),
45
+ * ],
46
+ * });
47
+ * ```
48
+ */
49
+ declare const provideKitTheme: (config: KitThemeConfig) => EnvironmentProviders;
50
+
51
+ /** The active theme mode. */
52
+ type KitThemeMode = 'light' | 'dark';
53
+ /**
54
+ * Light/dark theme controller: persists the user's choice, follows the OS setting until the user
55
+ * overrides it, toggles the configured palette classes, and syncs the native Android status bar.
56
+ *
57
+ * @remarks
58
+ * Consolidates the theme logic that had drifted across the fleet into one behavior. Notably it fixes
59
+ * a latent leak in one variant where the system-theme listener stayed registered after a manual
60
+ * toggle: {@link changeTheme} always detaches the listener via {@link removeEventListener} before
61
+ * applying the forced theme, so a later OS change can no longer silently flip an app the user pinned.
62
+ *
63
+ * - **Persistence** — the chosen mode is stored via {@link KitStorageService} under the configured key.
64
+ * - **Follow OS until overridden** — on boot with nothing stored, it tracks
65
+ * `prefers-color-scheme` (idempotent registration); once the user calls {@link changeTheme} it stops
66
+ * following and honors the explicit choice.
67
+ * - **Class toggling** — toggles {@link KitThemeConfig.darkClasses} on when dark and
68
+ * {@link KitThemeConfig.lightClasses} on when light, absorbing per-app CSS differences via config.
69
+ * - **Native status bar** — on Android native only, mirrors the Ionic behavior of setting the status
70
+ * bar style to match (iOS derives it from the web content, so it is intentionally left untouched).
71
+ *
72
+ * Subscribe to {@link themeSubject} to reflect the current mode in the UI (e.g. a settings toggle).
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * // On boot (app.component):
77
+ * inject(KitThemeController).setDefaultThemeMode();
78
+ *
79
+ * // From a settings toggle:
80
+ * const theme = inject(KitThemeController);
81
+ * theme.themeSubject.subscribe((mode) => this.isDark.set(mode === 'dark'));
82
+ * theme.changeTheme(true);
83
+ * ```
84
+ */
85
+ declare class KitThemeController {
86
+ #private;
87
+ /**
88
+ * Emits the active theme, seeded with `'light'`.
89
+ *
90
+ * @remarks
91
+ * A `BehaviorSubject`, so a late subscriber immediately receives the current mode; it emits again
92
+ * on every {@link setDefaultThemeMode} / {@link changeTheme} and on OS theme changes while following.
93
+ */
94
+ readonly themeSubject: BehaviorSubject<KitThemeMode>;
95
+ /**
96
+ * Apply the persisted theme, or start following the OS setting when nothing is stored yet.
97
+ *
98
+ * @remarks
99
+ * Call once on boot (e.g. from `app.component`).
100
+ *
101
+ * @returns a Promise that resolves once the initial theme has been applied
102
+ */
103
+ setDefaultThemeMode(): Promise<void>;
104
+ /**
105
+ * Force a theme, persist it, and stop following the OS setting.
106
+ *
107
+ * @param isDark - `true` for the dark theme, `false` for light
108
+ * @returns a Promise that resolves once the theme has been persisted and applied
109
+ */
110
+ changeTheme(isDark: boolean): Promise<void>;
111
+ static ɵfac: i0.ɵɵFactoryDeclaration<KitThemeController, never>;
112
+ static ɵprov: i0.ɵɵInjectableDeclaration<KitThemeController>;
113
+ }
114
+
115
+ export { KIT_THEME_CONFIG, KitThemeController, provideKitTheme };
116
+ export type { KitThemeConfig, KitThemeMode };