@rdlabo/capacitor-native-ui 1.2.1 → 2.0.0-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.
Files changed (67) hide show
  1. package/README.md +38 -25
  2. package/dist/core.d.ts +2 -2
  3. package/dist/native/activation.d.ts.map +1 -1
  4. package/dist/native/activation.js +19 -19
  5. package/dist/native/activation.js.map +1 -1
  6. package/dist/native/definitions.d.ts +22 -40
  7. package/dist/native/definitions.d.ts.map +1 -1
  8. package/dist/native/html.d.ts.map +1 -1
  9. package/dist/native/html.js +10 -1
  10. package/dist/native/html.js.map +1 -1
  11. package/dist/native/index.d.ts +2 -2
  12. package/dist/native/index.d.ts.map +1 -1
  13. package/dist/native/index.js +2 -11
  14. package/dist/native/index.js.map +1 -1
  15. package/dist/native/overlays/controller.js +1 -1
  16. package/dist/native/overlays/controller.js.map +1 -1
  17. package/dist/native/prehide.js +1 -1
  18. package/dist/native/prehide.js.map +1 -1
  19. package/dist/native/runtime.d.ts +1 -1
  20. package/dist/native/runtime.d.ts.map +1 -1
  21. package/dist/native/runtime.js +8 -20
  22. package/dist/native/runtime.js.map +1 -1
  23. package/dist/native/shared/candidate.d.ts +2 -2
  24. package/dist/native/shared/candidate.d.ts.map +1 -1
  25. package/dist/native/shared/candidate.js +2 -2
  26. package/dist/native/shared/candidate.js.map +1 -1
  27. package/dist/native/shared/control-options.d.ts +6 -0
  28. package/dist/native/shared/control-options.d.ts.map +1 -0
  29. package/dist/native/shared/control-options.js +17 -0
  30. package/dist/native/shared/control-options.js.map +1 -0
  31. package/dist/native/shared/toolbar-options.d.ts +6 -2
  32. package/dist/native/shared/toolbar-options.d.ts.map +1 -1
  33. package/dist/native/shared/toolbar-options.js +7 -15
  34. package/dist/native/shared/toolbar-options.js.map +1 -1
  35. package/dist/native/startup.d.ts.map +1 -1
  36. package/dist/native/startup.js +0 -16
  37. package/dist/native/startup.js.map +1 -1
  38. package/dist/native/vertical-bars-web.d.ts.map +1 -1
  39. package/dist/native/vertical-bars-web.js +3 -2
  40. package/dist/native/vertical-bars-web.js.map +1 -1
  41. package/dist/vertical-bars.d.ts +2 -2
  42. package/docs/appearance.md +45 -0
  43. package/docs/configuration.md +106 -74
  44. package/docs/framework-independent.md +35 -10
  45. package/docs/ionic-vertical-bars.md +173 -0
  46. package/docs/migration.md +65 -87
  47. package/docs/native-ui-extensions.md +60 -31
  48. package/docs/native-ui.md +186 -67
  49. package/docs/setup.md +43 -24
  50. package/docs/vertical-bars.md +124 -72
  51. package/ios/Sources/NativeUIPlugin/NativeUIPlugin.swift +1 -1
  52. package/package.json +1 -1
  53. package/src/core.ts +1 -2
  54. package/src/native/activation.ts +13 -22
  55. package/src/native/definitions.ts +40 -90
  56. package/src/native/html.ts +11 -5
  57. package/src/native/index.ts +2 -11
  58. package/src/native/overlays/controller.ts +1 -1
  59. package/src/native/prehide.ts +1 -1
  60. package/src/native/runtime.ts +7 -16
  61. package/src/native/shared/candidate.ts +4 -4
  62. package/src/native/shared/control-options.ts +20 -0
  63. package/src/native/shared/toolbar-options.ts +8 -12
  64. package/src/native/startup.ts +0 -16
  65. package/src/native/vertical-bars-web.ts +4 -2
  66. package/src/vertical-bars.ts +2 -1
  67. package/docs/native-mini-player.md +0 -47
