@sigx/lynx-appearance 0.4.1

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/src/setters.ts ADDED
@@ -0,0 +1,87 @@
1
+ import { callAsync, isModuleAvailable } from '@sigx/lynx-core';
2
+ import type { SetterResult, SystemBarStyle, SystemBarsStyleInput } from './types.js';
3
+
4
+ const MODULE = 'Appearance';
5
+
6
+ const UNSUPPORTED: SetterResult = { ok: false, reason: 'unsupported' };
7
+
8
+ /**
9
+ * Set the status-bar *content* tint (clock + icons).
10
+ *
11
+ * - `'light'` = light content (white-ish icons) — use when behind a dark theme.
12
+ * - `'dark'` = dark content — use when behind a light theme.
13
+ *
14
+ * On iOS the host VC must forward `preferredStatusBarStyle` to
15
+ * `AppearanceModule.preferredStatusBarStyle` for this to take effect — the
16
+ * lynx-cli iOS template wires that automatically.
17
+ *
18
+ * Resolves `{ ok: false, reason: 'unsupported' }` (never rejects) when the
19
+ * native module isn't registered — typical in web preview, SSR, tests, or
20
+ * apps that don't link the module. Fire-and-forget callers can therefore
21
+ * `void setStatusBarStyle(...)` without risking unhandled rejections.
22
+ */
23
+ export function setStatusBarStyle(style: SystemBarStyle): Promise<SetterResult> {
24
+ if (!isAvailable()) return Promise.resolve(UNSUPPORTED);
25
+ return callAsync<SetterResult>(MODULE, 'setStatusBarStyle', { style });
26
+ }
27
+
28
+ /**
29
+ * Android only — set the status-bar background color. Pass `null` (or
30
+ * omit / pass `'transparent'`) to clear. iOS resolves `{ ok: false,
31
+ * reason: 'unsupported' }` since iOS has no separate status-bar background.
32
+ *
33
+ * On Android 15+ (API 35) edge-to-edge is enforced and this call is a no-op
34
+ * at the system level — callers should overlay their own background view
35
+ * inside the safe-area top padding.
36
+ *
37
+ * Resolves `{ ok: false, reason: 'unsupported' }` (never rejects) when the
38
+ * native module isn't registered. See `setStatusBarStyle` for the rationale.
39
+ */
40
+ export function setStatusBarBackgroundColor(color: string | null): Promise<SetterResult> {
41
+ if (!isAvailable()) return Promise.resolve(UNSUPPORTED);
42
+ return callAsync<SetterResult>(MODULE, 'setStatusBarBackgroundColor', { color });
43
+ }
44
+
45
+ /**
46
+ * Android only — set the navigation-bar content tint + optional background.
47
+ * iOS resolves `{ ok: false, reason: 'unsupported' }` since there's no
48
+ * separate navigation bar.
49
+ *
50
+ * Resolves `{ ok: false, reason: 'unsupported' }` (never rejects) when the
51
+ * native module isn't registered. See `setStatusBarStyle` for the rationale.
52
+ */
53
+ export function setNavigationBarStyle(opts: { style: SystemBarStyle; color?: string }): Promise<SetterResult> {
54
+ if (!isAvailable()) return Promise.resolve(UNSUPPORTED);
55
+ return callAsync<SetterResult>(MODULE, 'setNavigationBarStyle', opts);
56
+ }
57
+
58
+ /**
59
+ * Convenience: apply status-bar tint + (optionally) status-bar background +
60
+ * nav-bar tint in one call. Resolves to the aggregate result — `ok: false`
61
+ * if any leg returned a non-`unsupported` failure, with the first such
62
+ * failure's reason. `unsupported` legs (e.g. status-bar background on iOS)
63
+ * are intentionally ignored so a partially-supported platform can still
64
+ * report success for the legs that do apply.
65
+ *
66
+ * Fields are optional; omitting any leaves that surface untouched. Order is
67
+ * deterministic (statusBar → statusBarBackground → navigationBar) so the
68
+ * resolved reason on partial failure is unambiguous.
69
+ */
70
+ export async function setSystemBarsStyle(opts: SystemBarsStyleInput): Promise<SetterResult> {
71
+ if (!isAvailable()) return UNSUPPORTED;
72
+ let firstFailure: SetterResult | undefined;
73
+ const record = (r: SetterResult): void => {
74
+ if (!r.ok && !firstFailure && r.reason !== 'unsupported') firstFailure = r;
75
+ };
76
+ if (opts.statusBar) record(await setStatusBarStyle(opts.statusBar));
77
+ if (opts.statusBarBackground !== undefined) {
78
+ record(await setStatusBarBackgroundColor(opts.statusBarBackground));
79
+ }
80
+ if (opts.navigationBar) record(await setNavigationBarStyle(opts.navigationBar));
81
+ return firstFailure ?? { ok: true };
82
+ }
83
+
84
+ /** Quick check whether the native Appearance module is registered. */
85
+ export function isAvailable(): boolean {
86
+ return isModuleAvailable(MODULE);
87
+ }
package/src/types.ts ADDED
@@ -0,0 +1,25 @@
1
+ /** The two color schemes the platform reports. iOS `unspecified` and
2
+ * Android `UI_MODE_NIGHT_UNDEFINED` both collapse to `'light'` at the
3
+ * native publisher boundary so JS only ever sees these two values. */
4
+ export type ColorScheme = 'light' | 'dark';
5
+
6
+ /** Tint of system-bar *content* (clock, icons), not its background. */
7
+ export type SystemBarStyle = 'light' | 'dark';
8
+
9
+ /** Result envelope returned by every native setter. */
10
+ export interface SetterResult {
11
+ ok: boolean;
12
+ /** Present when `ok === false` — `'unsupported'` on iOS for nav-bar and
13
+ * status-bar-background calls, or an Android failure message. */
14
+ reason?: string;
15
+ }
16
+
17
+ /** Argument to `setSystemBarsStyle` — partial; omitted fields are left alone. */
18
+ export interface SystemBarsStyleInput {
19
+ /** Status-bar content tint. `'light'` = light icons (legible on dark bg). */
20
+ statusBar?: SystemBarStyle;
21
+ /** Android only — status-bar background color. `null` clears (transparent). */
22
+ statusBarBackground?: string | null;
23
+ /** Android only — navigation-bar tint + optional background. */
24
+ navigationBar?: { style: SystemBarStyle; color?: string };
25
+ }