use-scroll-animate 4.6.0 → 4.7.0

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 (38) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/components/angular.cjs +1 -0
  3. package/dist/components/angular.cjs.map +1 -1
  4. package/dist/components/angular.js +1 -0
  5. package/dist/components/angular.js.map +1 -1
  6. package/dist/components/bridge.cjs +154 -0
  7. package/dist/components/bridge.cjs.map +1 -0
  8. package/dist/components/bridge.d.cts +63 -0
  9. package/dist/components/bridge.d.ts +63 -0
  10. package/dist/components/bridge.js +147 -0
  11. package/dist/components/bridge.js.map +1 -0
  12. package/dist/components/lite.cjs +149 -0
  13. package/dist/components/lite.cjs.map +1 -1
  14. package/dist/components/lite.js +144 -1
  15. package/dist/components/lite.js.map +1 -1
  16. package/dist/components/solid.cjs +1 -0
  17. package/dist/components/solid.cjs.map +1 -1
  18. package/dist/components/solid.js +1 -0
  19. package/dist/components/solid.js.map +1 -1
  20. package/dist/components/svelte.cjs +1 -0
  21. package/dist/components/svelte.cjs.map +1 -1
  22. package/dist/components/svelte.js +1 -0
  23. package/dist/components/svelte.js.map +1 -1
  24. package/dist/components/vue.cjs +1 -0
  25. package/dist/components/vue.cjs.map +1 -1
  26. package/dist/components/vue.js +1 -0
  27. package/dist/components/vue.js.map +1 -1
  28. package/dist/components.cjs +7 -0
  29. package/dist/components.cjs.map +1 -1
  30. package/dist/components.d.cts +61 -2
  31. package/dist/components.d.ts +61 -2
  32. package/dist/components.js +1 -0
  33. package/dist/components.js.map +1 -1
  34. package/dist/components.umd.js +3 -2
  35. package/dist/components.umd.js.map +1 -1
  36. package/docs/ROADMAP.md +1 -1
  37. package/docs/hybrid-apps.md +15 -0
  38. package/package.json +11 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [4.7.0] - 2026-10-08
11
+
12
+ ### Added
13
+ - **Native shell bridges** — new entry `use-scroll-animate/components/bridge` (also on `UsaComponents` in the UMD build): `connectNativeShell()` syncs the host app's **reduce motion**, **light / dark / high-contrast theme** and **accent color** (and optional motion-sensitivity level) into every `<usa-*>` component. JSON protocol `usa:ready` / `usa:request-settings` / `usa:settings` over WebView2 web messages, `window.postMessage` or `window.usaNative.apply()`; incoming values validated. Helpers `detectNativeHost()`, `postToNative()`, `parseNativeSettings()`, `applyNativeSettings()`; event `usa:native-settings`.
14
+ - **Official samples** in [examples/native](./examples/native/): **WinUI 3** (`UISettings.AnimationsEnabled`, accent, high contrast → `PostWebMessageAsJson`), **.NET MAUI** (Android animator scale, iOS Reduce Motion, Windows `UISettings`, `RequestedThemeChanged` → `EvaluateJavaScriptAsync`), **Flutter** (`MediaQuery.disableAnimations`, brightness, high contrast via a `UsaBridge` JavaScriptChannel), sharing one web page.
15
+ - Showcase: **connectNativeShell()** card (Page & app-wide) — simulate host messages on a demo tile.
16
+ - Docs: "Native shell bridge" in [docs/hybrid-apps.md](./docs/hybrid-apps.md).
17
+
10
18
  ## [4.6.0] - 2026-10-08
11
19
 
12
20
  ### Added
@@ -29,6 +29,7 @@ require('./packs.cjs');
29
29
  require('./a11y.cjs');
30
30
  require('../chunks/index-tags-BQh_uGqH.cjs');
31
31
  require('./perf.cjs');
32
+ require('./bridge.cjs');
32
33
 