@@ -1 +1 @@
1
- {"version":3,"file":"startup.js","names":["activate"],"sources":["../../src/native/startup.ts"],"sourcesContent":["import { enableNativeUI as activate } from './activation';\nimport type { NativeUIRuntimeOptions, NativeUIHandle, NativeUIOptions, NativeUIRuntimeHandle } from './definitions';\n\ntype OverlayFactory = Parameters<typeof activate>[1];\nconst handles = new WeakMap<NativeUIRuntimeHandle, NativeUIHandle>();\n\n/** Start one shell. Partial options override defaults; markup owns individual placement. */\nexport const startNativeUI = async (input: NativeUIOptions = {}, overlayFactory?: OverlayFactory): Promise<NativeUIHandle> => {\n const root = input.root ?? (typeof document === 'undefined' ? undefined : document.body);\n const bars = { enabled: true, ...input.verticalBars };\n const host = bars.placement?.webHost;\n if (root && (!root.isConnected || root.ownerDocument !== document))\n throw new Error('Native UI requires a connected root in the current document');\n if (host && (!host.isConnected || host.ownerDocument !== document || root?.contains(host) || host.contains(root!)))\n throw new Error('The Web rail host must be connected in the current document and outside the source root');\n const legacy = input.controls;\n const automatic = input.ionic?.auto;\n const controls = automatic === undefined ? legacy : typeof automatic === 'object' ? automatic : {};\n const defaultEnabled = automatic !== false;\n const options: NativeUIRuntimeOptions = {\n ...input,\n root,\n source: 'auto',\n explicitControls: automatic !== undefined || (legacy?.buttons ?? legacy?.toolbar ?? true),\n verticalBars: bars,\n controls: {\n ...controls,\n tabs: controls?.tabs ?? defaultEnabled,\n segment: controls?.segment ?? defaultEnabled,\n fab: controls?.fab ?? defaultEnabled,\n toolbar: controls?.buttons ?? (automatic === undefined ? legacy?.toolbar : undefined) ?? defaultEnabled,\n popover: bars.popover ?? legacy?.popover ?? false,\n },\n verticalBarsOnly: bars.only ?? input.verticalBarsOnly ?? false,\n buttonProjection: bars.buttonProjection ?? input.buttonProjection ?? 'system',\n buttonDefaultFill: bars.buttonDefaultFill === 'glass' ? null : (bars.buttonDefaultFill ?? input.buttonDefaultFill ?? null),\n rail: host ? { host, edge: bars.placement?.edge === 'leading' ? 'left' : 'right' } : undefined,\n };\n const runtime = await activate(options, overlayFactory);\n const existing = handles.get(runtime);\n if (existing) return existing;\n let stopped = false;\n let queue = Promise.resolve();\n const change = (enabled: boolean) => {\n const operation = queue.then(async () => {\n if (stopped) throw new Error('Native UI has been destroyed');\n if (bars.enabled === enabled) return;\n // Retire both surfaces before changing ownership. Resume also waits for native reconciliation.\n const lease = await runtime.suspend();\n try {\n if (stopped) throw new Error('Native UI has been destroyed');\n bars.enabled = enabled;\n root?.ownerDocument.defaultView?.dispatchEvent(new Event('nativeUIRefresh'));\n } finally {\n await lease.resume();\n }\n });\n queue = operation.catch(() => {});\n return operation;\n };\n let destruction: Promise<void> | undefined;\n const destroy = runtime.destroy.bind(runtime);\n const handle: NativeUIHandle = {\n markForCheck: runtime.markForCheck.bind(runtime),\n getStatus: runtime.getStatus.bind(runtime),\n suspend: runtime.suspend.bind(runtime),\n enableVerticalControlArea: () => change(true),\n disableVerticalControlArea: () => change(false),\n destroy() {\n if (!destruction) {\n stopped = true;\n // Reserve native teardown immediately, preserving the shared startup queue.\n destruction = destroy();\n }\n return destruction;\n },\n };\n const managed = Object.assign(runtime, handle);\n handles.set(runtime, managed);\n return managed;\n};\n\n/** Enable the shared standard shell without loading the optional Ionic overlay adapter. */\nexport const enableNativeUI = (options: NativeUIOptions = {}): Promise<NativeUIHandle> => startNativeUI(options);\n"],"mappings":";;AAIA,MAAM,0BAAU,IAAI,QAA+C;;AAGnE,MAAa,gBAAgB,OAAO,QAAyB,CAAC,GAAG,mBAA6D;CAC5H,MAAM,OAAO,MAAM,SAAS,OAAO,aAAa,cAAc,KAAA,IAAY,SAAS;CACnF,MAAM,OAAO;EAAE,SAAS;EAAM,GAAG,MAAM;CAAa;CACpD,MAAM,OAAO,KAAK,WAAW;CAC7B,IAAI,SAAS,CAAC,KAAK,eAAe,KAAK,kBAAkB,WACvD,MAAM,IAAI,MAAM,6DAA6D;CAC/E,IAAI,SAAS,CAAC,KAAK,eAAe,KAAK,kBAAkB,YAAY,MAAM,SAAS,IAAI,KAAK,KAAK,SAAS,IAAK,IAC9G,MAAM,IAAI,MAAM,yFAAyF;CAC3G,MAAM,SAAS,MAAM;CACrB,MAAM,YAAY,MAAM,OAAO;CAC/B,MAAM,WAAW,cAAc,KAAA,IAAY,SAAS,OAAO,cAAc,WAAW,YAAY,CAAC;CACjG,MAAM,iBAAiB,cAAc;CACrC,MAAM,UAAkC;EACtC,GAAG;EACH;EACA,QAAQ;EACR,kBAAkB,cAAc,KAAA,MAAc,QAAQ,WAAW,QAAQ,WAAW;EACpF,cAAc;EACd,UAAU;GACR,GAAG;GACH,MAAM,UAAU,QAAQ;GACxB,SAAS,UAAU,WAAW;GAC9B,KAAK,UAAU,OAAO;GACtB,SAAS,UAAU,YAAY,cAAc,KAAA,IAAY,QAAQ,UAAU,KAAA,MAAc;GACzF,SAAS,KAAK,WAAW,QAAQ,WAAW;EAC9C;EACA,kBAAkB,KAAK,QAAQ,MAAM,oBAAoB;EACzD,kBAAkB,KAAK,oBAAoB,MAAM,oBAAoB;EACrE,mBAAmB,KAAK,sBAAsB,UAAU,OAAQ,KAAK,qBAAqB,MAAM,qBAAqB;EACrH,MAAM,OAAO;GAAE;GAAM,MAAM,KAAK,WAAW,SAAS,YAAY,SAAS;EAAQ,IAAI,KAAA;CACvF;CACA,MAAM,UAAU,MAAMA,iBAAS,SAAS,cAAc;CACtD,MAAM,WAAW,QAAQ,IAAI,OAAO;CACpC,IAAI,UAAU,OAAO;CACrB,IAAI,UAAU;CACd,IAAI,QAAQ,QAAQ,QAAQ;CAC5B,MAAM,UAAU,YAAqB;EACnC,MAAM,YAAY,MAAM,KAAK,YAAY;GACvC,IAAI,SAAS,MAAM,IAAI,MAAM,8BAA8B;GAC3D,IAAI,KAAK,YAAY,SAAS;GAE9B,MAAM,QAAQ,MAAM,QAAQ,QAAQ;GACpC,IAAI;IACF,IAAI,SAAS,MAAM,IAAI,MAAM,8BAA8B;IAC3D,KAAK,UAAU;IACf,MAAM,cAAc,aAAa,cAAc,IAAI,MAAM,iBAAiB,CAAC;GAC7E,UAAU;IACR,MAAM,MAAM,OAAO;GACrB;EACF,CAAC;EACD,QAAQ,UAAU,YAAY,CAAC,CAAC;EAChC,OAAO;CACT;CACA,IAAI;CACJ,MAAM,UAAU,QAAQ,QAAQ,KAAK,OAAO;CAC5C,MAAM,SAAyB;EAC7B,cAAc,QAAQ,aAAa,KAAK,OAAO;EAC/C,WAAW,QAAQ,UAAU,KAAK,OAAO;EACzC,SAAS,QAAQ,QAAQ,KAAK,OAAO;EACrC,iCAAiC,OAAO,IAAI;EAC5C,kCAAkC,OAAO,KAAK;EAC9C,UAAU;GACR,IAAI,CAAC,aAAa;IAChB,UAAU;IAEV,cAAc,QAAQ;GACxB;GACA,OAAO;EACT;CACF;CACA,MAAM,UAAU,OAAO,OAAO,SAAS,MAAM;CAC7C,QAAQ,IAAI,SAAS,OAAO;CAC5B,OAAO;AACT;;AAGA,MAAa,kBAAkB,UAA2B,CAAC,MAA+B,cAAc,OAAO"}
1
+ {"version":3,"file":"startup.js","names":["activate"],"sources":["../../src/native/startup.ts"],"sourcesContent":["import { enableNativeUI as activate } from './activation';\nimport type { NativeUIRuntimeOptions, NativeUIHandle, NativeUIOptions, NativeUIRuntimeHandle } from './definitions';\n\ntype OverlayFactory = Parameters<typeof activate>[1];\nconst handles = new WeakMap<NativeUIRuntimeHandle, NativeUIHandle>();\n\n/** Start one shell. Partial options override defaults; markup owns individual placement. */\nexport const startNativeUI = async (input: NativeUIOptions = {}, overlayFactory?: OverlayFactory): Promise<NativeUIHandle> => {\n const root = input.root ?? (typeof document === 'undefined' ? undefined : document.body);\n const bars = { enabled: true, ...input.verticalBars };\n const host = bars.placement?.webHost;\n if (root && (!root.isConnected || root.ownerDocument !== document))\n throw new Error('Native UI requires a connected root in the current document');\n if (host && (!host.isConnected || host.ownerDocument !== document || root?.contains(host) || host.contains(root!)))\n throw new Error('The Web rail host must be connected in the current document and outside the source root');\n const options: NativeUIRuntimeOptions = {\n ...input,\n root,\n source: 'auto',\n verticalBars: bars,\n rail: host ? { host, edge: bars.placement?.edge === 'leading' ? 'left' : 'right' } : undefined,\n };\n const runtime = await activate(options, overlayFactory);\n const existing = handles.get(runtime);\n if (existing) return existing;\n let stopped = false;\n let queue = Promise.resolve();\n const change = (enabled: boolean) => {\n const operation = queue.then(async () => {\n if (stopped) throw new Error('Native UI has been destroyed');\n if (bars.enabled === enabled) return;\n // Retire both surfaces before changing ownership. Resume also waits for native reconciliation.\n const lease = await runtime.suspend();\n try {\n if (stopped) throw new Error('Native UI has been destroyed');\n bars.enabled = enabled;\n root?.ownerDocument.defaultView?.dispatchEvent(new Event('nativeUIRefresh'));\n } finally {\n await lease.resume();\n }\n });\n queue = operation.catch(() => {});\n return operation;\n };\n let destruction: Promise<void> | undefined;\n const destroy = runtime.destroy.bind(runtime);\n const handle: NativeUIHandle = {\n markForCheck: runtime.markForCheck.bind(runtime),\n getStatus: runtime.getStatus.bind(runtime),\n suspend: runtime.suspend.bind(runtime),\n enableVerticalControlArea: () => change(true),\n disableVerticalControlArea: () => change(false),\n destroy() {\n if (!destruction) {\n stopped = true;\n // Reserve native teardown immediately, preserving the shared startup queue.\n destruction = destroy();\n }\n return destruction;\n },\n };\n const managed = Object.assign(runtime, handle);\n handles.set(runtime, managed);\n return managed;\n};\n\n/** Enable the shared standard shell without loading the optional Ionic overlay adapter. */\nexport const enableNativeUI = (options: NativeUIOptions = {}): Promise<NativeUIHandle> => startNativeUI(options);\n"],"mappings":";;AAIA,MAAM,0BAAU,IAAI,QAA+C;;AAGnE,MAAa,gBAAgB,OAAO,QAAyB,CAAC,GAAG,mBAA6D;CAC5H,MAAM,OAAO,MAAM,SAAS,OAAO,aAAa,cAAc,KAAA,IAAY,SAAS;CACnF,MAAM,OAAO;EAAE,SAAS;EAAM,GAAG,MAAM;CAAa;CACpD,MAAM,OAAO,KAAK,WAAW;CAC7B,IAAI,SAAS,CAAC,KAAK,eAAe,KAAK,kBAAkB,WACvD,MAAM,IAAI,MAAM,6DAA6D;CAC/E,IAAI,SAAS,CAAC,KAAK,eAAe,KAAK,kBAAkB,YAAY,MAAM,SAAS,IAAI,KAAK,KAAK,SAAS,IAAK,IAC9G,MAAM,IAAI,MAAM,yFAAyF;CAC3G,MAAM,UAAkC;EACtC,GAAG;EACH;EACA,QAAQ;EACR,cAAc;EACd,MAAM,OAAO;GAAE;GAAM,MAAM,KAAK,WAAW,SAAS,YAAY,SAAS;EAAQ,IAAI,KAAA;CACvF;CACA,MAAM,UAAU,MAAMA,iBAAS,SAAS,cAAc;CACtD,MAAM,WAAW,QAAQ,IAAI,OAAO;CACpC,IAAI,UAAU,OAAO;CACrB,IAAI,UAAU;CACd,IAAI,QAAQ,QAAQ,QAAQ;CAC5B,MAAM,UAAU,YAAqB;EACnC,MAAM,YAAY,MAAM,KAAK,YAAY;GACvC,IAAI,SAAS,MAAM,IAAI,MAAM,8BAA8B;GAC3D,IAAI,KAAK,YAAY,SAAS;GAE9B,MAAM,QAAQ,MAAM,QAAQ,QAAQ;GACpC,IAAI;IACF,IAAI,SAAS,MAAM,IAAI,MAAM,8BAA8B;IAC3D,KAAK,UAAU;IACf,MAAM,cAAc,aAAa,cAAc,IAAI,MAAM,iBAAiB,CAAC;GAC7E,UAAU;IACR,MAAM,MAAM,OAAO;GACrB;EACF,CAAC;EACD,QAAQ,UAAU,YAAY,CAAC,CAAC;EAChC,OAAO;CACT;CACA,IAAI;CACJ,MAAM,UAAU,QAAQ,QAAQ,KAAK,OAAO;CAC5C,MAAM,SAAyB;EAC7B,cAAc,QAAQ,aAAa,KAAK,OAAO;EAC/C,WAAW,QAAQ,UAAU,KAAK,OAAO;EACzC,SAAS,QAAQ,QAAQ,KAAK,OAAO;EACrC,iCAAiC,OAAO,IAAI;EAC5C,kCAAkC,OAAO,KAAK;EAC9C,UAAU;GACR,IAAI,CAAC,aAAa;IAChB,UAAU;IAEV,cAAc,QAAQ;GACxB;GACA,OAAO;EACT;CACF;CACA,MAAM,UAAU,OAAO,OAAO,SAAS,MAAM;CAC7C,QAAQ,IAAI,SAAS,OAAO;CAC5B,OAAO;AACT;;AAGA,MAAa,kBAAkB,UAA2B,CAAC,MAA+B,cAAc,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"vertical-bars-web.d.ts","names":[],"sources":["../../src/native/vertical-bars-web.ts"],"mappings":";;qBA4Ca,kCACX,KAAK,UACL,SAAS,iBACT,4BACC"}
1
+ {"version":3,"file":"vertical-bars-web.d.ts","names":[],"sources":["../../src/native/vertical-bars-web.ts"],"mappings":";;qBA6Ca,kCACX,KAAK,UACL,SAAS,iBACT,4BACC"}
@@ -1,3 +1,4 @@
1
+ import { controlSelected } from "./shared/control-options.js";
1
2
  import { inVerticalBarsSurface, topModal } from "./shared/modal.js";
2
3
  import { createCrossfade } from "./shared/crossfade.js";
3
4
  import { activateProjectedElement, createVerticalBarsPageState, isExcluded, isNativeUIDisabled, isVerticalBarsToolbarGroup, marker, preferredVerticalBarsBack, prehiddenClass, prehideOnlyMutation, syncToolbarText, unprojected, verticalBarsActionCandidate, verticalBarsBackCandidate, verticalBarsEnteringPage, verticalBarsOwned, verticalBarsToolbarActions, withoutPrehide } from "./shared/dom.js";
@@ -14,7 +15,7 @@ const createVerticalBarsWebProjection = (doc, options, enabled = () => true) =>
14
15
  const win = doc.defaultView;
15
16
  const crossfade = createCrossfade(win);
16
17
  let incomingInstant;
17
- const toolbarEnabled = options.controls === void 0 || options.controls.toolbar === true;
18
+ const toolbarEnabled = options.ionic?.auto !== false;
18
19
  let root;
19
20
  let backSource;
20
21
  let backProjection;
@@ -40,7 +41,7 @@ const createVerticalBarsWebProjection = (doc, options, enabled = () => true) =>
40
41
  const rect = element.getBoundingClientRect();
41
42
  return element.isConnected && style.display !== "none" && style.visibility === "visible" && rect.width > 0 && rect.height > 0;
42
43
  });
43
- const search = createVerticalBarsWebSearch(doc, (element) => (options.controls === void 0 || options.controls.tabs === true) && !!verticalBarsRoot()?.contains(element) && (!options.root || options.root.contains(element)) && !element.closest("[data-native-ui-placement=\"element\"]") && inVerticalBarsSurface(element) && !isExcluded(element, verticalBarsEnteringPage(element)) && !isNativeUIDisabled(element) && !verticalBarsPages.isDeparted(element) && isRendered(element), () => {
44
+ const search = createVerticalBarsWebSearch(doc, (element) => options.ionic?.auto !== false && controlSelected(element, options, "tabs", true) && !!verticalBarsRoot()?.contains(element) && (!options.root || options.root.contains(element)) && !element.closest("[data-native-ui-placement=\"element\"]") && inVerticalBarsSurface(element) && !isExcluded(element, verticalBarsEnteringPage(element)) && !isNativeUIDisabled(element) && !verticalBarsPages.isDeparted(element) && isRendered(element), () => {
44
45
  schedule();
45
46
  });
46
47
  const inEligibleToolbar = (element) => !!verticalBarsRoot()?.contains(element) && (!options.root || options.root.contains(element)) && !element.closest("[data-native-ui-placement=\"element\"]") && inVerticalBarsSurface(element) && verticalBarsActionCandidate(element) && !isExcluded(element, verticalBarsEnteringPage(element)) && !verticalBarsPages.isDeparted(element);
@@ -1 +1 @@
1
- {"version":3,"file":"vertical-bars-web.js","names":[],"sources":["../../src/native/vertical-bars-web.ts"],"sourcesContent":["import { createCrossfade, fadeMarker } from './shared/crossfade';\nimport { alignVerticalBarClone, verticalBarFrame } from './shared/vertical-bars-geometry';\nimport { createVerticalBarsWebSearch, searchProjectionClass } from './vertical-bars-web-search';\nimport { inVerticalBarsSurface, topModal } from './shared/modal';\nimport type { NativeUIRuntimeHandle, NativeUIOptions, NativeUIStatus } from './definitions';\nimport { VERTICAL_BARS_TRANSITION_CANCELED } from '../native-integration';\nimport {\n activateProjectedElement,\n createVerticalBarsPageState,\n verticalBarsActionCandidate,\n verticalBarsBackCandidate,\n verticalBarsEnteringPage,\n verticalBarsToolbarActions,\n isExcluded,\n isNativeUIDisabled,\n isVerticalBarsToolbarGroup,\n preferredVerticalBarsBack,\n verticalBarsOwned,\n marker,\n syncToolbarText,\n toolbarTextMarker,\n prehideOnlyMutation,\n prehiddenClass,\n unprojected,\n withoutPrehide,\n} from './shared/dom';\n\nconst backProjectionClass = 'ios-theme-vertical-bars-back-button-projection';\nconst toolbarProjectionClass = 'ios-theme-vertical-bars-toolbar-projection';\nconst readyClass = 'ios-theme-vertical-bars-toolbar-ready';\nconst toolbarControlSize = 46;\nconst toolbarControlGap = 10;\n\ninterface ToolbarProjection {\n source: HTMLElement;\n projection: HTMLElement;\n actions: { source: HTMLElement; projection: HTMLElement; previousAriaHidden: string | null }[];\n}\n\ninterface ToolbarSource {\n group: HTMLElement;\n actions: HTMLElement[];\n}\n\nexport const createVerticalBarsWebProjection = (\n doc: Document,\n options: NativeUIOptions,\n enabled: () => boolean = () => true,\n): NativeUIRuntimeHandle => {\n const win = doc.defaultView!;\n const crossfade = createCrossfade(win);\n let incomingInstant: boolean | undefined;\n const toolbarEnabled = options.controls === undefined || options.controls.toolbar === true;\n let root: HTMLElement | undefined;\n let backSource: HTMLIonBackButtonElement | undefined;\n let backProjection: HTMLIonBackButtonElement | undefined;\n let previousBackAriaHidden: string | null = null;\n let toolbarProjections: ToolbarProjection[] = [];\n let suspended = 0;\n let stopped = false;\n let frame = 0;\n let updates = 0;\n let observingVerticalBars = false;\n const verticalBarsPages = createVerticalBarsPageState();\n let sourceObserver: MutationObserver | undefined;\n let waiters: (() => void)[] = [];\n const listeners = new AbortController();\n const verticalBarsRoot = () => doc.querySelector<HTMLElement>('ion-app.ios-theme-vertical-bars');\n const projectedSources = () =>\n [backSource, search.source, ...toolbarProjections.flatMap(({ actions }) => actions.map(({ source }) => source))].filter(\n (source): source is HTMLElement => !!source,\n );\n const isRendered = (element: HTMLElement) =>\n withoutPrehide(element, () => {\n const style = getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return element.isConnected && style.display !== 'none' && style.visibility === 'visible' && rect.width > 0 && rect.height > 0;\n });\n const search = createVerticalBarsWebSearch(\n doc,\n (element) =>\n (options.controls === undefined || options.controls.tabs === true) &&\n !!verticalBarsRoot()?.contains(element) &&\n (!options.root || options.root.contains(element)) &&\n !element.closest('[data-native-ui-placement=\"element\"]') &&\n inVerticalBarsSurface(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !isNativeUIDisabled(element) &&\n !verticalBarsPages.isDeparted(element) &&\n isRendered(element),\n () => {\n void schedule();\n },\n );\n const inEligibleToolbar = (element: HTMLElement) =>\n !!verticalBarsRoot()?.contains(element) &&\n (!options.root || options.root.contains(element)) &&\n !element.closest('[data-native-ui-placement=\"element\"]') &&\n inVerticalBarsSurface(element) &&\n verticalBarsActionCandidate(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !verticalBarsPages.isDeparted(element);\n const isEligibleBack = (element: HTMLIonBackButtonElement) =>\n !!verticalBarsRoot()?.contains(element) &&\n (!options.root || options.root.contains(element)) &&\n !element.closest('[data-native-ui-placement=\"element\"]') &&\n inVerticalBarsSurface(element) &&\n verticalBarsOwned(element) &&\n verticalBarsBackCandidate(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !verticalBarsPages.isDeparted(element) &&\n unprojected(projectedSources(), () => isRendered(element));\n const pageOrder = (element: Element) => Array.from(doc.querySelectorAll('.ion-page')).indexOf(element.closest('.ion-page')!);\n const findBack = () => {\n const candidates = Array.from(doc.querySelectorAll<HTMLIonBackButtonElement>(`ion-back-button:not(.${backProjectionClass})`)).filter(\n isEligibleBack,\n );\n return preferredVerticalBarsBack(candidates, doc);\n };\n const findToolbarGroups = () => {\n const candidates = Array.from(doc.querySelectorAll<HTMLIonButtonsElement>(`ion-buttons:not(.${toolbarProjectionClass})`)).flatMap(\n (group): ToolbarSource[] => {\n const actions = verticalBarsToolbarActions(group).filter((action) => unprojected(projectedSources(), () => isRendered(action)));\n if (!actions.length) return [];\n if (!isVerticalBarsToolbarGroup(group)) return actions.filter(inEligibleToolbar).map((action) => ({ group, actions: [action] }));\n return inEligibleToolbar(group) && unprojected(projectedSources(), () => isRendered(group)) ? [{ group, actions }] : [];\n },\n );\n for (const action of Array.from(doc.querySelectorAll<HTMLElement>('ion-button, ion-menu-button'))) {\n if (action.closest('ion-buttons') || !verticalBarsOwned(action) || !inEligibleToolbar(action)) continue;\n if (unprojected(projectedSources(), () => isRendered(action))) candidates.push({ group: action, actions: [action] });\n }\n const highestPage = Math.max(...candidates.map(({ group }) => pageOrder(group)));\n return candidates.filter(({ group }) => pageOrder(group) === highestPage);\n };\n const isCurrentToolbarAction = (source: HTMLElement) => findToolbarGroups().some(({ actions }) => actions.includes(source));\n const restore = (retire?: (surface: HTMLElement) => void) => {\n search.restore(retire);\n if (backProjection) {\n if (retire) retire(backProjection);\n else backProjection.remove();\n }\n backProjection = undefined;\n if (backSource) {\n backSource.removeAttribute(marker);\n if (previousBackAriaHidden === null) backSource.removeAttribute('aria-hidden');\n else backSource.setAttribute('aria-hidden', previousBackAriaHidden);\n backSource.dispatchEvent(new CustomEvent('nativeUIChange'));\n }\n backSource = undefined;\n previousBackAriaHidden = null;\n for (const { projection, actions } of toolbarProjections) {\n if (retire) retire(projection);\n else projection.remove();\n for (const { source, previousAriaHidden } of actions) {\n source.removeAttribute(marker);\n if (previousAriaHidden === null) source.removeAttribute('aria-hidden');\n else source.setAttribute('aria-hidden', previousAriaHidden);\n source.dispatchEvent(new CustomEvent('nativeUIChange'));\n }\n }\n toolbarProjections = [];\n sourceObserver?.disconnect();\n sourceObserver = undefined;\n root?.classList.remove(readyClass);\n root = undefined;\n };\n const copyAttributes = (target: HTMLElement, original: HTMLElement) => {\n for (const name of ['id', 'slot', marker, 'aria-hidden']) target.removeAttribute(name);\n for (const attribute of Array.from(target.attributes))\n if (!['class', marker, fadeMarker].includes(attribute.name) && !original.hasAttribute(attribute.name))\n target.removeAttribute(attribute.name);\n for (const attribute of Array.from(original.attributes))\n if (!['id', 'slot', marker, 'aria-hidden'].includes(attribute.name)) target.setAttribute(attribute.name, attribute.value);\n target.classList.remove(prehiddenClass);\n };\n const syncBack = (target: HTMLIonBackButtonElement, original: HTMLIonBackButtonElement) => {\n copyAttributes(target, original);\n target.classList.add(backProjectionClass, 'ion-cloned-element');\n target.disabled = original.disabled;\n target.defaultHref = original.defaultHref;\n target.icon = original.icon;\n target.color = original.color;\n target.mode = original.mode;\n target.text = '';\n if (root) alignVerticalBarClone(target, original, root);\n };\n const syncAction = (target: HTMLElement, original: HTMLElement) => {\n copyAttributes(target, original);\n target.classList.add('ios-theme-vertical-bars-toolbar-action', 'ion-cloned-element');\n const label =\n original.getAttribute('aria-label') ??\n original.shadowRoot?.querySelector('[part~=native]')?.getAttribute('aria-label') ??\n original.textContent?.trim();\n if (label) target.setAttribute('aria-label', label);\n if ('disabled' in original) (target as HTMLIonButtonElement).disabled = (original as HTMLIonButtonElement).disabled;\n if (original.matches('ion-button')) {\n const icon = original.querySelector<HTMLElement>('ion-icon, svg');\n const clonedIcon = icon?.cloneNode(true) as HTMLElement | undefined;\n clonedIcon?.setAttribute('slot', 'icon-only');\n target.replaceChildren(...(clonedIcon ? [clonedIcon] : [document.createTextNode(original.textContent?.trim() || label || '')]));\n }\n };\n const sameSources = (back: HTMLIonBackButtonElement | undefined, groups: ToolbarSource[]) =>\n back === backSource &&\n groups.length === toolbarProjections.length &&\n groups.every(({ group, actions }, index) => {\n const current = toolbarProjections[index];\n return (\n group === current.source &&\n actions.length === current.actions.length &&\n actions.every((action, actionIndex) => action === current.actions[actionIndex].source)\n );\n });\n const syncExisting = () => {\n if (backSource && backProjection) syncBack(backProjection, backSource);\n let topOffset = backSource ? toolbarControlSize + toolbarControlGap : 0;\n for (const { projection, source, actions } of toolbarProjections) {\n if (actions.length === 1 && !projection.matches('ion-buttons')) syncAction(projection, actions[0].source);\n else copyAttributes(projection, source);\n projection.classList.add(toolbarProjectionClass, 'ion-cloned-element');\n projection.style.setProperty('--ios-theme-vertical-bars-toolbar-offset', `${topOffset}px`);\n if (projection.matches('ion-buttons')) actions.forEach(({ source: action, projection: clone }) => syncAction(clone, action));\n const frames = actions.map(({ source }) => verticalBarFrame(source));\n if (root && frames.every((frame) => !!frame)) {\n if (actions.length === 1) alignVerticalBarClone(projection, actions[0].source, root);\n else {\n const left = Math.min(...frames.map((frame) => frame!.x));\n const top = Math.min(...frames.map((frame) => frame!.y));\n const right = Math.max(...frames.map((frame) => frame!.x + frame!.width));\n const bottom = Math.max(...frames.map((frame) => frame!.y + frame!.height));\n const origin = root.getBoundingClientRect();\n Object.assign(projection.style, {\n left: `${left - origin.left}px`,\n top: `${top - origin.top}px`,\n right: 'auto',\n bottom: 'auto',\n width: `${right - left}px`,\n height: `${bottom - top}px`,\n padding: '0',\n });\n actions.forEach(({ source, projection: clone }) => alignVerticalBarClone(clone, source, projection));\n }\n }\n topOffset += actions.length * toolbarControlSize + toolbarControlGap;\n }\n };\n const project = (nextBack: HTMLIonBackButtonElement | undefined, groups: ToolbarSource[]) => {\n root = topModal(doc) ?? verticalBarsRoot()!;\n let topOffset = 0;\n if (nextBack) {\n backSource = nextBack;\n previousBackAriaHidden = nextBack.getAttribute('aria-hidden');\n backProjection = nextBack.cloneNode(false) as HTMLIonBackButtonElement;\n syncBack(backProjection, nextBack);\n backProjection.addEventListener(\n 'click',\n (event) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n if (backSource && backSource === findBack()) activateProjectedElement(backSource);\n },\n { capture: true },\n );\n root.append(backProjection);\n nextBack.setAttribute(marker, '');\n nextBack.setAttribute('aria-hidden', 'true');\n nextBack.dispatchEvent(new CustomEvent('nativeUIChange'));\n topOffset = toolbarControlSize + toolbarControlGap;\n }\n for (const { group, actions: sources } of groups) {\n const projection = (sources.length === 1 ? sources[0] : group).cloneNode(false) as HTMLElement;\n if (sources.length === 1) syncAction(projection, sources[0]);\n else copyAttributes(projection, group);\n projection.classList.add(toolbarProjectionClass, 'ion-cloned-element');\n projection.style.setProperty('--ios-theme-vertical-bars-toolbar-offset', `${topOffset}px`);\n const actions = sources.map((source) => {\n const clone = sources.length === 1 ? projection : (source.cloneNode(false) as HTMLElement);\n if (sources.length > 1) syncAction(clone, source);\n clone.addEventListener(\n 'click',\n (event) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n if (isCurrentToolbarAction(source)) activateProjectedElement(source);\n },\n { capture: true },\n );\n if (sources.length > 1) projection.append(clone);\n const previousAriaHidden = source.getAttribute('aria-hidden');\n source.setAttribute(marker, '');\n source.setAttribute('aria-hidden', 'true');\n source.dispatchEvent(new CustomEvent('nativeUIChange'));\n return { source, projection: clone, previousAriaHidden };\n });\n root.append(projection);\n toolbarProjections.push({ source: group, projection, actions });\n topOffset += actions.length * toolbarControlSize + toolbarControlGap;\n }\n syncExisting();\n if (nextBack || toolbarProjections.length) root.classList.add(readyClass);\n sourceObserver = new MutationObserver((records) => {\n if (\n records.some(\n (record) =>\n record.type !== 'attributes' || (![marker, 'aria-hidden'].includes(record.attributeName ?? '') && !prehideOnlyMutation(record)),\n )\n )\n schedule();\n });\n if (nextBack?.shadowRoot)\n sourceObserver.observe(nextBack.shadowRoot, { subtree: true, childList: true, attributes: true, attributeOldValue: true });\n for (const { group } of groups)\n sourceObserver.observe(group, { subtree: true, childList: true, attributes: true, attributeOldValue: true });\n };\n const reveal = () => {\n if (incomingInstant === undefined) return;\n for (const surface of [backProjection, ...toolbarProjections.map(({ projection }) => projection), search.surface])\n if (surface) crossfade.play(surface, false, incomingInstant);\n incomingInstant = undefined;\n };\n const performUpdate = () => {\n frame = 0;\n syncToolbarText(doc);\n const currentRoot = verticalBarsRoot();\n if (observingVerticalBars !== !!currentRoot) {\n observingVerticalBars = !!currentRoot;\n observer.disconnect();\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n characterData: observingVerticalBars,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: observingVerticalBars ? undefined : ['class'],\n });\n }\n if (stopped || suspended || !currentRoot || !enabled()) return restore();\n const nextBack = toolbarEnabled ? findBack() : undefined;\n const groups = toolbarEnabled ? findToolbarGroups() : [];\n const projectionRoot = topModal(doc) ?? currentRoot;\n search.update(projectionRoot);\n if (!nextBack && !groups.length && !search.source) return restore();\n if (root === (topModal(doc) ?? currentRoot) && sameSources(nextBack, groups)) {\n syncExisting();\n reveal();\n return;\n }\n restore();\n project(nextBack, groups);\n search.update(projectionRoot);\n reveal();\n updates++;\n };\n const update = () => {\n try {\n performUpdate();\n } catch {\n restore();\n } finally {\n const pending = waiters;\n waiters = [];\n pending.forEach((resolve) => resolve());\n }\n };\n const schedule = (): Promise<void> => {\n if (stopped) return Promise.resolve();\n // Release Web ownership before the native runtime can acknowledge its next frame.\n if (!enabled()) restore();\n const done = new Promise<void>((resolve) => waiters.push(resolve));\n if (!frame) frame = win.requestAnimationFrame(update);\n return done;\n };\n const observer = new MutationObserver((records) => {\n const insideProjection = (target: Node) => {\n const element = target instanceof Element ? target : target.parentNode instanceof Element ? target.parentNode : undefined;\n const rootNode = target.getRootNode();\n const shadowHost = rootNode instanceof ShadowRoot ? rootNode.host : undefined;\n return !![element, shadowHost].some((candidate) =>\n candidate?.closest(`.${backProjectionClass}, .${toolbarProjectionClass}, .${searchProjectionClass}`),\n );\n };\n const verticalBarsChanged = records.some(\n (record) =>\n (record.type === 'attributes' && (record.target as Element).matches('ion-app')) ||\n (record.type === 'childList' &&\n Array.from(record.addedNodes).some(\n (node) =>\n node instanceof Element &&\n (node.matches('ion-app.ios-theme-vertical-bars') || !!node.querySelector('ion-app.ios-theme-vertical-bars')),\n )),\n );\n if (\n (observingVerticalBars &&\n records.some(\n (record) =>\n record.attributeName !== marker &&\n record.attributeName !== toolbarTextMarker &&\n !prehideOnlyMutation(record) &&\n !insideProjection(record.target),\n )) ||\n (!observingVerticalBars && verticalBarsChanged && records.some((record) => !prehideOnlyMutation(record)))\n )\n schedule();\n });\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: ['class'],\n });\n const pageLifecycle = (event: Event) => {\n const page = event.target;\n if (!(page instanceof HTMLElement) || !page.matches('.ion-page')) return;\n if (event.type === VERTICAL_BARS_TRANSITION_CANCELED) {\n const entering = (event as CustomEvent<{ entering?: HTMLElement }>).detail?.entering;\n verticalBarsPages.cancel(entering, page);\n } else verticalBarsPages.lifecycle(event);\n if (verticalBarsRoot()) schedule();\n };\n for (const name of ['ionViewWillEnter', 'ionViewWillLeave', 'ionViewDidEnter', 'ionViewDidLeave'])\n doc.addEventListener(name, pageLifecycle, { capture: true, signal: listeners.signal });\n doc.addEventListener(VERTICAL_BARS_TRANSITION_CANCELED, pageLifecycle, { capture: true, signal: listeners.signal });\n for (const name of ['ionModalWillPresent', 'ionModalDidDismiss'])\n doc.addEventListener(name, schedule, { capture: true, signal: listeners.signal });\n win.addEventListener(\n 'nativeUIVerticalBarsAcquire',\n (event) => {\n const instant = (event as CustomEvent<{ instant: boolean }>).detail?.instant ?? true;\n incomingInstant = undefined;\n restore((surface) => {\n // Keep only the outgoing visual at its last rectangle after Web ownership\n // is released. The native acknowledgement transfers input exactly once.\n const box = surface.getBoundingClientRect();\n surface.style.setProperty('position', 'fixed', 'important');\n surface.style.setProperty('display', 'block', 'important');\n surface.style.setProperty('left', `${box.left}px`, 'important');\n surface.style.setProperty('top', `${box.top}px`, 'important');\n surface.style.setProperty('right', 'auto', 'important');\n surface.style.setProperty('bottom', 'auto', 'important');\n surface.style.setProperty('width', `${box.width}px`, 'important');\n surface.style.setProperty('height', `${box.height}px`, 'important');\n crossfade.retire(surface, instant);\n });\n },\n { signal: listeners.signal },\n );\n win.addEventListener(\n 'nativeUIVerticalBarsRelease',\n (event) => {\n incomingInstant = (event as CustomEvent<{ instant: boolean }>).detail.instant;\n void schedule();\n },\n { signal: listeners.signal },\n );\n win.addEventListener('resize', schedule, { signal: listeners.signal });\n win.addEventListener('nativeUIRefresh', schedule, { signal: listeners.signal });\n schedule();\n\n return {\n markForCheck: () => {\n void schedule();\n },\n getStatus: (): NativeUIStatus => ({\n state: stopped ? 'stopped' : 'web',\n projected:\n Number(!!backSource) + Number(!!search.source) + toolbarProjections.reduce((count, group) => count + group.actions.length, 0),\n updates,\n }),\n async suspend() {\n suspended++;\n restore();\n let resumed = false;\n return {\n async resume() {\n if (resumed) return;\n resumed = true;\n suspended = Math.max(0, suspended - 1);\n if (!suspended) await schedule();\n },\n };\n },\n async destroy() {\n if (stopped) return;\n stopped = true;\n win.cancelAnimationFrame(frame);\n frame = 0;\n waiters.forEach((resolve) => resolve());\n waiters = [];\n observer.disconnect();\n sourceObserver?.disconnect();\n listeners.abort();\n crossfade.destroy();\n restore();\n },\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"vertical-bars-web.js","names":[],"sources":["../../src/native/vertical-bars-web.ts"],"sourcesContent":["import { controlSelected } from './shared/control-options';\nimport { createCrossfade, fadeMarker } from './shared/crossfade';\nimport { alignVerticalBarClone, verticalBarFrame } from './shared/vertical-bars-geometry';\nimport { createVerticalBarsWebSearch, searchProjectionClass } from './vertical-bars-web-search';\nimport { inVerticalBarsSurface, topModal } from './shared/modal';\nimport type { NativeUIRuntimeHandle, NativeUIOptions, NativeUIStatus } from './definitions';\nimport { VERTICAL_BARS_TRANSITION_CANCELED } from '../native-integration';\nimport {\n activateProjectedElement,\n createVerticalBarsPageState,\n verticalBarsActionCandidate,\n verticalBarsBackCandidate,\n verticalBarsEnteringPage,\n verticalBarsToolbarActions,\n isExcluded,\n isNativeUIDisabled,\n isVerticalBarsToolbarGroup,\n preferredVerticalBarsBack,\n verticalBarsOwned,\n marker,\n syncToolbarText,\n toolbarTextMarker,\n prehideOnlyMutation,\n prehiddenClass,\n unprojected,\n withoutPrehide,\n} from './shared/dom';\n\nconst backProjectionClass = 'ios-theme-vertical-bars-back-button-projection';\nconst toolbarProjectionClass = 'ios-theme-vertical-bars-toolbar-projection';\nconst readyClass = 'ios-theme-vertical-bars-toolbar-ready';\nconst toolbarControlSize = 46;\nconst toolbarControlGap = 10;\n\ninterface ToolbarProjection {\n source: HTMLElement;\n projection: HTMLElement;\n actions: { source: HTMLElement; projection: HTMLElement; previousAriaHidden: string | null }[];\n}\n\ninterface ToolbarSource {\n group: HTMLElement;\n actions: HTMLElement[];\n}\n\nexport const createVerticalBarsWebProjection = (\n doc: Document,\n options: NativeUIOptions,\n enabled: () => boolean = () => true,\n): NativeUIRuntimeHandle => {\n const win = doc.defaultView!;\n const crossfade = createCrossfade(win);\n let incomingInstant: boolean | undefined;\n const toolbarEnabled = options.ionic?.auto !== false;\n let root: HTMLElement | undefined;\n let backSource: HTMLIonBackButtonElement | undefined;\n let backProjection: HTMLIonBackButtonElement | undefined;\n let previousBackAriaHidden: string | null = null;\n let toolbarProjections: ToolbarProjection[] = [];\n let suspended = 0;\n let stopped = false;\n let frame = 0;\n let updates = 0;\n let observingVerticalBars = false;\n const verticalBarsPages = createVerticalBarsPageState();\n let sourceObserver: MutationObserver | undefined;\n let waiters: (() => void)[] = [];\n const listeners = new AbortController();\n const verticalBarsRoot = () => doc.querySelector<HTMLElement>('ion-app.ios-theme-vertical-bars');\n const projectedSources = () =>\n [backSource, search.source, ...toolbarProjections.flatMap(({ actions }) => actions.map(({ source }) => source))].filter(\n (source): source is HTMLElement => !!source,\n );\n const isRendered = (element: HTMLElement) =>\n withoutPrehide(element, () => {\n const style = getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return element.isConnected && style.display !== 'none' && style.visibility === 'visible' && rect.width > 0 && rect.height > 0;\n });\n const search = createVerticalBarsWebSearch(\n doc,\n (element) =>\n options.ionic?.auto !== false &&\n controlSelected(element, options, 'tabs', true) &&\n !!verticalBarsRoot()?.contains(element) &&\n (!options.root || options.root.contains(element)) &&\n !element.closest('[data-native-ui-placement=\"element\"]') &&\n inVerticalBarsSurface(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !isNativeUIDisabled(element) &&\n !verticalBarsPages.isDeparted(element) &&\n isRendered(element),\n () => {\n void schedule();\n },\n );\n const inEligibleToolbar = (element: HTMLElement) =>\n !!verticalBarsRoot()?.contains(element) &&\n (!options.root || options.root.contains(element)) &&\n !element.closest('[data-native-ui-placement=\"element\"]') &&\n inVerticalBarsSurface(element) &&\n verticalBarsActionCandidate(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !verticalBarsPages.isDeparted(element);\n const isEligibleBack = (element: HTMLIonBackButtonElement) =>\n !!verticalBarsRoot()?.contains(element) &&\n (!options.root || options.root.contains(element)) &&\n !element.closest('[data-native-ui-placement=\"element\"]') &&\n inVerticalBarsSurface(element) &&\n verticalBarsOwned(element) &&\n verticalBarsBackCandidate(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !verticalBarsPages.isDeparted(element) &&\n unprojected(projectedSources(), () => isRendered(element));\n const pageOrder = (element: Element) => Array.from(doc.querySelectorAll('.ion-page')).indexOf(element.closest('.ion-page')!);\n const findBack = () => {\n const candidates = Array.from(doc.querySelectorAll<HTMLIonBackButtonElement>(`ion-back-button:not(.${backProjectionClass})`)).filter(\n isEligibleBack,\n );\n return preferredVerticalBarsBack(candidates, doc);\n };\n const findToolbarGroups = () => {\n const candidates = Array.from(doc.querySelectorAll<HTMLIonButtonsElement>(`ion-buttons:not(.${toolbarProjectionClass})`)).flatMap(\n (group): ToolbarSource[] => {\n const actions = verticalBarsToolbarActions(group).filter((action) => unprojected(projectedSources(), () => isRendered(action)));\n if (!actions.length) return [];\n if (!isVerticalBarsToolbarGroup(group)) return actions.filter(inEligibleToolbar).map((action) => ({ group, actions: [action] }));\n return inEligibleToolbar(group) && unprojected(projectedSources(), () => isRendered(group)) ? [{ group, actions }] : [];\n },\n );\n for (const action of Array.from(doc.querySelectorAll<HTMLElement>('ion-button, ion-menu-button'))) {\n if (action.closest('ion-buttons') || !verticalBarsOwned(action) || !inEligibleToolbar(action)) continue;\n if (unprojected(projectedSources(), () => isRendered(action))) candidates.push({ group: action, actions: [action] });\n }\n const highestPage = Math.max(...candidates.map(({ group }) => pageOrder(group)));\n return candidates.filter(({ group }) => pageOrder(group) === highestPage);\n };\n const isCurrentToolbarAction = (source: HTMLElement) => findToolbarGroups().some(({ actions }) => actions.includes(source));\n const restore = (retire?: (surface: HTMLElement) => void) => {\n search.restore(retire);\n if (backProjection) {\n if (retire) retire(backProjection);\n else backProjection.remove();\n }\n backProjection = undefined;\n if (backSource) {\n backSource.removeAttribute(marker);\n if (previousBackAriaHidden === null) backSource.removeAttribute('aria-hidden');\n else backSource.setAttribute('aria-hidden', previousBackAriaHidden);\n backSource.dispatchEvent(new CustomEvent('nativeUIChange'));\n }\n backSource = undefined;\n previousBackAriaHidden = null;\n for (const { projection, actions } of toolbarProjections) {\n if (retire) retire(projection);\n else projection.remove();\n for (const { source, previousAriaHidden } of actions) {\n source.removeAttribute(marker);\n if (previousAriaHidden === null) source.removeAttribute('aria-hidden');\n else source.setAttribute('aria-hidden', previousAriaHidden);\n source.dispatchEvent(new CustomEvent('nativeUIChange'));\n }\n }\n toolbarProjections = [];\n sourceObserver?.disconnect();\n sourceObserver = undefined;\n root?.classList.remove(readyClass);\n root = undefined;\n };\n const copyAttributes = (target: HTMLElement, original: HTMLElement) => {\n for (const name of ['id', 'slot', marker, 'aria-hidden']) target.removeAttribute(name);\n for (const attribute of Array.from(target.attributes))\n if (!['class', marker, fadeMarker].includes(attribute.name) && !original.hasAttribute(attribute.name))\n target.removeAttribute(attribute.name);\n for (const attribute of Array.from(original.attributes))\n if (!['id', 'slot', marker, 'aria-hidden'].includes(attribute.name)) target.setAttribute(attribute.name, attribute.value);\n target.classList.remove(prehiddenClass);\n };\n const syncBack = (target: HTMLIonBackButtonElement, original: HTMLIonBackButtonElement) => {\n copyAttributes(target, original);\n target.classList.add(backProjectionClass, 'ion-cloned-element');\n target.disabled = original.disabled;\n target.defaultHref = original.defaultHref;\n target.icon = original.icon;\n target.color = original.color;\n target.mode = original.mode;\n target.text = '';\n if (root) alignVerticalBarClone(target, original, root);\n };\n const syncAction = (target: HTMLElement, original: HTMLElement) => {\n copyAttributes(target, original);\n target.classList.add('ios-theme-vertical-bars-toolbar-action', 'ion-cloned-element');\n const label =\n original.getAttribute('aria-label') ??\n original.shadowRoot?.querySelector('[part~=native]')?.getAttribute('aria-label') ??\n original.textContent?.trim();\n if (label) target.setAttribute('aria-label', label);\n if ('disabled' in original) (target as HTMLIonButtonElement).disabled = (original as HTMLIonButtonElement).disabled;\n if (original.matches('ion-button')) {\n const icon = original.querySelector<HTMLElement>('ion-icon, svg');\n const clonedIcon = icon?.cloneNode(true) as HTMLElement | undefined;\n clonedIcon?.setAttribute('slot', 'icon-only');\n target.replaceChildren(...(clonedIcon ? [clonedIcon] : [document.createTextNode(original.textContent?.trim() || label || '')]));\n }\n };\n const sameSources = (back: HTMLIonBackButtonElement | undefined, groups: ToolbarSource[]) =>\n back === backSource &&\n groups.length === toolbarProjections.length &&\n groups.every(({ group, actions }, index) => {\n const current = toolbarProjections[index];\n return (\n group === current.source &&\n actions.length === current.actions.length &&\n actions.every((action, actionIndex) => action === current.actions[actionIndex].source)\n );\n });\n const syncExisting = () => {\n if (backSource && backProjection) syncBack(backProjection, backSource);\n let topOffset = backSource ? toolbarControlSize + toolbarControlGap : 0;\n for (const { projection, source, actions } of toolbarProjections) {\n if (actions.length === 1 && !projection.matches('ion-buttons')) syncAction(projection, actions[0].source);\n else copyAttributes(projection, source);\n projection.classList.add(toolbarProjectionClass, 'ion-cloned-element');\n projection.style.setProperty('--ios-theme-vertical-bars-toolbar-offset', `${topOffset}px`);\n if (projection.matches('ion-buttons')) actions.forEach(({ source: action, projection: clone }) => syncAction(clone, action));\n const frames = actions.map(({ source }) => verticalBarFrame(source));\n if (root && frames.every((frame) => !!frame)) {\n if (actions.length === 1) alignVerticalBarClone(projection, actions[0].source, root);\n else {\n const left = Math.min(...frames.map((frame) => frame!.x));\n const top = Math.min(...frames.map((frame) => frame!.y));\n const right = Math.max(...frames.map((frame) => frame!.x + frame!.width));\n const bottom = Math.max(...frames.map((frame) => frame!.y + frame!.height));\n const origin = root.getBoundingClientRect();\n Object.assign(projection.style, {\n left: `${left - origin.left}px`,\n top: `${top - origin.top}px`,\n right: 'auto',\n bottom: 'auto',\n width: `${right - left}px`,\n height: `${bottom - top}px`,\n padding: '0',\n });\n actions.forEach(({ source, projection: clone }) => alignVerticalBarClone(clone, source, projection));\n }\n }\n topOffset += actions.length * toolbarControlSize + toolbarControlGap;\n }\n };\n const project = (nextBack: HTMLIonBackButtonElement | undefined, groups: ToolbarSource[]) => {\n root = topModal(doc) ?? verticalBarsRoot()!;\n let topOffset = 0;\n if (nextBack) {\n backSource = nextBack;\n previousBackAriaHidden = nextBack.getAttribute('aria-hidden');\n backProjection = nextBack.cloneNode(false) as HTMLIonBackButtonElement;\n syncBack(backProjection, nextBack);\n backProjection.addEventListener(\n 'click',\n (event) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n if (backSource && backSource === findBack()) activateProjectedElement(backSource);\n },\n { capture: true },\n );\n root.append(backProjection);\n nextBack.setAttribute(marker, '');\n nextBack.setAttribute('aria-hidden', 'true');\n nextBack.dispatchEvent(new CustomEvent('nativeUIChange'));\n topOffset = toolbarControlSize + toolbarControlGap;\n }\n for (const { group, actions: sources } of groups) {\n const projection = (sources.length === 1 ? sources[0] : group).cloneNode(false) as HTMLElement;\n if (sources.length === 1) syncAction(projection, sources[0]);\n else copyAttributes(projection, group);\n projection.classList.add(toolbarProjectionClass, 'ion-cloned-element');\n projection.style.setProperty('--ios-theme-vertical-bars-toolbar-offset', `${topOffset}px`);\n const actions = sources.map((source) => {\n const clone = sources.length === 1 ? projection : (source.cloneNode(false) as HTMLElement);\n if (sources.length > 1) syncAction(clone, source);\n clone.addEventListener(\n 'click',\n (event) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n if (isCurrentToolbarAction(source)) activateProjectedElement(source);\n },\n { capture: true },\n );\n if (sources.length > 1) projection.append(clone);\n const previousAriaHidden = source.getAttribute('aria-hidden');\n source.setAttribute(marker, '');\n source.setAttribute('aria-hidden', 'true');\n source.dispatchEvent(new CustomEvent('nativeUIChange'));\n return { source, projection: clone, previousAriaHidden };\n });\n root.append(projection);\n toolbarProjections.push({ source: group, projection, actions });\n topOffset += actions.length * toolbarControlSize + toolbarControlGap;\n }\n syncExisting();\n if (nextBack || toolbarProjections.length) root.classList.add(readyClass);\n sourceObserver = new MutationObserver((records) => {\n if (\n records.some(\n (record) =>\n record.type !== 'attributes' || (![marker, 'aria-hidden'].includes(record.attributeName ?? '') && !prehideOnlyMutation(record)),\n )\n )\n schedule();\n });\n if (nextBack?.shadowRoot)\n sourceObserver.observe(nextBack.shadowRoot, { subtree: true, childList: true, attributes: true, attributeOldValue: true });\n for (const { group } of groups)\n sourceObserver.observe(group, { subtree: true, childList: true, attributes: true, attributeOldValue: true });\n };\n const reveal = () => {\n if (incomingInstant === undefined) return;\n for (const surface of [backProjection, ...toolbarProjections.map(({ projection }) => projection), search.surface])\n if (surface) crossfade.play(surface, false, incomingInstant);\n incomingInstant = undefined;\n };\n const performUpdate = () => {\n frame = 0;\n syncToolbarText(doc);\n const currentRoot = verticalBarsRoot();\n if (observingVerticalBars !== !!currentRoot) {\n observingVerticalBars = !!currentRoot;\n observer.disconnect();\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n characterData: observingVerticalBars,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: observingVerticalBars ? undefined : ['class'],\n });\n }\n if (stopped || suspended || !currentRoot || !enabled()) return restore();\n const nextBack = toolbarEnabled ? findBack() : undefined;\n const groups = toolbarEnabled ? findToolbarGroups() : [];\n const projectionRoot = topModal(doc) ?? currentRoot;\n search.update(projectionRoot);\n if (!nextBack && !groups.length && !search.source) return restore();\n if (root === (topModal(doc) ?? currentRoot) && sameSources(nextBack, groups)) {\n syncExisting();\n reveal();\n return;\n }\n restore();\n project(nextBack, groups);\n search.update(projectionRoot);\n reveal();\n updates++;\n };\n const update = () => {\n try {\n performUpdate();\n } catch {\n restore();\n } finally {\n const pending = waiters;\n waiters = [];\n pending.forEach((resolve) => resolve());\n }\n };\n const schedule = (): Promise<void> => {\n if (stopped) return Promise.resolve();\n // Release Web ownership before the native runtime can acknowledge its next frame.\n if (!enabled()) restore();\n const done = new Promise<void>((resolve) => waiters.push(resolve));\n if (!frame) frame = win.requestAnimationFrame(update);\n return done;\n };\n const observer = new MutationObserver((records) => {\n const insideProjection = (target: Node) => {\n const element = target instanceof Element ? target : target.parentNode instanceof Element ? target.parentNode : undefined;\n const rootNode = target.getRootNode();\n const shadowHost = rootNode instanceof ShadowRoot ? rootNode.host : undefined;\n return !![element, shadowHost].some((candidate) =>\n candidate?.closest(`.${backProjectionClass}, .${toolbarProjectionClass}, .${searchProjectionClass}`),\n );\n };\n const verticalBarsChanged = records.some(\n (record) =>\n (record.type === 'attributes' && (record.target as Element).matches('ion-app')) ||\n (record.type === 'childList' &&\n Array.from(record.addedNodes).some(\n (node) =>\n node instanceof Element &&\n (node.matches('ion-app.ios-theme-vertical-bars') || !!node.querySelector('ion-app.ios-theme-vertical-bars')),\n )),\n );\n if (\n (observingVerticalBars &&\n records.some(\n (record) =>\n record.attributeName !== marker &&\n record.attributeName !== toolbarTextMarker &&\n !prehideOnlyMutation(record) &&\n !insideProjection(record.target),\n )) ||\n (!observingVerticalBars && verticalBarsChanged && records.some((record) => !prehideOnlyMutation(record)))\n )\n schedule();\n });\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: ['class'],\n });\n const pageLifecycle = (event: Event) => {\n const page = event.target;\n if (!(page instanceof HTMLElement) || !page.matches('.ion-page')) return;\n if (event.type === VERTICAL_BARS_TRANSITION_CANCELED) {\n const entering = (event as CustomEvent<{ entering?: HTMLElement }>).detail?.entering;\n verticalBarsPages.cancel(entering, page);\n } else verticalBarsPages.lifecycle(event);\n if (verticalBarsRoot()) schedule();\n };\n for (const name of ['ionViewWillEnter', 'ionViewWillLeave', 'ionViewDidEnter', 'ionViewDidLeave'])\n doc.addEventListener(name, pageLifecycle, { capture: true, signal: listeners.signal });\n doc.addEventListener(VERTICAL_BARS_TRANSITION_CANCELED, pageLifecycle, { capture: true, signal: listeners.signal });\n for (const name of ['ionModalWillPresent', 'ionModalDidDismiss'])\n doc.addEventListener(name, schedule, { capture: true, signal: listeners.signal });\n win.addEventListener(\n 'nativeUIVerticalBarsAcquire',\n (event) => {\n const instant = (event as CustomEvent<{ instant: boolean }>).detail?.instant ?? true;\n incomingInstant = undefined;\n restore((surface) => {\n // Keep only the outgoing visual at its last rectangle after Web ownership\n // is released. The native acknowledgement transfers input exactly once.\n const box = surface.getBoundingClientRect();\n surface.style.setProperty('position', 'fixed', 'important');\n surface.style.setProperty('display', 'block', 'important');\n surface.style.setProperty('left', `${box.left}px`, 'important');\n surface.style.setProperty('top', `${box.top}px`, 'important');\n surface.style.setProperty('right', 'auto', 'important');\n surface.style.setProperty('bottom', 'auto', 'important');\n surface.style.setProperty('width', `${box.width}px`, 'important');\n surface.style.setProperty('height', `${box.height}px`, 'important');\n crossfade.retire(surface, instant);\n });\n },\n { signal: listeners.signal },\n );\n win.addEventListener(\n 'nativeUIVerticalBarsRelease',\n (event) => {\n incomingInstant = (event as CustomEvent<{ instant: boolean }>).detail.instant;\n void schedule();\n },\n { signal: listeners.signal },\n );\n win.addEventListener('resize', schedule, { signal: listeners.signal });\n win.addEventListener('nativeUIRefresh', schedule, { signal: listeners.signal });\n schedule();\n\n return {\n markForCheck: () => {\n void schedule();\n },\n getStatus: (): NativeUIStatus => ({\n state: stopped ? 'stopped' : 'web',\n projected:\n Number(!!backSource) + Number(!!search.source) + toolbarProjections.reduce((count, group) => count + group.actions.length, 0),\n updates,\n }),\n async suspend() {\n suspended++;\n restore();\n let resumed = false;\n return {\n async resume() {\n if (resumed) return;\n resumed = true;\n suspended = Math.max(0, suspended - 1);\n if (!suspended) await schedule();\n },\n };\n },\n async destroy() {\n if (stopped) return;\n stopped = true;\n win.cancelAnimationFrame(frame);\n frame = 0;\n waiters.forEach((resolve) => resolve());\n waiters = [];\n observer.disconnect();\n sourceObserver?.disconnect();\n listeners.abort();\n crossfade.destroy();\n restore();\n },\n };\n};\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { NativeUIStatus, NativeUISuspension, ToolbarProjectionOptions, VerticalBarEdge, VerticalControlAreaHandle, VerticalControlAreaOptions } from "./native/definitions.js";
1
+ import { ControlProjection, NativeUIControls, NativeUIStatus, NativeUISuspension, VerticalBarEdge, VerticalControlAreaHandle, VerticalControlAreaOptions } from "./native/definitions.js";
2
2
  import { NativeUI } from "./native/activation.js";
3
3
  import { applyFoldStateClasses } from "./native/foldable/fold-state.js";
4
4
  import { setVerticalControlAreaPlacement } from "./native/legacy-layout.js";
5
5
  import { enableVerticalControlArea } from "./native/index.js";
6
- export { NativeUI, type NativeUIStatus, type NativeUISuspension, type ToolbarProjectionOptions, type VerticalBarEdge, type VerticalControlAreaHandle, type VerticalControlAreaOptions, applyFoldStateClasses, enableVerticalControlArea, setVerticalControlAreaPlacement };
6
+ export { type ControlProjection, NativeUI, type NativeUIControls, type NativeUIStatus, type NativeUISuspension, type VerticalBarEdge, type VerticalControlAreaHandle, type VerticalControlAreaOptions, applyFoldStateClasses, enableVerticalControlArea, setVerticalControlAreaPlacement };
@@ -0,0 +1,45 @@
1
+ # Light and dark appearance
2
+
3
+ Native UI reads the computed style of each projected source element and sends its light/dark appearance to the native renderer. Configure appearance in your Web CSS; there is no separate native dark-mode startup option.
4
+
5
+ ## How appearance is resolved
6
+
7
+ The first applicable row wins:
8
+
9
+ | Priority | Computed source style | Result |
10
+ | -------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
11
+ | 1 | Theme-provided `--ios27-color-scheme` is non-empty | `dark` selects dark; other values select light. The iOS 27 theme supplies this marker through its light and dark stylesheets. |
12
+ | 2 | `--ion-background-color-rgb` supplies three RGB channels | Infers dark or light from the background brightness. |
13
+ | 3 | CSS `color-scheme` contains only `dark` or only `light` | Uses that scheme. `light dark` does not select a single appearance. |
14
+ | 4 | None of the above | Uses the system's `prefers-color-scheme: dark` setting. |
15
+
16
+ Theme markers and Ionic background values take precedence over `color-scheme`. Changing only an arbitrary CSS background or text color does not select native light/dark appearance.
17
+
18
+ ## Match your Web theme
19
+
20
+ | Web setup | What to configure |
21
+ | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
22
+ | iOS 27 theme | Load the matching [System, Class or Always dark-mode pair](../../theme-ios27/docs/setup.md#choose-one-dark-mode-pair). The theme supplies the appearance marker. |
23
+ | Ionic with an existing theme | Keep `--ion-background-color-rgb` consistent with the active palette; native appearance uses it when no theme marker is present. |
24
+ | HTML without those theme variables | Set `color-scheme: light` or `color-scheme: dark` to match the active Web theme. |
25
+ | System-managed HTML appearance | Use system-responsive CSS; when no single scheme is selected, native appearance falls back to the system setting. |
26
+
27
+ For example, a plain HTML app with a manual dark-mode class can declare:
28
+
29
+ ```css
30
+ :root {
31
+ color-scheme: light;
32
+ }
33
+
34
+ :root.app-dark {
35
+ color-scheme: dark;
36
+ }
37
+ ```
38
+
39
+ Use the same class for your application's dark palette. This example assumes neither of the higher-priority theme variables is supplied. Class/style mutations and system appearance changes trigger re-evaluation while the runtime is active. For style changes without an observed DOM mutation, call `shell.markForCheck()` after applying them.
40
+
41
+ ## Shared Vertical Bars appearance
42
+
43
+ Ordinary controls resolve appearance from their own source styles. Vertical Bars shares one native rail appearance: **if any projected control is dark, the whole rail uses dark appearance**. It does not render separate light and dark rail regions. Keep sources projected into the same rail on a consistent Web palette.
44
+
45
+ Native light/dark appearance selects the system material and control appearance; it does not reproduce arbitrary application CSS. Vertical button fill and tint remain governed by the separate [button appearance settings](vertical-bars.md#choose-button-appearance).
@@ -1,5 +1,7 @@
1
1
  # Configure Native UI
2
2
 
3
+ This is the settings reference. Start with [how projection works](../README.md#how-projection-works), then [Ionic setup](setup.md) or [HTML setup](framework-independent.md) for installation.
4
+
3
5
  Call `enableNativeUI()` once after your application's DOM is mounted. Ionic and explicitly marked HTML controls share the standard Swift renderers. The theme is optional; Web layout, safe areas and spacing belong to your app or theme.
4
6
 
5
7
  ```ts
@@ -12,65 +14,97 @@ Without Ionic, import the same API from `@rdlabo/capacitor-native-ui/core`. That
12
14
 
13
15
  ## Platform behavior
14
16
 
15
- | Feature | Supported iOS | Android | Browser / older iOS |
16
- | --- | --- | --- | --- |
17
- | Automatic Ionic controls (`ionic.auto`) | Native | Original Web controls | Original Web controls |
18
- | Explicit element buttons | Native | Original Web controls | Original Web controls |
19
- | Element extensions | SwiftUI | Kotlin / Compose | Original Web content |
20
- | Vertical Bars | Native when available; otherwise Web rail | Web rail | Web rail |
21
- | `tab-accessory` extensions | Supported iOS tab host only | Original Web content | Original Web content |
17
+ | Feature | Supported iOS | Android | Browser / older iOS |
18
+ | --------------------------------------- | ----------------------------------------- | --------------------- | --------------------- |
19
+ | Automatic Ionic controls (`ionic.auto`) | Native | Original Web controls | Original Web controls |
20
+ | Explicit element buttons | Native | Original Web controls | Original Web controls |
21
+ | Element extensions | SwiftUI | Kotlin / Compose | Original Web content |
22
+ | Vertical Bars | Native when available; otherwise Web rail | Web rail | Web rail |
23
+ | `tab-accessory` extensions | Supported iOS tab host only | Original Web content | Original Web content |
24
+
25
+ Web rails require the Ionic rail layout or an application-owned HTML `webHost`. Settings never create a device capability.
22
26
 
23
- Web rails require the Ionic rail layout or an application-owned HTML `webHost`. Settings never create a device capability. `verticalBars.only: true` excludes element extensions on every platform; leave it false when combining a Web rail with Android extensions.
27
+ For HTML-derived light/dark behavior, see [Light and dark appearance](appearance.md). Appearance is configured in Web CSS, not through a startup option.
24
28
 
25
29
  ## All settings
26
30
 
27
- All nested objects merge with their defaults. For example, `ionic: { auto: { tabs: false } }` disables only tabs.
31
+ `controls` chooses selection and grouping defaults. `verticalBars` configures the rail. `ionic` configures Ionic discovery and appearance. Omitted fields default to `true` in `controls`, including partial objects.
28
32
 
29
33
  ```ts
30
34
  const shell = await enableNativeUI({
31
35
  root: document.body,
32
- debug: false,
33
- ionic: {
34
- auto: {
35
- buttons: true,
36
- tabs: true,
37
- segment: true,
38
- fab: true,
39
- },
36
+ controls: {
37
+ buttonGroup: true,
38
+ button: true,
39
+ backButton: true,
40
+ tabs: true,
41
+ segment: true,
42
+ fab: true,
40
43
  },
41
44
  verticalBars: {
42
45
  enabled: true,
43
- only: false,
44
- buttonProjection: 'system',
45
- buttonDefaultFill: 'glass',
46
- popover: false,
47
46
  // Optional: placement: { edge: 'trailing', webHost: appOwnedHost },
48
47
  },
49
- horizontal: true,
50
- vertical: true,
51
48
  extensions: [],
49
+ ionic: {
50
+ auto: true,
51
+ verticalBars: {
52
+ buttonProjection: 'system',
53
+ buttonDefaultFill: 'glass',
54
+ popover: false,
55
+ },
56
+ },
57
+ debug: false,
52
58
  });
53
59
  ```
54
60
 
55
- | Setting | Default | Meaning |
56
- | --- | --- | --- |
57
- | `ionic.auto` | `true` | `true` or omitted enables automatic Ionic projection; `false` disables it; an object selects kinds. Explicit `data-native-ui` sources and extensions are unaffected. |
58
- | `horizontal` / `vertical` | `true` | Automatic Ionic toolbar selection and grouping per layout: boolean or `{ buttons, button, backButton }`. Omitted fields are `true`; local attributes may override. See [toolbar settings](native-ui.md#toolbar-selection-and-grouping). |
59
- | `debug` | `false` | Log source elements and Web fallback reasons to the developer console; no props or application exception messages. |
60
- | `root` | `document.body` | Connected source subtree. Controls outside it are not projected. |
61
- | `ionic.auto.buttons` | `true` | Automatic Ionic toolbar/back/menu controls. Explicitly marked buttons are independent. |
62
- | `ionic.auto.tabs` | `true` | Ionic tabs and their registered native search. |
63
- | `ionic.auto.segment` | `true` | Supported Ionic segments. |
64
- | `ionic.auto.fab` | `true` | Supported Ionic floating action buttons. |
65
- | `verticalBars.enabled` | `true` | Allow rail projection when available. Device capability is always checked; enabling cannot create a system rail. |
66
- | `verticalBars.only` | `false` | Restrict native projection to rail controls. Other controls stay Web. |
67
- | `verticalBars.buttonProjection` | `'system'` | `'system'` uses native styling; `'source'` uses supported source styling. Local overrides take precedence. |
68
- | `verticalBars.buttonDefaultFill` | `'glass'` | `'glass'` or `'solid'` for source-style standalone Ionic buttons with no explicit fill. Explicit fills and the clear default inside `ion-buttons` take precedence. |
69
- | `verticalBars.popover` | `false` | Opt into Ionic popovers anchored to native rail buttons. Requires the Ionic entry and its optional peers; no effect on plain HTML. |
70
- | `verticalBars.placement` | omitted | Optional `{ edge: 'leading' \| 'trailing', webHost?: HTMLElement }`. Edge is a preference, not a device capability declaration. |
71
- | `extensions` | `[]` | **Experimental.** Application-specific SwiftUI / Compose extensions, paired with native registrations. API and behavior may change. |
72
-
73
- `webHost` is an optional, application-styled HTML fallback rail. It must be connected in the same document and outside `root`, with neither element containing the other. Use a limited `root`, such as your `<main>`, when supplying a sibling host; the default `document.body` cannot have such a host. Without a host, unavailable HTML rails leave their original controls visible. Ionic's existing rail layout uses its own fallback adapter.
61
+ ### Selection defaults
62
+
63
+ Every control accepts `ControlProjection`. `controls` itself accepts the same values as a shorthand for all six fields.
64
+
65
+ | Value | Ordinary placement | Vertical rail placement |
66
+ | ------------------ | ------------------ | ----------------------- |
67
+ | `true` (default) | Selected | Selected |
68
+ | `false` | Not selected | Not selected |
69
+ | `'horizontalOnly'` | Selected | Not selected |
70
+ | `'verticalOnly'` | Not selected | Selected |
71
+
72
+ Horizontal and vertical describe **control placement**, not screen orientation or device model. These defaults do not move a control, provide a missing device capability, or make unsupported markup eligible.
73
+
74
+ | Control | Responsibility |
75
+ | ------------- | -------------------------------------------------------------------------------- |
76
+ | `buttonGroup` | Group already selected actions when the group qualifies. Never selects children. |
77
+ | `button` | Select ordinary buttons and Ionic menu buttons. |
78
+ | `backButton` | Select back navigation, independently of its parent group. |
79
+ | `tabs` | Select tabs and their registered search presentation. |
80
+ | `segment` | Select supported segments. |
81
+ | `fab` | Select supported floating action buttons. |
82
+
83
+ Local `data-horizontal-bars="true|false"` and `data-vertical-bars="true|false"` override the matching selection default. On `ion-buttons` they control grouping only. Explicit `data-native-ui` sources are independent of these defaults. Structural exclusions and rail availability still apply. See [toolbar selection and grouping](native-ui.md#toolbar-selection-and-grouping).
84
+
85
+ ### Other settings
86
+
87
+ | Setting | Default | Meaning |
88
+ | -------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
89
+ | `root` | `document.body` | Connected source subtree. Controls outside it are not projected. |
90
+ | `verticalBars.enabled` | `true` | Allow rail projection when available. |
91
+ | `verticalBars.placement` | omitted | Optional `{ edge: 'leading' \| 'trailing', webHost?: HTMLElement }`. Edge is a preference, not a capability declaration. |
92
+ | `extensions` | `[]` | **Experimental.** App-specific SwiftUI / Compose extensions. Independent of `controls` and `ionic.auto`; the app decides when its reader returns content. |
93
+ | `ionic.auto` | `true` | Enable automatic Ionic discovery. `false` disables it, including local layout opt-ins. Explicit `data-native-ui` sources and extensions remain independent. |
94
+ | `ionic.verticalBars.buttonProjection` | `'system'` | `'system'` uses native styling; `'source'` projects supported Ionic styling. Local appearance overrides take precedence. |
95
+ | `ionic.verticalBars.buttonDefaultFill` | `'glass'` | `'glass'` or `'solid'` for source-style standalone Ionic buttons without explicit fill. Explicit fills and the clear default inside groups take precedence. |
96
+ | `ionic.verticalBars.popover` | `false` | Opt into Ionic popovers anchored to native rail buttons. Requires the Ionic entry and its optional peers. |
97
+ | `debug` | `false` | Log source elements and fallback reasons to the developer console. |
98
+
99
+ ### HTML fallback rail host
100
+
101
+ `webHost` is an optional, application-styled HTML fallback rail. Its requirements are:
102
+
103
+ - Connected to the same document as `root`.
104
+ - Outside `root`; neither element may contain the other.
105
+ - Styled and positioned by the application, including any reserved content spacing.
106
+
107
+ Use a limited `root`, such as your `<main>`, with a sibling host; the default `document.body` cannot have such a host. Without a host, unavailable HTML rails leave original controls visible. Ionic's existing rail layout uses its own fallback adapter.
74
108
 
75
109
  HTML currently supports buttons and back buttons. Tab, segment and FAB readers remain Ionic adapters; enabling those settings does not infer equivalent structures from arbitrary HTML.
76
110
 
@@ -80,25 +114,20 @@ HTML currently supports buttons and back buttons. Tab, segment and FAB readers r
80
114
  // Ionic or HTML: all supported controls, rail support enabled by default.
81
115
  const shell = await enableNativeUI();
82
116
 
83
- // Alternative startup: Ionic with only Vertical Bars native presentation.
84
- const railOnly = await enableNativeUI({ verticalBars: { only: true } });
117
+ // Alternative: automatic selection only in the rail.
118
+ const railOnly = await enableNativeUI({ controls: 'verticalOnly' });
85
119
 
86
- // Alternative startup: automatically project only Ionic tabs; explicit sources remain independent.
120
+ // Alternative: automatically select only tabs.
87
121
  const tabsOnly = await enableNativeUI({
88
- ionic: { auto: { buttons: false, segment: false, fab: false } },
122
+ controls: { buttonGroup: false, button: false, backButton: false, tabs: true, segment: false, fab: false },
89
123
  });
90
124
  ```
91
125
 
92
- These are alternatives: start only one shell. Repeating the same startup returns its handle; different startup settings require destroying the previous shell.
126
+ These are alternatives: start only one shell. Repeating equivalent startup settings returns its handle; different settings require destroying the previous shell.
93
127
 
94
- | Rail setting | Rail available | Rail unavailable |
95
- | --- | --- | --- |
96
- | `enabled: true, only: false` | Eligible rail and ordinary native controls | Ordinary native controls; unavailable rail controls retain Web fallback |
97
- | `enabled: true, only: true` | Eligible rail controls only | Web fallback |
98
- | `enabled: false, only: false` | Ordinary native controls; rail controls remain Web | Same |
99
- | `enabled: false, only: true` | All controls remain Web | Same |
128
+ `controls: false` disables all default selection and grouping, while local attributes can still opt in. `ionic: { auto: false }` instead disables automatic Ionic discovery altogether. Neither disables explicit HTML sources or extensions.
100
129
 
101
- `data-native-ui-placement="element"` preserves a control's original position. It is never moved into a rail; with `only: true` it stays Web. For Ionic groups, put the placement on the whole `ion-buttons` group so its shared native surface has a single placement.
130
+ `verticalBars.enabled: false` leaves rail controls on the Web regardless of selection. It does not affect ordinary controls. `data-native-ui-placement="element"` preserves an explicit control's original position, even with `controls: 'verticalOnly'`. For Ionic groups, put placement on the whole `ion-buttons` group so its shared native surface has one placement.
102
131
 
103
132
  ## Select controls explicitly in a customized Ionic app
104
133
 
@@ -108,10 +137,13 @@ Disable automatic Ionic projection while retaining the native rail and your cust
108
137
  const shell = await enableNativeUI({
109
138
  root: document.querySelector<HTMLElement>('#content')!,
110
139
  ionic: { auto: false },
111
- verticalBars: { enabled: true, placement: {
112
- edge: 'trailing',
113
- webHost: document.querySelector<HTMLElement>('#rail')!,
114
- } },
140
+ verticalBars: {
141
+ enabled: true,
142
+ placement: {
143
+ edge: 'trailing',
144
+ webHost: document.querySelector<HTMLElement>('#rail')!,
145
+ },
146
+ },
115
147
  extensions: [myExtension],
116
148
  });
117
149
  ```
@@ -129,7 +161,7 @@ Keep your original handlers on each source. Explicit `ion-button` uses the stand
129
161
 
130
162
  Explicit built-in sources support individual `button`, `ion-button`, and `[role="button"]` elements with `data-native-ui="button"` or `"back-button"`. This does not opt existing `ion-back-button`, `ion-menu-button`, button groups, tabs, segments, or FABs into their Ionic-specific readers. Keep automatic projection enabled for the corresponding kind, use a standard explicit button with your own click handler, or register an extension for custom UI.
131
163
 
132
- `verticalBars.enabled` and `only` still govern rail availability and projection scope. For example, `only: true` leaves explicitly marked element-position buttons and ordinary element extensions on the Web too.
164
+ `verticalBars.enabled` still governs rail availability. To leave a specific source on the Web, remove its explicit marker or use `data-native-ui="disabled"`.
133
165
 
134
166
  ## Change rail use after startup
135
167
 
@@ -138,12 +170,12 @@ await shell.disableVerticalControlArea();
138
170
  await shell.enableVerticalControlArea();
139
171
  ```
140
172
 
141
- These methods change `verticalBars.enabled` on this shell and preserve `only`, appearance, controls and placement. They retire existing projection before transferring ownership, without creating another shell. Calls are serialized. Calling either method after `destroy()` rejects.
173
+ These methods change `verticalBars.enabled` on this shell and preserve appearance, controls and placement. They retire existing projection before transferring ownership, without creating another shell. Calls are serialized. Calling either method after `destroy()` rejects.
142
174
 
143
175
  ```ts
144
176
  const lease = await shell.suspend(); // temporarily restore all Web controls
145
177
  await lease.resume();
146
- await shell.destroy(); // stop the shell and restore sources
178
+ await shell.destroy(); // stop the shell and restore sources
147
179
  ```
148
180
 
149
181
  Disabling rail projection does not remove application CSS or change application-owned spacing. Update your own layout alongside this setting if needed.
@@ -167,21 +199,21 @@ console.info(shell.getStatus());
167
199
 
168
200
  Open the WebView developer console and filter for `[Native UI]`. Diagnostics include the DOM source when available. Each reason is logged once per source during that activation, so scrolling or repeated `markForCheck()` calls do not flood the console. Props, action payloads and application exception messages are not logged.
169
201
 
170
- | Diagnostic | What to check |
171
- | --- | --- |
172
- | `web-fallback` | Platform support, native plugin registration, sync and native rebuild. |
173
- | `unregistered-extension` | Native registration name matches the DOM definition and runs before startup. Newly inserted sources are checked too. |
174
- | `reader-error` / `invalid-props` | Reader implementation, JSON-only values and the 64K size limit. |
175
- | `unsupported-placement` / `missing-tab-owner` | Platform and owning native tab host for a tab accessory. |
176
- | `source-hidden` / `source-clipped` / `source-focused` | Visibility, clipping/transformed ancestors, or a focused Web descendant. |
177
- | `reader-opt-out` / `rail-only` | Your reader returned null, or `verticalBars.only` excludes an element extension. |
178
- | `unsupported-control` | Supported markup, accessible name, fixed placement and styling. |
179
- | `native-rejected` | Native props decoding, placement or device support. The bridge reports rejection, not the native exception. |
202
+ | Diagnostic | What to check |
203
+ | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
204
+ | `web-fallback` | Platform support, native plugin registration, sync and native rebuild. |
205
+ | `unregistered-extension` | Native registration name matches the DOM definition and runs before startup. Newly inserted sources are checked too. |
206
+ | `reader-error` / `invalid-props` | Reader implementation, JSON-only values and the 64K size limit. |
207
+ | `unsupported-placement` / `missing-tab-owner` | Platform and owning native tab host for a tab accessory. |
208
+ | `source-hidden` / `source-clipped` / `source-focused` | Visibility, clipping/transformed ancestors, or a focused Web descendant. |
209
+ | `reader-opt-out` | Your reader returned null. |
210
+ | `unsupported-control` | Supported markup, accessible name, fixed placement and styling. |
211
+ | `native-rejected` | Native props decoding, placement or device support. The bridge reports rejection, not the native exception. |
180
212
 
181
213
  `getStatus()` summarizes the shell; it is not a per-element diagnostic report. Normal navigation, suspension and unsupported content can intentionally retain Web presentation. Turn debug off after investigating; it does not change projection eligibility.
182
214
 
183
- ## Compatibility
215
+ ## Existing applications
184
216
 
185
- `controls` is deprecated. If `ionic.auto` is omitted, existing `controls` settings retain their previous behavior, including `buttons: false` disabling explicitly marked buttons. When `ionic.auto` is supplied, it takes precedence for automatic controls and explicit sources are independent. Move `controls.popover` to `verticalBars.popover`. Partial objects retain enabled defaults for omitted kinds; use `false` to disable all automatic kinds.
217
+ The standalone `enableVerticalControlArea()` defaults selection to `'verticalOnly'`. Its `setPlacement()` helper is a deprecated Web CSS adapter; use the theme's `setVerticalBarsLayout({ edge, inset })` for Web layout. Native availability comes from the plugin's device metrics.
186
218
 
187
- The existing global `enableVerticalControlArea()` remains a startup wrapper for Ionic rail-only usage, while `setVerticalControlAreaPlacement()` is a deprecated Web CSS compatibility adapter. Its `nativeEdge` input is ignored; native availability is obtained from the plugin’s own device metrics. Use the theme’s `setVerticalBarsLayout({ edge, inset })` for Web layout. New code should use the shared startup and handle methods above. See [migration](migration.md) for legacy settings and the changed partial-control defaults.
219
+ See [upgrading from 1.2.1](migration.md) for package separation, removed options and changed partial-control defaults.