33
34
  /**
34
35
  * use-scroll-animate/components/angular — Angular integration (v3.8).
@@ -1 +1 @@
1
- {"version":3,"file":"angular.cjs","sources":["../../src/components/frameworks/angular.ts"],"sourcesContent":["/**\n * use-scroll-animate/components/angular — Angular integration (v3.8).\n * Angular renders `<usa-*>` tags once the component (or NgModule) allows\n * custom elements with `CUSTOM_ELEMENTS_SCHEMA`; property binding\n * `[checked]=\"on\"` and event binding `(usa:change)=\"…\"` then work as is.\n * This entry is framework-free (no `@angular/*` import):\n *\n * ```ts\n * import { CUSTOM_ELEMENTS_SCHEMA, Component, APP_INITIALIZER } from '@angular/core';\n * import { usaInitializer } from 'use-scroll-animate/components/angular';\n *\n * // app.config.ts\n * providers: [{ provide: APP_INITIALIZER, multi: true, useFactory: usaInitializer(['click', 'ui']) }]\n *\n * @Component({ standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA],\n * template: `<usa-toggle [checked]=\"on\" (usa:change)=\"on = $any($event).detail.checked\"></usa-toggle>` })\n * ```\n * `bindUsa(el, { props, on })` is available for directives that bind imperatively.\n */\nimport { defineComponents, type ComponentCategory } from '../index';\n\nexport { bindUsa, usaEventName } from './bind';\nexport type { UsaBinding } from './bind';\n\n/** `APP_INITIALIZER` factory: registers the elements in the browser (no-op during SSR). */\nexport function usaInitializer(categories?: ComponentCategory[]): () => () => void {\n return () => () => {\n if (typeof window !== 'undefined') defineComponents(categories);\n };\n}\n\n/** Register the elements directly (e.g. in `main.ts` before `bootstrapApplication`). */\nexport function defineUsa(categories?: ComponentCategory[]): void {\n if (typeof window !== 'undefined') defineComponents(categories);\n}\n\n/** Read `event.detail` from a `usa:*` event in a template handler: `(usa:change)=\"on = usaDetail($event).checked\"`. */\nexport const usaDetail = <T = any>(e: Event): T => (e as CustomEvent<T>).detail;\n"],"names":["defineComponents"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;AAkBG;AAMH;AACM,SAAU,cAAc,CAAC,UAAgC,EAAA;AAC7D,IAAA,OAAO,MAAM,MAAK;QAChB,IAAI,OAAO,MAAM,KAAK,WAAW;YAAEA,2BAAgB,CAAC,UAAU,CAAC;AACjE,IAAA,CAAC;AACH;AAEA;AACM,SAAU,SAAS,CAAC,UAAgC,EAAA;IACxD,IAAI,OAAO,MAAM,KAAK,WAAW;QAAEA,2BAAgB,CAAC,UAAU,CAAC;AACjE;AAEA;AACO,MAAM,SAAS,GAAG,CAAU,CAAQ,KAAS,CAAoB,CAAC;;;;;;;;"}
1
+ {"version":3,"file":"angular.cjs","sources":["../../src/components/frameworks/angular.ts"],"sourcesContent":["/**\n * use-scroll-animate/components/angular — Angular integration (v3.8).\n * Angular renders `<usa-*>` tags once the component (or NgModule) allows\n * custom elements with `CUSTOM_ELEMENTS_SCHEMA`; property binding\n * `[checked]=\"on\"` and event binding `(usa:change)=\"…\"` then work as is.\n * This entry is framework-free (no `@angular/*` import):\n *\n * ```ts\n * import { CUSTOM_ELEMENTS_SCHEMA, Component, APP_INITIALIZER } from '@angular/core';\n * import { usaInitializer } from 'use-scroll-animate/components/angular';\n *\n * // app.config.ts\n * providers: [{ provide: APP_INITIALIZER, multi: true, useFactory: usaInitializer(['click', 'ui']) }]\n *\n * @Component({ standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA],\n * template: `<usa-toggle [checked]=\"on\" (usa:change)=\"on = $any($event).detail.checked\"></usa-toggle>` })\n * ```\n * `bindUsa(el, { props, on })` is available for directives that bind imperatively.\n */\nimport { defineComponents, type ComponentCategory } from '../index';\n\nexport { bindUsa, usaEventName } from './bind';\nexport type { UsaBinding } from './bind';\n\n/** `APP_INITIALIZER` factory: registers the elements in the browser (no-op during SSR). */\nexport function usaInitializer(categories?: ComponentCategory[]): () => () => void {\n return () => () => {\n if (typeof window !== 'undefined') defineComponents(categories);\n };\n}\n\n/** Register the elements directly (e.g. in `main.ts` before `bootstrapApplication`). */\nexport function defineUsa(categories?: ComponentCategory[]): void {\n if (typeof window !== 'undefined') defineComponents(categories);\n}\n\n/** Read `event.detail` from a `usa:*` event in a template handler: `(usa:change)=\"on = usaDetail($event).checked\"`. */\nexport const usaDetail = <T = any>(e: Event): T => (e as CustomEvent<T>).detail;\n"],"names":["defineComponents"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;AAkBG;AAMH;AACM,SAAU,cAAc,CAAC,UAAgC,EAAA;AAC7D,IAAA,OAAO,MAAM,MAAK;QAChB,IAAI,OAAO,MAAM,KAAK,WAAW;YAAEA,2BAAgB,CAAC,UAAU,CAAC;AACjE,IAAA,CAAC;AACH;AAEA;AACM,SAAU,SAAS,CAAC,UAAgC,EAAA;IACxD,IAAI,OAAO,MAAM,KAAK,WAAW;QAAEA,2BAAgB,CAAC,UAAU,CAAC;AACjE;AAEA;AACO,MAAM,SAAS,GAAG,CAAU,CAAQ,KAAS,CAAoB,CAAC;;;;;;;;"}
@@ -27,6 +27,7 @@ import './packs.js';
27
27
  import './a11y.js';
28
28
  import '../chunks/index-tags-43Xtd01A.js';
29
29
  import './perf.js';
30
+ import './bridge.js';
30
31
 
31
32
  /**
32
33
  * use-scroll-animate/components/angular — Angular integration (v3.8).
@@ -1 +1 @@
1
- {"version":3,"file":"angular.js","sources":["../../src/components/frameworks/angular.ts"],"sourcesContent":["/**\n * use-scroll-animate/components/angular — Angular integration (v3.8).\n * Angular renders `<usa-*>` tags once the component (or NgModule) allows\n * custom elements with `CUSTOM_ELEMENTS_SCHEMA`; property binding\n * `[checked]=\"on\"` and event binding `(usa:change)=\"…\"` then work as is.\n * This entry is framework-free (no `@angular/*` import):\n *\n * ```ts\n * import { CUSTOM_ELEMENTS_SCHEMA, Component, APP_INITIALIZER } from '@angular/core';\n * import { usaInitializer } from 'use-scroll-animate/components/angular';\n *\n * // app.config.ts\n * providers: [{ provide: APP_INITIALIZER, multi: true, useFactory: usaInitializer(['click', 'ui']) }]\n *\n * @Component({ standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA],\n * template: `<usa-toggle [checked]=\"on\" (usa:change)=\"on = $any($event).detail.checked\"></usa-toggle>` })\n * ```\n * `bindUsa(el, { props, on })` is available for directives that bind imperatively.\n */\nimport { defineComponents, type ComponentCategory } from '../index';\n\nexport { bindUsa, usaEventName } from './bind';\nexport type { UsaBinding } from './bind';\n\n/** `APP_INITIALIZER` factory: registers the elements in the browser (no-op during SSR). */\nexport function usaInitializer(categories?: ComponentCategory[]): () => () => void {\n return () => () => {\n if (typeof window !== 'undefined') defineComponents(categories);\n };\n}\n\n/** Register the elements directly (e.g. in `main.ts` before `bootstrapApplication`). */\nexport function defineUsa(categories?: ComponentCategory[]): void {\n if (typeof window !== 'undefined') defineComponents(categories);\n}\n\n/** Read `event.detail` from a `usa:*` event in a template handler: `(usa:change)=\"on = usaDetail($event).checked\"`. */\nexport const usaDetail = <T = any>(e: Event): T => (e as CustomEvent<T>).detail;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;AAkBG;AAMH;AACM,SAAU,cAAc,CAAC,UAAgC,EAAA;AAC7D,IAAA,OAAO,MAAM,MAAK;QAChB,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,gBAAgB,CAAC,UAAU,CAAC;AACjE,IAAA,CAAC;AACH;AAEA;AACM,SAAU,SAAS,CAAC,UAAgC,EAAA;IACxD,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,gBAAgB,CAAC,UAAU,CAAC;AACjE;AAEA;AACO,MAAM,SAAS,GAAG,CAAU,CAAQ,KAAS,CAAoB,CAAC;;;;"}
1
+ {"version":3,"file":"angular.js","sources":["../../src/components/frameworks/angular.ts"],"sourcesContent":["/**\n * use-scroll-animate/components/angular — Angular integration (v3.8).\n * Angular renders `<usa-*>` tags once the component (or NgModule) allows\n * custom elements with `CUSTOM_ELEMENTS_SCHEMA`; property binding\n * `[checked]=\"on\"` and event binding `(usa:change)=\"…\"` then work as is.\n * This entry is framework-free (no `@angular/*` import):\n *\n * ```ts\n * import { CUSTOM_ELEMENTS_SCHEMA, Component, APP_INITIALIZER } from '@angular/core';\n * import { usaInitializer } from 'use-scroll-animate/components/angular';\n *\n * // app.config.ts\n * providers: [{ provide: APP_INITIALIZER, multi: true, useFactory: usaInitializer(['click', 'ui']) }]\n *\n * @Component({ standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA],\n * template: `<usa-toggle [checked]=\"on\" (usa:change)=\"on = $any($event).detail.checked\"></usa-toggle>` })\n * ```\n * `bindUsa(el, { props, on })` is available for directives that bind imperatively.\n */\nimport { defineComponents, type ComponentCategory } from '../index';\n\nexport { bindUsa, usaEventName } from './bind';\nexport type { UsaBinding } from './bind';\n\n/** `APP_INITIALIZER` factory: registers the elements in the browser (no-op during SSR). */\nexport function usaInitializer(categories?: ComponentCategory[]): () => () => void {\n return () => () => {\n if (typeof window !== 'undefined') defineComponents(categories);\n };\n}\n\n/** Register the elements directly (e.g. in `main.ts` before `bootstrapApplication`). */\nexport function defineUsa(categories?: ComponentCategory[]): void {\n if (typeof window !== 'undefined') defineComponents(categories);\n}\n\n/** Read `event.detail` from a `usa:*` event in a template handler: `(usa:change)=\"on = usaDetail($event).checked\"`. */\nexport const usaDetail = <T = any>(e: Event): T => (e as CustomEvent<T>).detail;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;AAkBG;AAMH;AACM,SAAU,cAAc,CAAC,UAAgC,EAAA;AAC7D,IAAA,OAAO,MAAM,MAAK;QAChB,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,gBAAgB,CAAC,UAAU,CAAC;AACjE,IAAA,CAAC;AACH;AAEA;AACM,SAAU,SAAS,CAAC,UAAgC,EAAA;IACxD,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,gBAAgB,CAAC,UAAU,CAAC;AACjE;AAEA;AACO,MAAM,SAAS,GAAG,CAAU,CAAQ,KAAS,CAAoB,CAAC;;;;"}
@@ -0,0 +1,154 @@
1
+ 'use strict';
2
+
3
+ var base = require('../chunks/base-CxYU2NK_.cjs');
4
+
5
+ /**
6
+ * use-scroll-animate/components/bridge — native shell bridges (4.7).
7
+ *
8
+ * Keeps the web UI in sync with the host app's system settings when it runs
9
+ * inside **WinUI 3 / WPF (WebView2)**, **.NET MAUI** (WebView / HybridWebView)
10
+ * or **Flutter** (webview_flutter / flutter_inappwebview): the native side
11
+ * sends "reduce motion", light / dark / high-contrast theme and accent color;
12
+ * the page applies them to every `<usa-*>` component.
13
+ *
14
+ * Protocol (JSON, both directions):
15
+ * - native → web `{ "type": "usa:settings", "reducedMotion": true, "theme": "dark", "accent": "#0078d4", "sensitivity": "gentle" }`
16
+ * - web → native `{ "type": "usa:ready", "version": 1 }` on connect, `{ "type": "usa:request-settings" }`
17
+ *
18
+ * Hosts that can only run script call `window.usaNative.apply({...})`.
19
+ * Samples: examples/native/{winui3,maui,flutter}.
20
+ */
21
+ const BRIDGE_PROTOCOL_VERSION = 1;
22
+ const win = () => (typeof window === 'undefined' ? null : window);
23
+ /** Which native shell (if any) hosts this page. */
24
+ function detectNativeHost(channel = 'UsaBridge') {
25
+ const w = win();
26
+ if (!w)
27
+ return 'browser';
28
+ if (w.chrome?.webview?.postMessage)
29
+ return 'webview2';
30
+ if (w.HybridWebView?.SendRawMessage || w.HybridWebView?.SendRawMessageToDotNet || /\bMAUI\b/i.test(w.navigator?.userAgent || ''))
31
+ return 'maui';
32
+ if (w.flutter_inappwebview?.callHandler || w[channel]?.postMessage)
33
+ return 'flutter';
34
+ if (w.__TAURI__ || w.__TAURI_INTERNALS__)
35
+ return 'tauri';
36
+ if (w.process?.versions?.electron || /Electron\//.test(w.navigator?.userAgent || ''))
37
+ return 'electron';
38
+ return 'browser';
39
+ }
40
+ /** Send a JSON message to the native host (no-op in a plain browser). Returns whether it was sent. */
41
+ function postToNative(message, channel = 'UsaBridge') {
42
+ const w = win();
43
+ if (!w)
44
+ return false;
45
+ const json = JSON.stringify(message);
46
+ try {
47
+ if (w.chrome?.webview?.postMessage)
48
+ return w.chrome.webview.postMessage(message), true;
49
+ if (w.HybridWebView?.SendRawMessage)
50
+ return w.HybridWebView.SendRawMessage(json), true;
51
+ if (w.HybridWebView?.SendRawMessageToDotNet)
52
+ return w.HybridWebView.SendRawMessageToDotNet(json), true;
53
+ if (w.flutter_inappwebview?.callHandler)
54
+ return w.flutter_inappwebview.callHandler(channel, json), true;
55
+ if (w[channel]?.postMessage)
56
+ return w[channel].postMessage(json), true;
57
+ }
58
+ catch {
59
+ /* host went away */
60
+ }
61
+ return false;
62
+ }
63
+ const THEMES = ['light', 'dark', 'high-contrast'];
64
+ const COLOR = /^(#[0-9a-f]{3,8}|rgba?\([\d\s.,%]+\)|hsla?\([\d\s.,%deg]+\))$/i;
65
+ /** Validate an incoming message (string or object); unknown fields are dropped. */
66
+ function parseNativeSettings(data) {
67
+ let d = data;
68
+ if (typeof d === 'string') {
69
+ try {
70
+ d = JSON.parse(d);
71
+ }
72
+ catch {
73
+ return null;
74
+ }
75
+ }
76
+ if (!d || typeof d !== 'object' || d.type !== 'usa:settings')
77
+ return null;
78
+ const out = {};
79
+ if (typeof d.reducedMotion === 'boolean')
80
+ out.reducedMotion = d.reducedMotion;
81
+ if (THEMES.includes(d.theme))
82
+ out.theme = d.theme;
83
+ if (typeof d.accent === 'string' && COLOR.test(d.accent.trim()))
84
+ out.accent = d.accent.trim();
85
+ if (base.MOTION_SENSITIVITY_LEVELS.includes(d.sensitivity))
86
+ out.sensitivity = d.sensitivity;
87
+ return out;
88
+ }
89
+ /**
90
+ * Apply native settings: reduce motion → `configureComponents({ reducedMotion: 'reduce' })`
91
+ * (`false` → follow the media query again); theme → `data-theme`, `data-usa-contrast`
92
+ * and `color-scheme`; accent → `--usa-accent`; sensitivity → `motionSensitivity`.
93
+ */
94
+ function applyNativeSettings(s, root) {
95
+ if (s.reducedMotion !== undefined)
96
+ base.configureComponents({ reducedMotion: s.reducedMotion ? 'reduce' : 'user' });
97
+ if (s.sensitivity)
98
+ base.configureComponents({ motionSensitivity: s.sensitivity });
99
+ const el = root || (typeof document !== 'undefined' ? document.documentElement : null);
100
+ if (!el)
101
+ return;
102
+ if (s.theme) {
103
+ el.setAttribute('data-theme', s.theme === 'high-contrast' ? 'dark' : s.theme);
104
+ el.toggleAttribute('data-usa-contrast', s.theme === 'high-contrast');
105
+ el.style.colorScheme = s.theme === 'light' ? 'light' : 'dark';
106
+ }
107
+ if (s.accent)
108
+ el.style.setProperty('--usa-accent', s.accent);
109
+ if (typeof document !== 'undefined')
110
+ document.dispatchEvent(new CustomEvent('usa:native-settings', { detail: s }));
111
+ }
112
+ /**
113
+ * Connect to the native shell: listens for `usa:settings` messages
114
+ * (WebView2 `chrome.webview` messages, `window.postMessage`, or
115
+ * `window.usaNative.apply()`), applies them, then announces `usa:ready` and
116
+ * asks for the current settings. Returns `{ host, disconnect }`.
117
+ */
118
+ function connectNativeShell(options = {}) {
119
+ const w = win();
120
+ const channel = options.channel || 'UsaBridge';
121
+ const host = detectNativeHost(channel);
122
+ if (!w)
123
+ return { host, disconnect: () => undefined };
124
+ const handle = (data) => {
125
+ const s = parseNativeSettings(data);
126
+ if (!s)
127
+ return;
128
+ applyNativeSettings(s, options.root);
129
+ options.onSettings?.(s, host);
130
+ };
131
+ const onMessage = (e) => handle(e.data);
132
+ w.chrome?.webview?.addEventListener?.('message', onMessage);
133
+ w.addEventListener?.('message', onMessage);
134
+ const prev = w.usaNative;
135
+ w.usaNative = { apply: (s) => handle({ ...s, type: 'usa:settings' }), version: BRIDGE_PROTOCOL_VERSION, host };
136
+ postToNative({ type: 'usa:ready', version: BRIDGE_PROTOCOL_VERSION }, channel);
137
+ postToNative({ type: 'usa:request-settings' }, channel);
138
+ return {
139
+ host,
140
+ disconnect: () => {
141
+ w.chrome?.webview?.removeEventListener?.('message', onMessage);
142
+ w.removeEventListener?.('message', onMessage);
143
+ w.usaNative = prev;
144
+ },
145
+ };
146
+ }
147
+
148
+ exports.BRIDGE_PROTOCOL_VERSION = BRIDGE_PROTOCOL_VERSION;
149
+ exports.applyNativeSettings = applyNativeSettings;
150
+ exports.connectNativeShell = connectNativeShell;
151
+ exports.detectNativeHost = detectNativeHost;
152
+ exports.parseNativeSettings = parseNativeSettings;
153
+ exports.postToNative = postToNative;
154
+ //# sourceMappingURL=bridge.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.cjs","sources":["../../src/components/bridge/index.ts"],"sourcesContent":["/**\n * use-scroll-animate/components/bridge — native shell bridges (4.7).\n *\n * Keeps the web UI in sync with the host app's system settings when it runs\n * inside **WinUI 3 / WPF (WebView2)**, **.NET MAUI** (WebView / HybridWebView)\n * or **Flutter** (webview_flutter / flutter_inappwebview): the native side\n * sends \"reduce motion\", light / dark / high-contrast theme and accent color;\n * the page applies them to every `<usa-*>` component.\n *\n * Protocol (JSON, both directions):\n * - native → web `{ \"type\": \"usa:settings\", \"reducedMotion\": true, \"theme\": \"dark\", \"accent\": \"#0078d4\", \"sensitivity\": \"gentle\" }`\n * - web → native `{ \"type\": \"usa:ready\", \"version\": 1 }` on connect, `{ \"type\": \"usa:request-settings\" }`\n *\n * Hosts that can only run script call `window.usaNative.apply({...})`.\n * Samples: examples/native/{winui3,maui,flutter}.\n */\nimport { configureComponents, MOTION_SENSITIVITY_LEVELS, type MotionSensitivity } from '../base';\n\nexport type NativeHost = 'webview2' | 'maui' | 'flutter' | 'electron' | 'tauri' | 'browser';\nexport type NativeTheme = 'light' | 'dark' | 'high-contrast';\n\nexport interface NativeSettings {\n reducedMotion?: boolean;\n theme?: NativeTheme;\n /** CSS color (`#0078d4`, `rgb(…)`). */\n accent?: string;\n /** Optional finer level (4.4). */\n sensitivity?: MotionSensitivity;\n}\n\nexport interface NativeShellOptions {\n /** Element that gets `data-theme` / `color-scheme` / `--usa-accent` (default `<html>`). */\n root?: HTMLElement;\n /** Flutter JavaScriptChannel name (default `UsaBridge`). */\n channel?: string;\n /** Called after settings are applied. */\n onSettings?: (settings: NativeSettings, host: NativeHost) => void;\n}\n\nexport const BRIDGE_PROTOCOL_VERSION = 1;\n\ntype W = Record<string, any>;\nconst win = (): W | null => (typeof window === 'undefined' ? null : (window as unknown as W));\n\n/** Which native shell (if any) hosts this page. */\nexport function detectNativeHost(channel = 'UsaBridge'): NativeHost {\n const w = win();\n if (!w) return 'browser';\n if (w.chrome?.webview?.postMessage) return 'webview2';\n if (w.HybridWebView?.SendRawMessage || w.HybridWebView?.SendRawMessageToDotNet || /\\bMAUI\\b/i.test(w.navigator?.userAgent || '')) return 'maui';\n if (w.flutter_inappwebview?.callHandler || w[channel]?.postMessage) return 'flutter';\n if (w.__TAURI__ || w.__TAURI_INTERNALS__) return 'tauri';\n if (w.process?.versions?.electron || /Electron\\//.test(w.navigator?.userAgent || '')) return 'electron';\n return 'browser';\n}\n\n/** Send a JSON message to the native host (no-op in a plain browser). Returns whether it was sent. */\nexport function postToNative(message: Record<string, unknown>, channel = 'UsaBridge'): boolean {\n const w = win();\n if (!w) return false;\n const json = JSON.stringify(message);\n try {\n if (w.chrome?.webview?.postMessage) return w.chrome.webview.postMessage(message), true;\n if (w.HybridWebView?.SendRawMessage) return w.HybridWebView.SendRawMessage(json), true;\n if (w.HybridWebView?.SendRawMessageToDotNet) return w.HybridWebView.SendRawMessageToDotNet(json), true;\n if (w.flutter_inappwebview?.callHandler) return w.flutter_inappwebview.callHandler(channel, json), true;\n if (w[channel]?.postMessage) return w[channel].postMessage(json), true;\n } catch {\n /* host went away */\n }\n return false;\n}\n\nconst THEMES: NativeTheme[] = ['light', 'dark', 'high-contrast'];\nconst COLOR = /^(#[0-9a-f]{3,8}|rgba?\\([\\d\\s.,%]+\\)|hsla?\\([\\d\\s.,%deg]+\\))$/i;\n\n/** Validate an incoming message (string or object); unknown fields are dropped. */\nexport function parseNativeSettings(data: unknown): NativeSettings | null {\n let d: any = data;\n if (typeof d === 'string') {\n try {\n d = JSON.parse(d);\n } catch {\n return null;\n }\n }\n if (!d || typeof d !== 'object' || d.type !== 'usa:settings') return null;\n const out: NativeSettings = {};\n if (typeof d.reducedMotion === 'boolean') out.reducedMotion = d.reducedMotion;\n if (THEMES.includes(d.theme)) out.theme = d.theme;\n if (typeof d.accent === 'string' && COLOR.test(d.accent.trim())) out.accent = d.accent.trim();\n if (MOTION_SENSITIVITY_LEVELS.includes(d.sensitivity)) out.sensitivity = d.sensitivity;\n return out;\n}\n\n/**\n * Apply native settings: reduce motion → `configureComponents({ reducedMotion: 'reduce' })`\n * (`false` → follow the media query again); theme → `data-theme`, `data-usa-contrast`\n * and `color-scheme`; accent → `--usa-accent`; sensitivity → `motionSensitivity`.\n */\nexport function applyNativeSettings(s: NativeSettings, root?: HTMLElement): void {\n if (s.reducedMotion !== undefined) configureComponents({ reducedMotion: s.reducedMotion ? 'reduce' : 'user' });\n if (s.sensitivity) configureComponents({ motionSensitivity: s.sensitivity });\n const el = root || (typeof document !== 'undefined' ? document.documentElement : null);\n if (!el) return;\n if (s.theme) {\n el.setAttribute('data-theme', s.theme === 'high-contrast' ? 'dark' : s.theme);\n el.toggleAttribute('data-usa-contrast', s.theme === 'high-contrast');\n el.style.colorScheme = s.theme === 'light' ? 'light' : 'dark';\n }\n if (s.accent) el.style.setProperty('--usa-accent', s.accent);\n if (typeof document !== 'undefined') document.dispatchEvent(new CustomEvent('usa:native-settings', { detail: s }));\n}\n\n/**\n * Connect to the native shell: listens for `usa:settings` messages\n * (WebView2 `chrome.webview` messages, `window.postMessage`, or\n * `window.usaNative.apply()`), applies them, then announces `usa:ready` and\n * asks for the current settings. Returns `{ host, disconnect }`.\n */\nexport function connectNativeShell(options: NativeShellOptions = {}): { host: NativeHost; disconnect: () => void } {\n const w = win();\n const channel = options.channel || 'UsaBridge';\n const host = detectNativeHost(channel);\n if (!w) return { host, disconnect: () => undefined };\n const handle = (data: unknown) => {\n const s = parseNativeSettings(data);\n if (!s) return;\n applyNativeSettings(s, options.root);\n options.onSettings?.(s, host);\n };\n const onMessage = (e: MessageEvent) => handle(e.data);\n w.chrome?.webview?.addEventListener?.('message', onMessage);\n w.addEventListener?.('message', onMessage);\n const prev = w.usaNative;\n w.usaNative = { apply: (s: NativeSettings) => handle({ ...s, type: 'usa:settings' }), version: BRIDGE_PROTOCOL_VERSION, host };\n postToNative({ type: 'usa:ready', version: BRIDGE_PROTOCOL_VERSION }, channel);\n postToNative({ type: 'usa:request-settings' }, channel);\n return {\n host,\n disconnect: () => {\n w.chrome?.webview?.removeEventListener?.('message', onMessage);\n w.removeEventListener?.('message', onMessage);\n w.usaNative = prev;\n },\n };\n}\n"],"names":["MOTION_SENSITIVITY_LEVELS","configureComponents"],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ type MotionSensitivity = 'full' | 'gentle' | 'minimal' | 'static';
2
+
3
+ /**
4
+ * use-scroll-animate/components/bridge — native shell bridges (4.7).
5
+ *
6
+ * Keeps the web UI in sync with the host app's system settings when it runs
7
+ * inside **WinUI 3 / WPF (WebView2)**, **.NET MAUI** (WebView / HybridWebView)
8
+ * or **Flutter** (webview_flutter / flutter_inappwebview): the native side
9
+ * sends "reduce motion", light / dark / high-contrast theme and accent color;
10
+ * the page applies them to every `<usa-*>` component.
11
+ *
12
+ * Protocol (JSON, both directions):
13
+ * - native → web `{ "type": "usa:settings", "reducedMotion": true, "theme": "dark", "accent": "#0078d4", "sensitivity": "gentle" }`
14
+ * - web → native `{ "type": "usa:ready", "version": 1 }` on connect, `{ "type": "usa:request-settings" }`
15
+ *
16
+ * Hosts that can only run script call `window.usaNative.apply({...})`.
17
+ * Samples: examples/native/{winui3,maui,flutter}.
18
+ */
19
+
20
+ type NativeHost = 'webview2' | 'maui' | 'flutter' | 'electron' | 'tauri' | 'browser';
21
+ type NativeTheme = 'light' | 'dark' | 'high-contrast';
22
+ interface NativeSettings {
23
+ reducedMotion?: boolean;
24
+ theme?: NativeTheme;
25
+ /** CSS color (`#0078d4`, `rgb(…)`). */
26
+ accent?: string;
27
+ /** Optional finer level (4.4). */
28
+ sensitivity?: MotionSensitivity;
29
+ }
30
+ interface NativeShellOptions {
31
+ /** Element that gets `data-theme` / `color-scheme` / `--usa-accent` (default `<html>`). */
32
+ root?: HTMLElement;
33
+ /** Flutter JavaScriptChannel name (default `UsaBridge`). */
34
+ channel?: string;
35
+ /** Called after settings are applied. */
36
+ onSettings?: (settings: NativeSettings, host: NativeHost) => void;
37
+ }
38
+ declare const BRIDGE_PROTOCOL_VERSION = 1;
39
+ /** Which native shell (if any) hosts this page. */
40
+ declare function detectNativeHost(channel?: string): NativeHost;
41
+ /** Send a JSON message to the native host (no-op in a plain browser). Returns whether it was sent. */
42
+ declare function postToNative(message: Record<string, unknown>, channel?: string): boolean;
43
+ /** Validate an incoming message (string or object); unknown fields are dropped. */
44
+ declare function parseNativeSettings(data: unknown): NativeSettings | null;
45
+ /**
46
+ * Apply native settings: reduce motion → `configureComponents({ reducedMotion: 'reduce' })`
47
+ * (`false` → follow the media query again); theme → `data-theme`, `data-usa-contrast`
48
+ * and `color-scheme`; accent → `--usa-accent`; sensitivity → `motionSensitivity`.
49
+ */
50
+ declare function applyNativeSettings(s: NativeSettings, root?: HTMLElement): void;
51
+ /**
52
+ * Connect to the native shell: listens for `usa:settings` messages
53
+ * (WebView2 `chrome.webview` messages, `window.postMessage`, or
54
+ * `window.usaNative.apply()`), applies them, then announces `usa:ready` and
55
+ * asks for the current settings. Returns `{ host, disconnect }`.
56
+ */
57
+ declare function connectNativeShell(options?: NativeShellOptions): {
58
+ host: NativeHost;
59
+ disconnect: () => void;
60
+ };
61
+
62
+ export { BRIDGE_PROTOCOL_VERSION, applyNativeSettings, connectNativeShell, detectNativeHost, parseNativeSettings, postToNative };
63
+ export type { NativeHost, NativeSettings, NativeShellOptions, NativeTheme };
@@ -0,0 +1,63 @@
1
+ type MotionSensitivity = 'full' | 'gentle' | 'minimal' | 'static';
2
+
3
+ /**
4
+ * use-scroll-animate/components/bridge — native shell bridges (4.7).
5
+ *
6
+ * Keeps the web UI in sync with the host app's system settings when it runs
7
+ * inside **WinUI 3 / WPF (WebView2)**, **.NET MAUI** (WebView / HybridWebView)
8
+ * or **Flutter** (webview_flutter / flutter_inappwebview): the native side
9
+ * sends "reduce motion", light / dark / high-contrast theme and accent color;
10
+ * the page applies them to every `<usa-*>` component.
11
+ *
12
+ * Protocol (JSON, both directions):
13
+ * - native → web `{ "type": "usa:settings", "reducedMotion": true, "theme": "dark", "accent": "#0078d4", "sensitivity": "gentle" }`
14
+ * - web → native `{ "type": "usa:ready", "version": 1 }` on connect, `{ "type": "usa:request-settings" }`
15
+ *
16
+ * Hosts that can only run script call `window.usaNative.apply({...})`.
17
+ * Samples: examples/native/{winui3,maui,flutter}.
18
+ */
19
+
20
+ type NativeHost = 'webview2' | 'maui' | 'flutter' | 'electron' | 'tauri' | 'browser';
21
+ type NativeTheme = 'light' | 'dark' | 'high-contrast';
22
+ interface NativeSettings {
23
+ reducedMotion?: boolean;
24
+ theme?: NativeTheme;
25
+ /** CSS color (`#0078d4`, `rgb(…)`). */
26
+ accent?: string;
27
+ /** Optional finer level (4.4). */
28
+ sensitivity?: MotionSensitivity;
29
+ }
30
+ interface NativeShellOptions {
31
+ /** Element that gets `data-theme` / `color-scheme` / `--usa-accent` (default `<html>`). */
32
+ root?: HTMLElement;
33
+ /** Flutter JavaScriptChannel name (default `UsaBridge`). */
34
+ channel?: string;
35
+ /** Called after settings are applied. */
36
+ onSettings?: (settings: NativeSettings, host: NativeHost) => void;
37
+ }
38
+ declare const BRIDGE_PROTOCOL_VERSION = 1;
39
+ /** Which native shell (if any) hosts this page. */
40
+ declare function detectNativeHost(channel?: string): NativeHost;
41
+ /** Send a JSON message to the native host (no-op in a plain browser). Returns whether it was sent. */
42
+ declare function postToNative(message: Record<string, unknown>, channel?: string): boolean;
43
+ /** Validate an incoming message (string or object); unknown fields are dropped. */
44
+ declare function parseNativeSettings(data: unknown): NativeSettings | null;
45
+ /**
46
+ * Apply native settings: reduce motion → `configureComponents({ reducedMotion: 'reduce' })`
47
+ * (`false` → follow the media query again); theme → `data-theme`, `data-usa-contrast`
48
+ * and `color-scheme`; accent → `--usa-accent`; sensitivity → `motionSensitivity`.
49
+ */
50
+ declare function applyNativeSettings(s: NativeSettings, root?: HTMLElement): void;
51
+ /**
52
+ * Connect to the native shell: listens for `usa:settings` messages
53
+ * (WebView2 `chrome.webview` messages, `window.postMessage`, or
54
+ * `window.usaNative.apply()`), applies them, then announces `usa:ready` and
55
+ * asks for the current settings. Returns `{ host, disconnect }`.
56
+ */
57
+ declare function connectNativeShell(options?: NativeShellOptions): {
58
+ host: NativeHost;
59
+ disconnect: () => void;
60
+ };
61
+
62
+ export { BRIDGE_PROTOCOL_VERSION, applyNativeSettings, connectNativeShell, detectNativeHost, parseNativeSettings, postToNative };
63
+ export type { NativeHost, NativeSettings, NativeShellOptions, NativeTheme };
@@ -0,0 +1,147 @@
1
+ import { f as configureComponents, a as MOTION_SENSITIVITY_LEVELS } from '../chunks/base-CZiIAMBc.js';
2
+
3
+ /**
4
+ * use-scroll-animate/components/bridge — native shell bridges (4.7).
5
+ *
6
+ * Keeps the web UI in sync with the host app's system settings when it runs
7
+ * inside **WinUI 3 / WPF (WebView2)**, **.NET MAUI** (WebView / HybridWebView)
8
+ * or **Flutter** (webview_flutter / flutter_inappwebview): the native side
9
+ * sends "reduce motion", light / dark / high-contrast theme and accent color;
10
+ * the page applies them to every `<usa-*>` component.
11
+ *
12
+ * Protocol (JSON, both directions):
13
+ * - native → web `{ "type": "usa:settings", "reducedMotion": true, "theme": "dark", "accent": "#0078d4", "sensitivity": "gentle" }`
14
+ * - web → native `{ "type": "usa:ready", "version": 1 }` on connect, `{ "type": "usa:request-settings" }`
15
+ *
16
+ * Hosts that can only run script call `window.usaNative.apply({...})`.
17
+ * Samples: examples/native/{winui3,maui,flutter}.
18
+ */
19
+ const BRIDGE_PROTOCOL_VERSION = 1;
20
+ const win = () => (typeof window === 'undefined' ? null : window);
21
+ /** Which native shell (if any) hosts this page. */
22
+ function detectNativeHost(channel = 'UsaBridge') {
23
+ const w = win();
24
+ if (!w)
25
+ return 'browser';
26
+ if (w.chrome?.webview?.postMessage)
27
+ return 'webview2';
28
+ if (w.HybridWebView?.SendRawMessage || w.HybridWebView?.SendRawMessageToDotNet || /\bMAUI\b/i.test(w.navigator?.userAgent || ''))
29
+ return 'maui';
30
+ if (w.flutter_inappwebview?.callHandler || w[channel]?.postMessage)
31
+ return 'flutter';
32
+ if (w.__TAURI__ || w.__TAURI_INTERNALS__)
33
+ return 'tauri';
34
+ if (w.process?.versions?.electron || /Electron\//.test(w.navigator?.userAgent || ''))
35
+ return 'electron';
36
+ return 'browser';
37
+ }
38
+ /** Send a JSON message to the native host (no-op in a plain browser). Returns whether it was sent. */
39
+ function postToNative(message, channel = 'UsaBridge') {
40
+ const w = win();
41
+ if (!w)
42
+ return false;
43
+ const json = JSON.stringify(message);
44
+ try {
45
+ if (w.chrome?.webview?.postMessage)
46
+ return w.chrome.webview.postMessage(message), true;
47
+ if (w.HybridWebView?.SendRawMessage)
48
+ return w.HybridWebView.SendRawMessage(json), true;
49
+ if (w.HybridWebView?.SendRawMessageToDotNet)
50
+ return w.HybridWebView.SendRawMessageToDotNet(json), true;
51
+ if (w.flutter_inappwebview?.callHandler)
52
+ return w.flutter_inappwebview.callHandler(channel, json), true;
53
+ if (w[channel]?.postMessage)
54
+ return w[channel].postMessage(json), true;
55
+ }
56
+ catch {
57
+ /* host went away */
58
+ }
59
+ return false;
60
+ }
61
+ const THEMES = ['light', 'dark', 'high-contrast'];
62
+ const COLOR = /^(#[0-9a-f]{3,8}|rgba?\([\d\s.,%]+\)|hsla?\([\d\s.,%deg]+\))$/i;
63
+ /** Validate an incoming message (string or object); unknown fields are dropped. */
64
+ function parseNativeSettings(data) {
65
+ let d = data;
66
+ if (typeof d === 'string') {
67
+ try {
68
+ d = JSON.parse(d);
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ if (!d || typeof d !== 'object' || d.type !== 'usa:settings')
75
+ return null;
76
+ const out = {};
77
+ if (typeof d.reducedMotion === 'boolean')
78
+ out.reducedMotion = d.reducedMotion;
79
+ if (THEMES.includes(d.theme))
80
+ out.theme = d.theme;
81
+ if (typeof d.accent === 'string' && COLOR.test(d.accent.trim()))
82
+ out.accent = d.accent.trim();
83
+ if (MOTION_SENSITIVITY_LEVELS.includes(d.sensitivity))
84
+ out.sensitivity = d.sensitivity;
85
+ return out;
86
+ }
87
+ /**
88
+ * Apply native settings: reduce motion → `configureComponents({ reducedMotion: 'reduce' })`
89
+ * (`false` → follow the media query again); theme → `data-theme`, `data-usa-contrast`
90
+ * and `color-scheme`; accent → `--usa-accent`; sensitivity → `motionSensitivity`.
91
+ */
92
+ function applyNativeSettings(s, root) {
93
+ if (s.reducedMotion !== undefined)
94
+ configureComponents({ reducedMotion: s.reducedMotion ? 'reduce' : 'user' });
95
+ if (s.sensitivity)
96
+ configureComponents({ motionSensitivity: s.sensitivity });
97
+ const el = root || (typeof document !== 'undefined' ? document.documentElement : null);
98
+ if (!el)
99
+ return;
100
+ if (s.theme) {
101
+ el.setAttribute('data-theme', s.theme === 'high-contrast' ? 'dark' : s.theme);
102
+ el.toggleAttribute('data-usa-contrast', s.theme === 'high-contrast');
103
+ el.style.colorScheme = s.theme === 'light' ? 'light' : 'dark';
104
+ }
105
+ if (s.accent)
106
+ el.style.setProperty('--usa-accent', s.accent);
107
+ if (typeof document !== 'undefined')
108
+ document.dispatchEvent(new CustomEvent('usa:native-settings', { detail: s }));
109
+ }
110
+ /**
111
+ * Connect to the native shell: listens for `usa:settings` messages
112
+ * (WebView2 `chrome.webview` messages, `window.postMessage`, or
113
+ * `window.usaNative.apply()`), applies them, then announces `usa:ready` and
114
+ * asks for the current settings. Returns `{ host, disconnect }`.
115
+ */
116
+ function connectNativeShell(options = {}) {
117
+ const w = win();
118
+ const channel = options.channel || 'UsaBridge';
119
+ const host = detectNativeHost(channel);
120
+ if (!w)
121
+ return { host, disconnect: () => undefined };
122
+ const handle = (data) => {
123
+ const s = parseNativeSettings(data);
124
+ if (!s)
125
+ return;
126
+ applyNativeSettings(s, options.root);
127
+ options.onSettings?.(s, host);
128
+ };
129
+ const onMessage = (e) => handle(e.data);
130
+ w.chrome?.webview?.addEventListener?.('message', onMessage);
131
+ w.addEventListener?.('message', onMessage);
132
+ const prev = w.usaNative;
133
+ w.usaNative = { apply: (s) => handle({ ...s, type: 'usa:settings' }), version: BRIDGE_PROTOCOL_VERSION, host };
134
+ postToNative({ type: 'usa:ready', version: BRIDGE_PROTOCOL_VERSION }, channel);
135
+ postToNative({ type: 'usa:request-settings' }, channel);
136
+ return {
137
+ host,
138
+ disconnect: () => {
139
+ w.chrome?.webview?.removeEventListener?.('message', onMessage);
140
+ w.removeEventListener?.('message', onMessage);
141
+ w.usaNative = prev;
142
+ },
143
+ };
144
+ }
145
+
146
+ export { BRIDGE_PROTOCOL_VERSION, applyNativeSettings, connectNativeShell, detectNativeHost, parseNativeSettings, postToNative };
147
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sources":["../../src/components/bridge/index.ts"],"sourcesContent":["/**\n * use-scroll-animate/components/bridge — native shell bridges (4.7).\n *\n * Keeps the web UI in sync with the host app's system settings when it runs\n * inside **WinUI 3 / WPF (WebView2)**, **.NET MAUI** (WebView / HybridWebView)\n * or **Flutter** (webview_flutter / flutter_inappwebview): the native side\n * sends \"reduce motion\", light / dark / high-contrast theme and accent color;\n * the page applies them to every `<usa-*>` component.\n *\n * Protocol (JSON, both directions):\n * - native → web `{ \"type\": \"usa:settings\", \"reducedMotion\": true, \"theme\": \"dark\", \"accent\": \"#0078d4\", \"sensitivity\": \"gentle\" }`\n * - web → native `{ \"type\": \"usa:ready\", \"version\": 1 }` on connect, `{ \"type\": \"usa:request-settings\" }`\n *\n * Hosts that can only run script call `window.usaNative.apply({...})`.\n * Samples: examples/native/{winui3,maui,flutter}.\n */\nimport { configureComponents, MOTION_SENSITIVITY_LEVELS, type MotionSensitivity } from '../base';\n\nexport type NativeHost = 'webview2' | 'maui' | 'flutter' | 'electron' | 'tauri' | 'browser';\nexport type NativeTheme = 'light' | 'dark' | 'high-contrast';\n\nexport interface NativeSettings {\n reducedMotion?: boolean;\n theme?: NativeTheme;\n /** CSS color (`#0078d4`, `rgb(…)`). */\n accent?: string;\n /** Optional finer level (4.4). */\n sensitivity?: MotionSensitivity;\n}\n\nexport interface NativeShellOptions {\n /** Element that gets `data-theme` / `color-scheme` / `--usa-accent` (default `<html>`). */\n root?: HTMLElement;\n /** Flutter JavaScriptChannel name (default `UsaBridge`). */\n channel?: string;\n /** Called after settings are applied. */\n onSettings?: (settings: NativeSettings, host: NativeHost) => void;\n}\n\nexport const BRIDGE_PROTOCOL_VERSION = 1;\n\ntype W = Record<string, any>;\nconst win = (): W | null => (typeof window === 'undefined' ? null : (window as unknown as W));\n\n/** Which native shell (if any) hosts this page. */\nexport function detectNativeHost(channel = 'UsaBridge'): NativeHost {\n const w = win();\n if (!w) return 'browser';\n if (w.chrome?.webview?.postMessage) return 'webview2';\n if (w.HybridWebView?.SendRawMessage || w.HybridWebView?.SendRawMessageToDotNet || /\\bMAUI\\b/i.test(w.navigator?.userAgent || '')) return 'maui';\n if (w.flutter_inappwebview?.callHandler || w[channel]?.postMessage) return 'flutter';\n if (w.__TAURI__ || w.__TAURI_INTERNALS__) return 'tauri';\n if (w.process?.versions?.electron || /Electron\\//.test(w.navigator?.userAgent || '')) return 'electron';\n return 'browser';\n}\n\n/** Send a JSON message to the native host (no-op in a plain browser). Returns whether it was sent. */\nexport function postToNative(message: Record<string, unknown>, channel = 'UsaBridge'): boolean {\n const w = win();\n if (!w) return false;\n const json = JSON.stringify(message);\n try {\n if (w.chrome?.webview?.postMessage) return w.chrome.webview.postMessage(message), true;\n if (w.HybridWebView?.SendRawMessage) return w.HybridWebView.SendRawMessage(json), true;\n if (w.HybridWebView?.SendRawMessageToDotNet) return w.HybridWebView.SendRawMessageToDotNet(json), true;\n if (w.flutter_inappwebview?.callHandler) return w.flutter_inappwebview.callHandler(channel, json), true;\n if (w[channel]?.postMessage) return w[channel].postMessage(json), true;\n } catch {\n /* host went away */\n }\n return false;\n}\n\nconst THEMES: NativeTheme[] = ['light', 'dark', 'high-contrast'];\nconst COLOR = /^(#[0-9a-f]{3,8}|rgba?\\([\\d\\s.,%]+\\)|hsla?\\([\\d\\s.,%deg]+\\))$/i;\n\n/** Validate an incoming message (string or object); unknown fields are dropped. */\nexport function parseNativeSettings(data: unknown): NativeSettings | null {\n let d: any = data;\n if (typeof d === 'string') {\n try {\n d = JSON.parse(d);\n } catch {\n return null;\n }\n }\n if (!d || typeof d !== 'object' || d.type !== 'usa:settings') return null;\n const out: NativeSettings = {};\n if (typeof d.reducedMotion === 'boolean') out.reducedMotion = d.reducedMotion;\n if (THEMES.includes(d.theme)) out.theme = d.theme;\n if (typeof d.accent === 'string' && COLOR.test(d.accent.trim())) out.accent = d.accent.trim();\n if (MOTION_SENSITIVITY_LEVELS.includes(d.sensitivity)) out.sensitivity = d.sensitivity;\n return out;\n}\n\n/**\n * Apply native settings: reduce motion → `configureComponents({ reducedMotion: 'reduce' })`\n * (`false` → follow the media query again); theme → `data-theme`, `data-usa-contrast`\n * and `color-scheme`; accent → `--usa-accent`; sensitivity → `motionSensitivity`.\n */\nexport function applyNativeSettings(s: NativeSettings, root?: HTMLElement): void {\n if (s.reducedMotion !== undefined) configureComponents({ reducedMotion: s.reducedMotion ? 'reduce' : 'user' });\n if (s.sensitivity) configureComponents({ motionSensitivity: s.sensitivity });\n const el = root || (typeof document !== 'undefined' ? document.documentElement : null);\n if (!el) return;\n if (s.theme) {\n el.setAttribute('data-theme', s.theme === 'high-contrast' ? 'dark' : s.theme);\n el.toggleAttribute('data-usa-contrast', s.theme === 'high-contrast');\n el.style.colorScheme = s.theme === 'light' ? 'light' : 'dark';\n }\n if (s.accent) el.style.setProperty('--usa-accent', s.accent);\n if (typeof document !== 'undefined') document.dispatchEvent(new CustomEvent('usa:native-settings', { detail: s }));\n}\n\n/**\n * Connect to the native shell: listens for `usa:settings` messages\n * (WebView2 `chrome.webview` messages, `window.postMessage`, or\n * `window.usaNative.apply()`), applies them, then announces `usa:ready` and\n * asks for the current settings. Returns `{ host, disconnect }`.\n */\nexport function connectNativeShell(options: NativeShellOptions = {}): { host: NativeHost; disconnect: () => void } {\n const w = win();\n const channel = options.channel || 'UsaBridge';\n const host = detectNativeHost(channel);\n if (!w) return { host, disconnect: () => undefined };\n const handle = (data: unknown) => {\n const s = parseNativeSettings(data);\n if (!s) return;\n applyNativeSettings(s, options.root);\n options.onSettings?.(s, host);\n };\n const onMessage = (e: MessageEvent) => handle(e.data);\n w.chrome?.webview?.addEventListener?.('message', onMessage);\n w.addEventListener?.('message', onMessage);\n const prev = w.usaNative;\n w.usaNative = { apply: (s: NativeSettings) => handle({ ...s, type: 'usa:settings' }), version: BRIDGE_PROTOCOL_VERSION, host };\n postToNative({ type: 'usa:ready', version: BRIDGE_PROTOCOL_VERSION }, channel);\n postToNative({ type: 'usa:request-settings' }, channel);\n return {\n host,\n disconnect: () => {\n w.chrome?.webview?.removeEventListener?.('message', onMessage);\n w.removeEventListener?.('message', onMessage);\n w.usaNative = prev;\n },\n };\n}\n"],"names":[],"mappings":"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"}