@bitforgehq/ui 0.3.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 (281) hide show
  1. package/CHANGELOG.md +3665 -0
  2. package/LICENSE +21 -0
  3. package/README.md +175 -0
  4. package/ai/MANIFEST.index.json +383 -0
  5. package/ai/MANIFEST.json +7528 -0
  6. package/ai/REFERENCE.index.json +1461 -0
  7. package/ai/REFERENCE.json +7213 -0
  8. package/ai/UI_GUIDE.md +1159 -0
  9. package/ai/components/action-bar.md +209 -0
  10. package/ai/components/action-sheet.md +526 -0
  11. package/ai/components/alert-dialog.md +509 -0
  12. package/ai/components/alert.md +376 -0
  13. package/ai/components/avatar.md +146 -0
  14. package/ai/components/back-button.md +286 -0
  15. package/ai/components/badge.md +171 -0
  16. package/ai/components/button.md +431 -0
  17. package/ai/components/card.md +303 -0
  18. package/ai/components/checkbox.md +418 -0
  19. package/ai/components/chip-group.md +205 -0
  20. package/ai/components/chip.md +300 -0
  21. package/ai/components/content.md +474 -0
  22. package/ai/components/desktop-toast.md +420 -0
  23. package/ai/components/dialog.md +962 -0
  24. package/ai/components/empty-state.md +146 -0
  25. package/ai/components/field.md +319 -0
  26. package/ai/components/header.md +809 -0
  27. package/ai/components/icon-button.md +221 -0
  28. package/ai/components/icon.md +176 -0
  29. package/ai/components/input.md +455 -0
  30. package/ai/components/list-item.md +326 -0
  31. package/ai/components/list.md +178 -0
  32. package/ai/components/menu-button.md +377 -0
  33. package/ai/components/menu.md +661 -0
  34. package/ai/components/modal.md +613 -0
  35. package/ai/components/number-input.md +423 -0
  36. package/ai/components/page.md +299 -0
  37. package/ai/components/progress.md +215 -0
  38. package/ai/components/radio-group.md +432 -0
  39. package/ai/components/refresher.md +377 -0
  40. package/ai/components/segmented.md +517 -0
  41. package/ai/components/select.md +510 -0
  42. package/ai/components/sheet.md +845 -0
  43. package/ai/components/spinner.md +171 -0
  44. package/ai/components/stack-outlet.md +661 -0
  45. package/ai/components/tab-bar.md +427 -0
  46. package/ai/components/tab.md +295 -0
  47. package/ai/components/tabs.md +408 -0
  48. package/ai/components/textarea.md +371 -0
  49. package/ai/components/toast.md +522 -0
  50. package/ai/components/toggle.md +387 -0
  51. package/ai/reference/bf-action-directive.md +21 -0
  52. package/ai/reference/bf-action-sheet-action-role.md +27 -0
  53. package/ai/reference/bf-action-sheet-action.md +28 -0
  54. package/ai/reference/bf-action-sheet-options.md +28 -0
  55. package/ai/reference/bf-action-sheet-service.md +33 -0
  56. package/ai/reference/bf-alert-dialog-button-role.md +27 -0
  57. package/ai/reference/bf-alert-dialog-button.md +27 -0
  58. package/ai/reference/bf-alert-dialog-options.md +29 -0
  59. package/ai/reference/bf-alert-dialog-service.md +34 -0
  60. package/ai/reference/bf-alert-variant.md +28 -0
  61. package/ai/reference/bf-autocapitalize.md +30 -0
  62. package/ai/reference/bf-avatar-size.md +27 -0
  63. package/ai/reference/bf-avatar-variant.md +28 -0
  64. package/ai/reference/bf-back-at-root.md +28 -0
  65. package/ai/reference/bf-back-button-service.md +40 -0
  66. package/ai/reference/bf-badge-variant.md +29 -0
  67. package/ai/reference/bf-button-size.md +29 -0
  68. package/ai/reference/bf-button-type.md +28 -0
  69. package/ai/reference/bf-button-variant.md +29 -0
  70. package/ai/reference/bf-card-padding.md +26 -0
  71. package/ai/reference/bf-card-variant.md +28 -0
  72. package/ai/reference/bf-chip-group-mode.md +27 -0
  73. package/ai/reference/bf-chip-variant.md +26 -0
  74. package/ai/reference/bf-compare-with.md +24 -0
  75. package/ai/reference/bf-component-overlay-ref.md +33 -0
  76. package/ai/reference/bf-confirm-button-role.md +26 -0
  77. package/ai/reference/bf-confirm-button.md +27 -0
  78. package/ai/reference/bf-confirm-options.md +31 -0
  79. package/ai/reference/bf-confirm-size.md +26 -0
  80. package/ai/reference/bf-content-scroll-event.md +21 -0
  81. package/ai/reference/bf-defaults-options.md +32 -0
  82. package/ai/reference/bf-defaults.md +28 -0
  83. package/ai/reference/bf-desktop-toast-config.md +28 -0
  84. package/ai/reference/bf-desktop-toast-harness.md +33 -0
  85. package/ai/reference/bf-desktop-toast-options.md +28 -0
  86. package/ai/reference/bf-desktop-toast-position.md +28 -0
  87. package/ai/reference/bf-desktop-toast-service.md +42 -0
  88. package/ai/reference/bf-dialog-config.md +44 -0
  89. package/ai/reference/bf-dialog-harness.md +52 -0
  90. package/ai/reference/bf-dialog-ref.md +44 -0
  91. package/ai/reference/bf-dialog-role.md +26 -0
  92. package/ai/reference/bf-dialog-service.md +55 -0
  93. package/ai/reference/bf-dialog-size.md +31 -0
  94. package/ai/reference/bf-dialog-template-context.md +32 -0
  95. package/ai/reference/bf-empty-state-heading-level.md +26 -0
  96. package/ai/reference/bf-enter-key-hint.md +31 -0
  97. package/ai/reference/bf-field-control-class.md +32 -0
  98. package/ai/reference/bf-field-control-state.md +28 -0
  99. package/ai/reference/bf-field-size.md +29 -0
  100. package/ai/reference/bf-haptics-impact-style.md +27 -0
  101. package/ai/reference/bf-haptics-notification-type.md +27 -0
  102. package/ai/reference/bf-haptics-service.md +41 -0
  103. package/ai/reference/bf-harness-filters.md +29 -0
  104. package/ai/reference/bf-horizontal-scroll-directive.md +129 -0
  105. package/ai/reference/bf-icon-button-variant.md +28 -0
  106. package/ai/reference/bf-icon-size.md +27 -0
  107. package/ai/reference/bf-input-autocapitalize.md +36 -0
  108. package/ai/reference/bf-input-enter-key-hint.md +38 -0
  109. package/ai/reference/bf-input-input-mode.md +38 -0
  110. package/ai/reference/bf-input-mode.md +32 -0
  111. package/ai/reference/bf-input-type.md +35 -0
  112. package/ai/reference/bf-jsdom-shim-options.md +22 -0
  113. package/ai/reference/bf-keyboard-assist-behavior.md +26 -0
  114. package/ai/reference/bf-keyboard-assist-directive.md +185 -0
  115. package/ai/reference/bf-keyboard-phase.md +30 -0
  116. package/ai/reference/bf-keyboard-service.md +50 -0
  117. package/ai/reference/bf-labels-overrides.md +26 -0
  118. package/ai/reference/bf-labels.md +44 -0
  119. package/ai/reference/bf-menu-button-harness.md +40 -0
  120. package/ai/reference/bf-menu-button-variant.md +27 -0
  121. package/ai/reference/bf-menu-divider-directive.md +13 -0
  122. package/ai/reference/bf-menu-group-directive.md +14 -0
  123. package/ai/reference/bf-menu-harness.md +55 -0
  124. package/ai/reference/bf-menu-item-checkbox-directive.md +31 -0
  125. package/ai/reference/bf-menu-item-directive.md +31 -0
  126. package/ai/reference/bf-menu-item-harness.md +52 -0
  127. package/ai/reference/bf-menu-item-radio-directive.md +29 -0
  128. package/ai/reference/bf-menu-placement.md +29 -0
  129. package/ai/reference/bf-menu-trigger-directive.md +46 -0
  130. package/ai/reference/bf-modal-options.md +30 -0
  131. package/ai/reference/bf-modal-presentation.md +26 -0
  132. package/ai/reference/bf-modal-service.md +38 -0
  133. package/ai/reference/bf-nav-controller.md +59 -0
  134. package/ai/reference/bf-nav-direction.md +23 -0
  135. package/ai/reference/bf-nav-target.md +21 -0
  136. package/ai/reference/bf-number-input-mode.md +28 -0
  137. package/ai/reference/bf-number-input-step.md +25 -0
  138. package/ai/reference/bf-overlay-auto-focus.md +29 -0
  139. package/ai/reference/bf-overlay-controller.md +22 -0
  140. package/ai/reference/bf-overlay-host.md +36 -0
  141. package/ai/reference/bf-overlay-options.md +53 -0
  142. package/ai/reference/bf-overlay-position.md +30 -0
  143. package/ai/reference/bf-overlay-ref.md +53 -0
  144. package/ai/reference/bf-overlay-role.md +27 -0
  145. package/ai/reference/bf-overlay-service.md +53 -0
  146. package/ai/reference/bf-overlay-stack-options.md +24 -0
  147. package/ai/reference/bf-overlay-stack.md +81 -0
  148. package/ai/reference/bf-overlay-template-context.md +24 -0
  149. package/ai/reference/bf-overscroll-stretch-directive.md +163 -0
  150. package/ai/reference/bf-page-context.md +24 -0
  151. package/ai/reference/bf-platform-service.md +53 -0
  152. package/ai/reference/bf-platform.md +28 -0
  153. package/ai/reference/bf-progress-size.md +26 -0
  154. package/ai/reference/bf-progress-tone.md +28 -0
  155. package/ai/reference/bf-radio-group-harness.md +49 -0
  156. package/ai/reference/bf-radio-group-orientation.md +26 -0
  157. package/ai/reference/bf-radio-option.md +30 -0
  158. package/ai/reference/bf-refresher-refresh-event.md +22 -0
  159. package/ai/reference/bf-segment-option.md +29 -0
  160. package/ai/reference/bf-segmented-harness.md +48 -0
  161. package/ai/reference/bf-segmented-size.md +29 -0
  162. package/ai/reference/bf-select-harness.md +70 -0
  163. package/ai/reference/bf-select-option.md +29 -0
  164. package/ai/reference/bf-sheet-auto-focus.md +29 -0
  165. package/ai/reference/bf-sheet-options.md +32 -0
  166. package/ai/reference/bf-sheet-ref.md +45 -0
  167. package/ai/reference/bf-sheet-service.md +34 -0
  168. package/ai/reference/bf-shell-config-mode.md +28 -0
  169. package/ai/reference/bf-shell-config.md +38 -0
  170. package/ai/reference/bf-shell-dynamic-type-limit.md +21 -0
  171. package/ai/reference/bf-shell-dynamic-type.md +25 -0
  172. package/ai/reference/bf-shell-mode.md +28 -0
  173. package/ai/reference/bf-shell-testing-options.md +26 -0
  174. package/ai/reference/bf-size.md +45 -0
  175. package/ai/reference/bf-spinner-size.md +27 -0
  176. package/ai/reference/bf-stack-change.md +22 -0
  177. package/ai/reference/bf-stack-reuse-strategy.md +32 -0
  178. package/ai/reference/bf-stack-transition-event.md +26 -0
  179. package/ai/reference/bf-stack-transition.md +26 -0
  180. package/ai/reference/bf-stacked-overlay.md +23 -0
  181. package/ai/reference/bf-system-bars-style.md +38 -0
  182. package/ai/reference/bf-tab-bar-controller.md +51 -0
  183. package/ai/reference/bf-tab-bar-host.md +52 -0
  184. package/ai/reference/bf-tab-context.md +32 -0
  185. package/ai/reference/bf-tab-links.md +37 -0
  186. package/ai/reference/bf-testing-options.md +27 -0
  187. package/ai/reference/bf-text-scale-service.md +35 -0
  188. package/ai/reference/bf-theme.md +27 -0
  189. package/ai/reference/bf-toast-action.md +25 -0
  190. package/ai/reference/bf-toast-controller.md +17 -0
  191. package/ai/reference/bf-toast-dismiss-reason.md +29 -0
  192. package/ai/reference/bf-toast-options.md +29 -0
  193. package/ai/reference/bf-toast-position.md +26 -0
  194. package/ai/reference/bf-toast-ref.md +41 -0
  195. package/ai/reference/bf-toast-service.md +39 -0
  196. package/ai/reference/bf-toggle-label-position.md +26 -0
  197. package/ai/reference/bf-transition-kind.md +28 -0
  198. package/ai/reference/bf-validation-message.md +31 -0
  199. package/ai/reference/bf-validation-messages.md +33 -0
  200. package/ai/reference/bf-view-event.md +28 -0
  201. package/ai/reference/bf-view-lifecycle.md +41 -0
  202. package/ai/reference/bf-view-state.md +28 -0
  203. package/ai/reference/bf_default_labels.md +21 -0
  204. package/ai/reference/bf_default_values.md +21 -0
  205. package/ai/reference/bf_defaults.md +21 -0
  206. package/ai/reference/bf_desktop_toast_defaults.md +21 -0
  207. package/ai/reference/bf_dialog_data.md +17 -0
  208. package/ai/reference/bf_labels.md +21 -0
  209. package/ai/reference/bf_overlay_data.md +19 -0
  210. package/ai/reference/bf_overlay_host.md +21 -0
  211. package/ai/reference/bf_sheet_default_snap_points.md +17 -0
  212. package/ai/reference/bf_shell_config.md +21 -0
  213. package/ai/reference/bf_shell_defaults.md +21 -0
  214. package/ai/reference/bf_tab_bar.md +21 -0
  215. package/ai/reference/bf_tab_bar_controller.md +21 -0
  216. package/ai/reference/bf_tab_context.md +21 -0
  217. package/ai/reference/bf_tab_links.md +21 -0
  218. package/ai/reference/bf_theme_storage.md +19 -0
  219. package/ai/reference/create-transition.md +36 -0
  220. package/ai/reference/duration_fast.md +17 -0
  221. package/ai/reference/duration_md.md +17 -0
  222. package/ai/reference/duration_overlay.md +17 -0
  223. package/ai/reference/duration_push.md +17 -0
  224. package/ai/reference/fade-down.md +26 -0
  225. package/ai/reference/fade-in.md +25 -0
  226. package/ai/reference/fade-out.md +25 -0
  227. package/ai/reference/fade-up.md +26 -0
  228. package/ai/reference/inject-shell-mode.md +23 -0
  229. package/ai/reference/install-bf-jsdom-shims.md +31 -0
  230. package/ai/reference/ios_duration.md +17 -0
  231. package/ai/reference/ios_easing.md +17 -0
  232. package/ai/reference/is-text-entry.md +25 -0
  233. package/ai/reference/max_complete_ms.md +17 -0
  234. package/ai/reference/md-transition.md +31 -0
  235. package/ai/reference/md_duration.md +17 -0
  236. package/ai/reference/md_easing.md +17 -0
  237. package/ai/reference/overlay_duration.md +21 -0
  238. package/ai/reference/overlay_easing.md +19 -0
  239. package/ai/reference/overlay_reduced_duration.md +17 -0
  240. package/ai/reference/pop-frames-at.md +25 -0
  241. package/ai/reference/prefers-reduced-motion.md +25 -0
  242. package/ai/reference/provide-bf-defaults.md +33 -0
  243. package/ai/reference/provide-bf-desktop-toast.md +28 -0
  244. package/ai/reference/provide-bf-labels.md +38 -0
  245. package/ai/reference/provide-bf-shell-testing.md +34 -0
  246. package/ai/reference/provide-bf-shell.md +41 -0
  247. package/ai/reference/provide-bf-testing.md +33 -0
  248. package/ai/reference/reduced-transition.md +28 -0
  249. package/ai/reference/reduced_duration.md +17 -0
  250. package/ai/reference/resolve-shell-mode.md +33 -0
  251. package/ai/reference/scale-in.md +25 -0
  252. package/ai/reference/settle-duration.md +25 -0
  253. package/ai/reference/settle-pop.md +33 -0
  254. package/ai/reference/settle_easing.md +17 -0
  255. package/ai/reference/should-complete-pop.md +26 -0
  256. package/ai/reference/slide-down.md +26 -0
  257. package/ai/reference/slide-up.md +26 -0
  258. package/ai/reference/with-bf-shell-routing.md +19 -0
  259. package/bin/bf-ui.js +81 -0
  260. package/fesm2022/bitforgehq-ui-icons.mjs +230 -0
  261. package/fesm2022/bitforgehq-ui-icons.mjs.map +1 -0
  262. package/fesm2022/bitforgehq-ui-mobile.mjs +5530 -0
  263. package/fesm2022/bitforgehq-ui-mobile.mjs.map +1 -0
  264. package/fesm2022/bitforgehq-ui-number-input.mjs +680 -0
  265. package/fesm2022/bitforgehq-ui-number-input.mjs.map +1 -0
  266. package/fesm2022/bitforgehq-ui-overlay.mjs +2675 -0
  267. package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -0
  268. package/fesm2022/bitforgehq-ui-testing.mjs +402 -0
  269. package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -0
  270. package/fesm2022/bitforgehq-ui.mjs +7765 -0
  271. package/fesm2022/bitforgehq-ui.mjs.map +1 -0
  272. package/llms-full.txt +25394 -0
  273. package/llms.txt +329 -0
  274. package/package.json +94 -0
  275. package/theme.css +253 -0
  276. package/types/bitforgehq-ui-icons.d.ts +50 -0
  277. package/types/bitforgehq-ui-mobile.d.ts +2914 -0
  278. package/types/bitforgehq-ui-number-input.d.ts +282 -0
  279. package/types/bitforgehq-ui-overlay.d.ts +1514 -0
  280. package/types/bitforgehq-ui-testing.d.ts +495 -0
  281. package/types/bitforgehq-ui.d.ts +3499 -0
@@ -0,0 +1,2914 @@
1
+ import * as i0 from "@angular/core";
2
+ import { AfterViewInit, ComponentRef, EnvironmentInjector, EnvironmentProviders, InjectionToken, Injector, OnDestroy, OnInit, Signal, TemplateRef, Type } from "@angular/core";
3
+ import { SystemBarsStyle } from "@capacitor/core";
4
+ import { ActivatedRoute, ActivatedRouteSnapshot, BaseRouteReuseStrategy, Data, NavigationExtras, RouterConfigurationFeature, RouterOutletContract, Routes, UrlTree } from "@angular/router";
5
+ import * as core from "@bitforgehq/ui/overlay";
6
+ import { BfOverlayController, BfOverlayRef as BfOverlayRef$1, BfOverlayTemplateContext as BfOverlayTemplateContext$1, BfToastAction, BfToastAction as BfToastAction$1, BfToastDismissReason, BfToastRef, BfToastRef as BfToastRef$1, prefersReducedMotion } from "@bitforgehq/ui/overlay";
7
+ import { BfButtonVariant, BfTabBarController } from "@bitforgehq/ui";
8
+ import { IconNode } from "lucide";
9
+ /**
10
+ * The shell's transition and gesture style: `ios`, `md` (Material), or `auto` (iOS on iOS, else
11
+ * `md`).
12
+ *
13
+ * @summary The shell style setting, iOS, Material or automatic from the platform
14
+ * @since 0.3.0
15
+ */
16
+ type BfShellConfigMode = 'ios' | 'md' | 'auto';
17
+ /**
18
+ * The cap of iOS Dynamic Type: the largest root font scale the shell applies.
19
+ *
20
+ * @summary The largest root font scale iOS Dynamic Type may apply in the shell
21
+ * @since 0.3.0
22
+ */
23
+ interface BfShellDynamicTypeLimit {
24
+ /** The largest root font scale (2.35, the AX3 size, by default); `Infinity` removes the cap. */
25
+ maxScale: number;
26
+ }
27
+ /**
28
+ * The shell's iOS Dynamic Type setting: `false` opts out, a `BfShellDynamicTypeLimit` caps it.
29
+ *
30
+ * @summary Whether the shell follows iOS Dynamic Type, and up to which scale
31
+ * @since 0.3.0
32
+ */
33
+ type BfShellDynamicType = false | BfShellDynamicTypeLimit;
34
+ /**
35
+ * What the Android back button does at the root of every stack, when no overlay or page claims
36
+ * it: `minimize` moves the app to the background (`App.minimizeApp()`), so a relaunch resumes it
37
+ * warm; `exit` finishes the activity (`App.exitApp()`), so the next launch starts cold.
38
+ *
39
+ * @summary What Android back does at a stack root, background the app or exit it
40
+ * @since 0.3.0
41
+ */
42
+ type BfBackAtRoot = 'minimize' | 'exit';
43
+ /**
44
+ * Configuration of the mobile shell, set once through `provideBfShell()`.
45
+ *
46
+ * @summary The mobile shell settings: mode, swipe-back, haptics, Dynamic Type and system bars
47
+ * @since 0.2.0
48
+ */
49
+ interface BfShellConfig {
50
+ /**
51
+ * Transition and gesture style: `ios`, `md` (Material), or `auto` (iOS on iOS, else `md`).
52
+ * Overscroll is not part of it: `bf-content`'s iOS bounce and Android stretch and
53
+ * `bf-refresher`'s iOS bounce mode follow the engine (`BfPlatformService.mode()`), because the
54
+ * bounce is WebKit's own and Chrome never reports a negative `scrollTop`.
55
+ * @default 'auto'
56
+ */
57
+ mode: BfShellConfigMode;
58
+ /**
59
+ * Enables the iOS edge swipe-back in every stack outlet (iOS mode only).
60
+ * @default true
61
+ */
62
+ swipeBack: boolean;
63
+ /**
64
+ * Holds a transition at frame 0 for two animation frames while the entering page renders.
65
+ * @default true
66
+ */
67
+ deferTransitionStart: boolean;
68
+ /**
69
+ * Plays a light haptic tick on tab changes (native only).
70
+ * @default true
71
+ */
72
+ hapticsOnTabChange: boolean;
73
+ /**
74
+ * iOS Dynamic Type (native iOS only; see `BfTextScaleService`): the root font size follows the
75
+ * user's text size. `false` opts out; `maxScale` caps the root scale (default 2.35, the AX3
76
+ * size, at least 200 %). `Infinity` removes the cap entirely; a non-finite value other than
77
+ * `Infinity` (e.g. `NaN`) falls back to the default cap. Left out, the default applies. Android
78
+ * needs no setting: its WebView applies the system font scale.
79
+ * @default { maxScale: 2.35 }
80
+ */
81
+ dynamicType?: BfShellDynamicType;
82
+ /**
83
+ * Native iOS and Android only: the status-bar and navigation-bar icons follow the in-app theme
84
+ * (`BfPlatformService.dark()`) through Capacitor's `SystemBars.setStyle()`, on start and on every
85
+ * theme change (see `bfSystemBarsStyle()`). `false` leaves the system bars to the app.
86
+ * @default true
87
+ */
88
+ syncSystemBars?: boolean;
89
+ /**
90
+ * Native Android only: what the back button does when no overlay and no stack can go back
91
+ * (every stack is at its first page). `minimize` (default) moves the app to the background, as
92
+ * Android does for a root activity, so a relaunch resumes it warm on the same tab; `exit`
93
+ * finishes the activity, as 0.2 did, so the next launch starts cold.
94
+ * @default 'minimize'
95
+ */
96
+ backAtRoot?: BfBackAtRoot;
97
+ /**
98
+ * How many pages of one stack stay alive in each `bf-stack-outlet` (default `Infinity`: every
99
+ * page). Above it, the deepest pages are destroyed and kept as a record (route, URL, history
100
+ * position and the content's scroll position); a pop back to one creates the page again, fires
101
+ * its lifecycle and restores its scroll. Deep pages come back fresh: their component state and
102
+ * the stacks of outlets nested in them are gone. Values below 1 count as 1.
103
+ * @default Infinity
104
+ */
105
+ maxLivePages?: number;
106
+ }
107
+ /** The default Dynamic Type cap: the AX3 size (40 / 17 px), at least 200 %. Internal. */
108
+ declare const DEFAULT_MAX_TEXT_SCALE = 2.35;
109
+ /**
110
+ * The shell defaults, merged under the overrides given to `provideBfShell()`.
111
+ *
112
+ * @summary The mobile shell defaults that provideBfShell merges the app settings over
113
+ * @since 0.2.0
114
+ */
115
+ export declare const BF_SHELL_DEFAULTS: Readonly<BfShellConfig>;
116
+ /**
117
+ * The resolved shell configuration.
118
+ *
119
+ * @summary Injection token holding the resolved mobile shell configuration of the app
120
+ * @since 0.2.0
121
+ */
122
+ export declare const BF_SHELL_CONFIG: InjectionToken<BfShellConfig>;
123
+ /**
124
+ * The platform the app runs on: native iOS, native Android, or a browser.
125
+ *
126
+ * @summary The platform the app runs on, native iOS, native Android or the web
127
+ * @since 0.2.0
128
+ */
129
+ type BfPlatform = 'ios' | 'android' | 'web';
130
+ /**
131
+ * The shell's look and motion: `ios`, or `md` (Material) everywhere else.
132
+ *
133
+ * @summary The shell's look and motion conventions, iOS or Material Design
134
+ * @since 0.2.0
135
+ */
136
+ type BfShellMode = 'ios' | 'md';
137
+ /**
138
+ * The app theme choice: follow the system, or force light or dark.
139
+ *
140
+ * @summary The app theme choice, following the system or forcing light or dark
141
+ * @since 0.2.0
142
+ */
143
+ type BfTheme = 'system' | 'light' | 'dark';
144
+ /** A theme store in memory, gone with the app: where `localStorage` is unavailable, and in tests. Internal. */
145
+ declare function createMemoryThemeStorage(): Pick<Storage, 'getItem' | 'setItem'>;
146
+ /**
147
+ * Where `BfPlatformService` keeps the theme choice (the key `bf-theme`): `localStorage` when it is
148
+ * available, otherwise an in-memory map. Provide another store (a native preferences plugin, or an
149
+ * in-memory one in tests, as `provideBfShellTesting()` does) to keep the choice elsewhere.
150
+ *
151
+ * @example
152
+ * providers: [{ provide: BF_THEME_STORAGE, useValue: sessionStorage }]
153
+ * @summary Injection token for the store that keeps the app theme choice between visits
154
+ * @since 0.3.0
155
+ */
156
+ export declare const BF_THEME_STORAGE: InjectionToken<Pick<Storage, "getItem" | "setItem">>;
157
+ /**
158
+ * The SystemBars style for a theme: Dark = light icons. Android WebView < 140 pads the WebView, so
159
+ * the bar areas show the activity's window background (which follows the system theme): use
160
+ * Default there.
161
+ *
162
+ * The WebView ≥ 140 case assumes the shell's setup: `viewport-fit=cover` and Capacitor's default
163
+ * `SystemBars.insetsHandling: 'css'`, so the page draws under the bars. With `insetsHandling`
164
+ * `'disable'` or `'native'` the page never reaches under them and the bars show the window
165
+ * background as on older WebViews; pass `syncSystemBars: false` and style them yourself there.
166
+ * `webViewMajor` is read from `Chrome/<n>` in the user agent (Capacitor reads the WebView
167
+ * package, which normally agrees).
168
+ *
169
+ * @example
170
+ * await SystemBars.setStyle({ style: bfSystemBarsStyle(true, 'ios', null) });
171
+ * @param dark Whether the app is dark now (`BfPlatformService.dark()`).
172
+ * @param platform The platform the app runs on.
173
+ * @param webViewMajor The Android WebView's major version (`Chrome/<n>` in the user agent), or
174
+ * `null` when unknown.
175
+ * @returns The `SystemBarsStyle` to pass to `SystemBars.setStyle()`.
176
+ * @summary The system-bar icon style that keeps the bars readable in the in-app theme
177
+ * @since 0.3.0
178
+ */
179
+ export declare function bfSystemBarsStyle(dark: boolean, platform: BfPlatform, webViewMajor: number | null): SystemBarsStyle;
180
+ /**
181
+ * Platform facts and the app theme: native or web, iOS or Android, the shell mode that follows
182
+ * from it, and the user's theme choice (system, light, dark) reflected as the `dark` class on
183
+ * `<html>`. `matchMedia('(prefers-color-scheme: dark)')` is the single source for the system
184
+ * theme on every platform.
185
+ *
186
+ * The `theme`/`dark` signals always compute, but the `<html>` class and storage writes
187
+ * only run when `provideBfShell()` provided `BF_SHELL_CONFIG` — i.e. this service is the app's
188
+ * own shell, not merely injected by something that wants `platform`/`mode`. Without it (e.g. a
189
+ * docs demo that instantiates `BfPlatformService` directly to preview `bf-tabs`), this service
190
+ * would otherwise fight the host page's own theme: its `effect` runs on construction and would
191
+ * immediately overwrite `<html class="dark">` with whatever `prefers-color-scheme` says.
192
+ *
193
+ * With `provideBfShell()` on a native platform it also makes the viewport meta forbid zoom
194
+ * (`maximum-scale=1, user-scalable=no`, other directives kept; the meta is created if missing):
195
+ * WKWebView zooms a focused control whose font is under 16 px and never zooms back, so the native
196
+ * shell forbids zoom — pinch, double tap and focus alike — and honours the system text size
197
+ * instead (iOS Dynamic Type through `BfTextScaleService`, Android's font scale in the WebView).
198
+ * On the web the meta is never touched, so a web build keeps pinch zoom (the owner's ruling,
199
+ * audit §12): ship `index.html` without `maximum-scale`/`user-scalable`.
200
+ *
201
+ * With `provideBfShell()` on native iOS and Android (unless `syncSystemBars: false`) the status-bar
202
+ * and navigation-bar icons follow `dark()`: `SystemBars.setStyle()` with `bfSystemBarsStyle()`,
203
+ * on start and on every theme change (Android WebView < 140 keeps `Default`, see there).
204
+ * @summary Platform facts and the app theme: native or web, iOS or Android, light or dark
205
+ * @since 0.2.0
206
+ */
207
+ export declare class BfPlatformService {
208
+ private readonly document;
209
+ private readonly shellConfig;
210
+ private readonly storage;
211
+ /** True inside the native iOS or Android app, false in a browser. */
212
+ readonly isNative: boolean;
213
+ /** The platform the app runs on. */
214
+ readonly platform: BfPlatform;
215
+ /** The platform's shell mode: `ios` on iOS, else `md`; `resolveShellMode()` applies the config. */
216
+ readonly mode: import("@angular/core").Signal<BfShellMode>;
217
+ /** The user's theme choice, stored in `BF_THEME_STORAGE` (`localStorage`); set it with `theme.set(…)`. */
218
+ readonly theme: import("@angular/core").WritableSignal<BfTheme>;
219
+ private readonly systemDark;
220
+ /** Whether the app is dark now: the theme choice, or the system's under `system`. */
221
+ readonly dark: import("@angular/core").Signal<boolean>;
222
+ constructor();
223
+ /** The native system bars are outside the page; a failed call leaves them as they were. */
224
+ private applySystemBars;
225
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfPlatformService, never>;
226
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
227
+ }
228
+ /**
229
+ * The shell mode in effect: `config.mode`, or the platform's (`BfPlatformService.mode()`: iOS on
230
+ * iOS, else Material) when it is `'auto'`. The one resolution every mode-dependent part of the
231
+ * shell (stack outlet, modal, header, back button) shares; apps use it (or `injectShellMode()`)
232
+ * to follow the same per-mode conventions, e.g. text vs icon header actions.
233
+ *
234
+ * @example
235
+ * const mode = resolveShellMode(inject(BF_SHELL_CONFIG), inject(BfPlatformService));
236
+ * @param config The shell configuration, usually `inject(BF_SHELL_CONFIG)`.
237
+ * @param platform The platform service.
238
+ * @returns The mode in effect.
239
+ * @summary Resolves the shell mode in effect from the configuration and the platform
240
+ * @since 0.2.0
241
+ */
242
+ export declare function resolveShellMode(config: Readonly<BfShellConfig>, platform: BfPlatformService): BfShellMode;
243
+ /**
244
+ * `resolveShellMode()` from the injector: `BF_SHELL_CONFIG` (the defaults, i.e. `'auto'`, without
245
+ * `provideBfShell()`) and `BfPlatformService`. Call it in an injection context (a field
246
+ * initializer or constructor); the mode is fixed for the app's lifetime.
247
+ *
248
+ * @example
249
+ * protected readonly ios = injectShellMode() === 'ios';
250
+ * @returns The mode in effect.
251
+ * @summary Reads the shell mode in effect from the injector, iOS or Material
252
+ * @since 0.2.0
253
+ */
254
+ export declare function injectShellMode(): BfShellMode;
255
+ /**
256
+ * The hardware back button queue: on native Android it listens to `@capacitor/app`'s
257
+ * `backButton` event; on iOS and web nothing is registered (there is no hardware button to
258
+ * listen to), but `register` and `dispatch` still work so overlays and tests can drive the same
259
+ * queue. `register` adds a handler at a priority (an open overlay registers at 100,
260
+ * `BfNavController` at 0 — it pops the deepest active `bf-stack-outlet`); `dispatch` runs the
261
+ * queue from the highest priority down until one handler returns true; on equal priority the
262
+ * newest registration runs first, so stacked overlays close top-down. When none does (every
263
+ * stack is at its first page), the app moves to the background (`App.minimizeApp()`), so a
264
+ * relaunch resumes it warm; `provideBfShell({ backAtRoot: 'exit' })` finishes it instead
265
+ * (`App.exitApp()`).
266
+ *
267
+ * @example
268
+ * const unregister = backButton.register(100, () => {
269
+ * closeTopOverlay();
270
+ * return true;
271
+ * });
272
+ * @summary The Android hardware back button queue that overlays and navigation stacks share
273
+ * @since 0.2.0
274
+ */
275
+ export declare class BfBackButtonService {
276
+ private readonly platform;
277
+ private readonly destroyRef;
278
+ private readonly backAtRoot;
279
+ private readonly handlers;
280
+ private sequence;
281
+ constructor();
282
+ /**
283
+ * Adds a handler at `priority` (higher priority runs first; on a tie, the handler registered
284
+ * last runs first). Returns a function that removes
285
+ * it again; call it when the registrant (an overlay, an outlet) is torn down.
286
+ * @param priority Higher runs first: an open overlay uses 100, `BfNavController` 0.
287
+ * @param handler Returns (or resolves) true when it handled the press.
288
+ */
289
+ register(priority: number, handler: () => boolean | Promise<boolean>): () => void;
290
+ /**
291
+ * Runs the registered handlers from highest to lowest priority until one claims the event
292
+ * (returns true); when none does, minimizes the app (or exits it with `backAtRoot: 'exit'`).
293
+ * Public so tests and the native listener share one code path, and so overlays outside the
294
+ * native listener's reach (phase 2c) can still be driven by it, e.g. `Escape`.
295
+ */
296
+ dispatch(): Promise<void>;
297
+ private attachNativeListener;
298
+ private minimizeApp;
299
+ private exitApp;
300
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfBackButtonService, never>;
301
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
302
+ }
303
+ /**
304
+ * Impact weight, mapped to `ImpactStyle.Light` / `Medium` / `Heavy` on native.
305
+ *
306
+ * @summary The weight of an impact haptic, light, medium or heavy
307
+ * @since 0.2.0
308
+ */
309
+ type BfHapticsImpactStyle = 'light' | 'medium' | 'heavy';
310
+ /**
311
+ * Outcome of a task, mapped to `NotificationType.Success` / `Warning` / `Error` on native.
312
+ *
313
+ * @summary The outcome a notification haptic reports: success, warning or error
314
+ * @since 0.2.0
315
+ */
316
+ type BfHapticsNotificationType = 'success' | 'warning' | 'error';
317
+ /**
318
+ * Haptic feedback: `impact`, `selection` and `notification` forward to `@capacitor/haptics` on
319
+ * native (loaded lazily on first use, the import cached like `BfKeyboardService`'s plugin); on
320
+ * the web, and when the plugin fails to load (an app that didn't add the optional dependency),
321
+ * every method resolves as a silent no-op.
322
+ *
323
+ * @example
324
+ * const haptics = inject(BfHapticsService);
325
+ * await haptics.impact('light');
326
+ * @since 0.2.0
327
+ * @summary Haptic feedback on native devices that silently does nothing on the web
328
+ */
329
+ export declare class BfHapticsService {
330
+ private readonly platformService;
331
+ private modulePromise;
332
+ /**
333
+ * Impact feedback: a collision between UI elements of the given weight.
334
+ * @param style The weight of the impact.
335
+ */
336
+ impact(style: BfHapticsImpactStyle): Promise<void>;
337
+ /** A light tick for a discrete selection change (scrubbing a picker, crossing a threshold). */
338
+ selection(): Promise<void>;
339
+ /**
340
+ * Feedback for the outcome of a task.
341
+ * @param type The outcome of the task.
342
+ */
343
+ notification(type: BfHapticsNotificationType): Promise<void>;
344
+ private run;
345
+ /**
346
+ * Resolves the plugin, or `null` when it is not installed. The `import()` stays lexically inside
347
+ * the `try` so esbuild tolerates an unresolved optional peer at build time (as in
348
+ * `BfBackButtonService` and `BfKeyboardService`); a bare `import()` fails the consumer's build.
349
+ */
350
+ private loadPlugin;
351
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfHapticsService, never>;
352
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
353
+ }
354
+ /**
355
+ * Scales the root font size with iOS Dynamic Type inside the native shell. WKWebView resolves the
356
+ * system text style `font: -apple-system-body` to the user's text size (17 px at the default
357
+ * "Large", 21 px at xxL, 40 px at AX3, 53 px at AX5); a hidden, persistent probe element with that
358
+ * font gives the size, and `<html>` gets `font-size: probe / 17 × 100 %` (rounded to 0.1 %). Every
359
+ * type token and spacing step of the library is in `rem`, so text and rem-based layout grow
360
+ * together, as UIKit's Dynamic Type does.
361
+ *
362
+ * A `ResizeObserver` on the probe re-applies the scale when the setting changes while the app
363
+ * runs (WebKit re-resolves system fonts then); `visibilitychange` re-probes as the fallback. The
364
+ * scale never goes below 1 (the smaller iOS sizes, and a Mac running the iOS app, keep the design
365
+ * size) and is capped at `BfShellConfig.dynamicType.maxScale` (default 2.35; `Infinity` means no
366
+ * cap; `NaN` falls back to the default). A missing or non-finite probe value gives 1; at 1 the
367
+ * root font size is left unset.
368
+ *
369
+ * Acts only with `provideBfShell()` (which starts it at bootstrap), on native iOS, and while
370
+ * `dynamicType` is not `false`. Android needs nothing: its WebView applies the system font scale
371
+ * (`textZoom`) itself, so probing there would scale twice. On the web the browser's own text
372
+ * size and zoom apply. Destroying the service removes the probe, its listeners and the root font
373
+ * size.
374
+ *
375
+ * @example
376
+ * const textScale = inject(BfTextScaleService);
377
+ * const compact = computed(() => textScale.scale() > 1.5);
378
+ * @since 0.2.0
379
+ * @summary Follows iOS Dynamic Type by scaling the root font size of the app
380
+ */
381
+ export declare class BfTextScaleService {
382
+ private readonly document;
383
+ private readonly platformService;
384
+ private readonly config;
385
+ private readonly destroyRef;
386
+ private readonly scaleState;
387
+ /** Current root scale (1 = the system default "Large"); always 1 on Android and the web. */
388
+ readonly scale: import("@angular/core").Signal<number>;
389
+ constructor();
390
+ private createProbe;
391
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfTextScaleService, never>;
392
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
393
+ }
394
+ /**
395
+ * Keyboard lifecycle phase, for animations only; never gate logic on the order of the phases.
396
+ * `showing` starts at `keyboardWillShow`, `shown` at `keyboardDidShow`. Either hide event
397
+ * (`keyboardWillHide` or `keyboardDidHide`, whichever arrives first — iOS does not guarantee
398
+ * the order) moves straight to `hidden`, so there is no `hiding` phase.
399
+ *
400
+ * @summary The soft keyboard phase, hidden, showing or shown, for animations only
401
+ * @since 0.2.0
402
+ */
403
+ type BfKeyboardPhase = 'hidden' | 'showing' | 'shown';
404
+ /**
405
+ * True for an element that opens the soft keyboard when focused: a text-like `input` (not a
406
+ * button, checkbox, color, file, hidden, image, radio, range, reset or submit), a `textarea`, or
407
+ * a `[contenteditable]` element other than `contenteditable="false"`.
408
+ *
409
+ * @param element The element to test, usually `document.activeElement`.
410
+ * @returns Whether it opens the soft keyboard.
411
+ * @summary Tells whether focusing an element opens the soft keyboard on a phone
412
+ * @since 0.2.0
413
+ */
414
+ export declare function isTextEntry(element: Element | null): element is HTMLElement;
415
+ /**
416
+ * The soft keyboard as signals. On native it listens to the Capacitor Keyboard plugin
417
+ * (`@capacitor/keyboard`, loaded lazily, height known at `keyboardWillShow`); on the web it falls
418
+ * back to `visualViewport` resizes with an 80 px threshold (height known only once the viewport has
419
+ * shrunk; ignored while the page is pinch-zoomed, `visualViewport.scale` ≠ 1); in Jest and SSR it
420
+ * stays inert (height 0, never visible). The rest height (viewport with the keyboard hidden) comes
421
+ * from a fixed `100lvh` probe element, never `innerHeight`, which sticks at a wrong value after a
422
+ * field-to-field focus jump on iOS; it is measured at construction and on window resizes while the
423
+ * keyboard is hidden and no text control is focused, never at will-show. `imminent` flags a focused
424
+ * text control before any keyboard event, and `keyboardTop()` gives the keyboard's top edge in
425
+ * viewport px. It also writes the height as `--bf-keyboard-height` on `<html>` (`0px` while hidden)
426
+ * for CSS that follows the keyboard.
427
+ *
428
+ * @example
429
+ * const keyboard = inject(BfKeyboardService);
430
+ * const hideTabBar = computed(() => keyboard.visible());
431
+ * @since 0.2.0
432
+ * @summary The soft keyboard state as signals: visible, its height and its phase
433
+ */
434
+ export declare class BfKeyboardService {
435
+ private readonly platformService;
436
+ private readonly document;
437
+ private readonly destroyRef;
438
+ private readonly heightState;
439
+ private readonly phaseState;
440
+ private readonly restHeightState;
441
+ private readonly willShowState;
442
+ private readonly imminentState;
443
+ private imminentTarget;
444
+ private imminentTimer;
445
+ private plugin;
446
+ private probe;
447
+ private destroyed;
448
+ /** Keyboard height in CSS px (iOS: includes the home-indicator strip); 0 when hidden. */
449
+ readonly height: import("@angular/core").Signal<number>;
450
+ /** Lifecycle phase for animations; see `BfKeyboardPhase`. */
451
+ readonly phase: import("@angular/core").Signal<BfKeyboardPhase>;
452
+ /** True from will-show until either hide event: the moment to hide chrome such as the tab bar. */
453
+ readonly visible: import("@angular/core").Signal<boolean>;
454
+ /** True when the keyboard overlays the WebView (native iOS, `resize: 'none'`); false when the WebView resizes. */
455
+ readonly overlaysContent: import("@angular/core").Signal<boolean>;
456
+ /** Viewport height with the keyboard hidden, in CSS px, from a fixed `100lvh` probe. */
457
+ readonly restHeight: import("@angular/core").Signal<number>;
458
+ /** Increments once per keyboard show (at will-show), for one-off reactions such as closing popovers. */
459
+ readonly willShow: import("@angular/core").Signal<number>;
460
+ /**
461
+ * True from `focusin` on a text-entry control (see `isTextEntry`) until that control's
462
+ * `focusout` or either keyboard hide event; never cleared by will-show. Hide chrome such as the
463
+ * tab bar on `visible() || imminent()`: on Android the WebView shrinks before the plugin's
464
+ * will-show, which lifts `position: fixed` elements above the keyboard; `focusin` is the only
465
+ * earlier signal. When it turns true without the keyboard up, it also clears itself after
466
+ * `IMMINENT_TIMEOUT_MS` (2500 ms) unless will-show or a visible keyboard arrives first, so a
467
+ * hardware keyboard, which fires no keyboard event, does not keep the tab bar hidden.
468
+ */
469
+ readonly imminent: import("@angular/core").Signal<boolean>;
470
+ constructor();
471
+ /** Hides the keyboard: `Keyboard.hide()` on native, blurs the focused element on the web. */
472
+ hide(): Promise<void>;
473
+ /**
474
+ * The keyboard's top edge in viewport CSS px, read on demand. While the keyboard overlays the
475
+ * WebView (native iOS) it is `restHeight() - height()`; where the viewport shrinks for it
476
+ * (Android, the web) it is the bottom of `visualViewport` (else `innerHeight`). With the
477
+ * keyboard hidden it is `restHeight()`.
478
+ */
479
+ keyboardTop(): number;
480
+ private createProbe;
481
+ private measureRestHeight;
482
+ /** Never measures the rest height: on Android the WebView has already shrunk by will-show. */
483
+ private onWillShow;
484
+ private onDidShow;
485
+ private onHidden;
486
+ /** Either plugin hide event: the keyboard is gone even if the control keeps focus. */
487
+ private onHideEvent;
488
+ private clearImminent;
489
+ /** Arms the hardware-keyboard fallback; a keyboard already up needs none. */
490
+ private armImminentTimeout;
491
+ private cancelImminentTimeout;
492
+ private setHeight;
493
+ private writeHeightVariable;
494
+ private attachPlugin;
495
+ private attachVisualViewport;
496
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfKeyboardService, never>;
497
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
498
+ }
499
+ /**
500
+ * Provides the mobile shell: its configuration, the stack-aware route reuse strategy
501
+ * (`BfStackReuseStrategy`) and `BF_OVERLAY_HOST` (the hardware back button closes the top overlay
502
+ * through `BfBackButtonService`, which on native Android also stands in for the overlays'
503
+ * `CloseWatcher`, and the document never scrolls, so overlays skip the scroll lock). An environment initializer starts `BfPlatformService` (theme sync, the `dark` class),
504
+ * `BfBackButtonService` (the Android hardware back listener), `BfKeyboardService` (keyboard
505
+ * listeners and the rest-height probe), `BfHapticsService` (its native plugin loads lazily on first
506
+ * use, so this only makes the singleton available) and `BfTextScaleService` (iOS Dynamic Type on
507
+ * the root font size) at bootstrap, before any page renders. Every service is
508
+ * `providedIn: 'root'`, so this function lists none of them: `BfNavController` and the overlay
509
+ * services (`BfOverlayStack`, `BfOverlayService`, `BfSheetService`, `BfModalService`,
510
+ * `BfToastService`, `BfActionSheetService`, `BfAlertDialogService`) are created on first
511
+ * injection, and an app that never injects an overlay service bundles no overlay code. Use it
512
+ * together with `provideRouter(routes, withComponentInputBinding(), withBfShellRouting())`, in the
513
+ * application providers: in a lazy route's environment injector the services still resolve from
514
+ * the root injector.
515
+ *
516
+ * @param config The settings to change; any left out keep `BF_SHELL_DEFAULTS`.
517
+ * @returns The shell's environment providers.
518
+ * @summary Provides the Capacitor app shell: its configuration, navigation and platform services
519
+ * @since 0.2.0
520
+ */
521
+ export declare function provideBfShell(config?: Partial<BfShellConfig>): EnvironmentProviders;
522
+ /**
523
+ * The router feature the stack needs: `canceledNavigationResolution: 'computed'`, so a refused
524
+ * back navigation (a guard stopping a swipe-back) restores the browser history position and the
525
+ * stack stays in sync with it. Pass it to `provideRouter()`.
526
+ *
527
+ * @returns The router configuration feature.
528
+ * @summary The router setting the mobile shell's stack needs, passed to provideRouter
529
+ * @since 0.2.0
530
+ */
531
+ export declare function withBfShellRouting(): RouterConfigurationFeature;
532
+ /**
533
+ * The route reuse strategy the stack needs: the default one, except that a route whose *path
534
+ * params* change (`/items/4` → `/items/5`) is a new page, not an in-place update. The default only
535
+ * compares `routeConfig`, so the router would reuse the component and never call the outlet, and
536
+ * the stack would no longer match the history. Query-param changes still reuse the page (filters,
537
+ * tabs). Exported so an app can extend it for its own reuse rules.
538
+ * @summary Route reuse strategy that treats a changed path parameter as a new stack page
539
+ * @since 0.2.0
540
+ */
541
+ export declare class BfStackReuseStrategy extends BaseRouteReuseStrategy {
542
+ /**
543
+ * Whether the router may reuse the current page for `future`: same route config and path params.
544
+ * @param future The route being navigated to.
545
+ * @param curr The route shown now.
546
+ * @returns True to reuse the page in place.
547
+ */
548
+ shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean;
549
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfStackReuseStrategy, never>;
550
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
551
+ }
552
+ /**
553
+ * Where a stacked page is in its lifecycle.
554
+ *
555
+ * @summary Where a stacked page is in its lifecycle: entering, active, leaving or inactive
556
+ * @since 0.2.0
557
+ */
558
+ type BfViewState = 'entering' | 'active' | 'leaving' | 'inactive';
559
+ /**
560
+ * One lifecycle event of a stacked page.
561
+ *
562
+ * @summary The four lifecycle events of a stacked page as it enters and leaves
563
+ * @since 0.2.0
564
+ */
565
+ type BfViewEvent = 'willEnter' | 'didEnter' | 'willLeave' | 'didLeave';
566
+ /**
567
+ * Per-page lifecycle. `bf-stack-outlet` creates one per page and provides it through the page's
568
+ * element injector; `bf-page` re-exposes it as outputs, and any page or service can
569
+ * `inject(BfViewLifecycle)` to react to the page entering or leaving the top of the stack.
570
+ * `state` and the counters are signals for `computed`/`effect`; `on()` delivers every event
571
+ * synchronously, including the ones that happen before the page's first change detection and
572
+ * right before a popped page is destroyed.
573
+ * @summary The lifecycle of one stacked page as signals and events, from enter to leave
574
+ * @since 0.2.0
575
+ */
576
+ export declare class BfViewLifecycle {
577
+ /** The page's current lifecycle state. */
578
+ readonly state: import("@angular/core").WritableSignal<BfViewState>;
579
+ /** How often the page started entering; monotonic, so a page can `effect()` on it. */
580
+ readonly willEnter: import("@angular/core").WritableSignal<number>;
581
+ /** How often the page became the top page (its enter transition ended). */
582
+ readonly didEnter: import("@angular/core").WritableSignal<number>;
583
+ /** How often the page started leaving the top of the stack. */
584
+ readonly willLeave: import("@angular/core").WritableSignal<number>;
585
+ /** How often the page stopped being the top page (its leave transition ended). */
586
+ readonly didLeave: import("@angular/core").WritableSignal<number>;
587
+ private readonly listeners;
588
+ /**
589
+ * Calls `listener` synchronously on every event; returns a function that removes it.
590
+ * @param listener Called with each event, synchronously.
591
+ */
592
+ on(listener: (event: BfViewEvent) => void): () => void;
593
+ /**
594
+ * Moves the page to its `willEnter` state and notifies; called by `bf-stack-outlet`.
595
+ * @internal
596
+ */
597
+ fireWillEnter(): void;
598
+ /**
599
+ * Moves the page to its `didEnter` state and notifies; called by `bf-stack-outlet`.
600
+ * @internal
601
+ */
602
+ fireDidEnter(): void;
603
+ /**
604
+ * Moves the page to its `willLeave` state and notifies; called by `bf-stack-outlet`.
605
+ * @internal
606
+ */
607
+ fireWillLeave(): void;
608
+ /**
609
+ * Moves the page to its `didLeave` state and notifies; called by `bf-stack-outlet`.
610
+ * @internal
611
+ */
612
+ fireDidLeave(): void;
613
+ private notify;
614
+ }
615
+ /**
616
+ * The direction a navigation should animate in.
617
+ *
618
+ * @summary The direction a stack navigation animates in: forward, back or a new root
619
+ * @since 0.2.0
620
+ */
621
+ type BfNavDirection = 'forward' | 'back' | 'root';
622
+ /**
623
+ * A router target: a URL string, a `UrlTree` or a commands array, as `Router` accepts.
624
+ *
625
+ * @summary A navigation target as the router accepts it: a URL, a UrlTree or commands
626
+ * @since 0.2.0
627
+ */
628
+ type BfNavTarget = string | UrlTree | readonly unknown[];
629
+ /** What a stack outlet tells `BfNavController` when it registers (see `registerOutlet`). */
630
+ interface BfNavOutlet {
631
+ /** Number of pages in the outlet's shown stack. */
632
+ readonly depth: Signal<number>;
633
+ /** False while the page that hosts the outlet is parked under another page (or leaving). */
634
+ readonly active: Signal<boolean>;
635
+ /** The (negative) history step that pops the outlet's top page, or null when unknown. */
636
+ popDelta(): number | null;
637
+ }
638
+ /**
639
+ * Stack-aware navigation. `forward` pushes, `back` pops through the real history (so the browser
640
+ * or WebView history stays in sync), `root` replaces the whole stack. Each call leaves a direction
641
+ * hint that `bf-stack-outlet` consumes on the next activation; without a hint the outlet infers
642
+ * the direction from the router event. A hint lives only as long as the navigation it started:
643
+ * when that navigation ends without an activation (a guard refused it), the hint is dropped so it
644
+ * cannot mislabel the next one. Every primary `bf-stack-outlet` registers here with its nesting
645
+ * level; `depth`, `canGoBack` and `back()` follow the **deepest active outlet** (the innermost one
646
+ * whose page is shown, e.g. the outlet inside `bf-tabs`, or the root outlet once it pushed a page
647
+ * above the tabs page). The controller also owns the priority-0 hardware back handler: it pops the
648
+ * deepest active outlet that has a page to pop, and lets the app exit only when every active
649
+ * outlet is at its first page (a parked outlet cannot be popped, so it never blocks the exit).
650
+ * @summary Stack-aware navigation that pushes, pops through the history and replaces the root
651
+ * @since 0.2.0
652
+ */
653
+ export declare class BfNavController {
654
+ private readonly router;
655
+ private readonly location;
656
+ private readonly outlets;
657
+ private hint;
658
+ /** Id of the navigation the hint belongs to; null until that navigation starts. */
659
+ private hintNavigationId;
660
+ /** The active outlets, deepest first (on equal level, the one registered last first). */
661
+ private readonly activeOutlets;
662
+ /** Number of pages in the deepest active stack outlet (0 without an outlet). */
663
+ readonly depth: Signal<number>;
664
+ /** True when the deepest active stack has a page to go back to. */
665
+ readonly canGoBack: Signal<boolean>;
666
+ constructor();
667
+ /**
668
+ * Pushes a page.
669
+ * @param url Where to go.
670
+ * @param extras Router navigation extras, such as `queryParams`.
671
+ * @returns Whether the navigation succeeded.
672
+ */
673
+ forward(url: BfNavTarget, extras?: NavigationExtras): Promise<boolean>;
674
+ /**
675
+ * Replaces the whole stack with one page (`replaceUrl`, no animation).
676
+ * @param url Where to go.
677
+ * @param extras Router navigation extras, such as `queryParams`.
678
+ * @returns Whether the navigation succeeded.
679
+ */
680
+ root(url: BfNavTarget, extras?: NavigationExtras): Promise<boolean>;
681
+ /**
682
+ * Pops the top page of the deepest active outlet that has one to pop: always a real history
683
+ * step. When the page added history entries of its own (a query-only or nested child
684
+ * navigation), it goes back past them in one step (`Location.historyGo(-n)`) so the page below
685
+ * is shown; otherwise `Location.back()`.
686
+ */
687
+ back(): void;
688
+ /**
689
+ * Called by every primary stack outlet on init with its nesting level (the number of stack
690
+ * outlets around it). Returns a function that removes it again.
691
+ * @internal
692
+ */
693
+ registerOutlet(outlet: BfNavOutlet, level: number): () => void;
694
+ /**
695
+ * Returns the pending direction hint and clears it; called by the stack outlet.
696
+ * @internal
697
+ */
698
+ consumeHint(): BfNavDirection | null;
699
+ /**
700
+ * Drops a pending hint (its navigation never happened).
701
+ * @internal
702
+ */
703
+ clearHint(): void;
704
+ /** The deepest active outlet with a page to pop, else the deepest active outlet. */
705
+ private popTarget;
706
+ /**
707
+ * The hardware back button: pops while an active outlet has a page to pop; returns false (and
708
+ * the back button service exits the app) when every active outlet is at depth 1 or less. A
709
+ * parked outlet cannot be popped by `back()`, so it does not keep the app from exiting.
710
+ */
711
+ private handleBackButton;
712
+ private setHint;
713
+ private go;
714
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfNavController, never>;
715
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
716
+ }
717
+ /**
718
+ * Motion constants of the mobile shell, shared by the page transitions, the overlays and the
719
+ * refresher. `theme.css` mirrors them for CSS: `--ease-ios`, `--ease-md`, `--ease-settle`
720
+ * (`@theme`) and `--bf-duration-fast`, `--bf-duration-overlay`, `--bf-duration-push` (`:root`).
721
+ */
722
+ /**
723
+ * UIKit's navigation and sheet curve (push/pop, overlays, modal depth); `OVERLAY_EASING` too.
724
+ *
725
+ * @summary The UIKit navigation and sheet easing curve of pushes, pops and overlays
726
+ * @since 0.2.0
727
+ */
728
+ export declare const IOS_EASING = "cubic-bezier(0.32, 0.72, 0, 1)";
729
+ /**
730
+ * Material standard easing (the Android fade-up).
731
+ *
732
+ * @summary The Material standard easing curve of the Android page fade-up transition
733
+ * @since 0.2.0
734
+ */
735
+ export declare const MD_EASING = "cubic-bezier(0.2, 0, 0, 1)";
736
+ /**
737
+ * Ease-out of a released gesture settling into place (swipe-back, refresher).
738
+ *
739
+ * @summary The ease-out curve a released swipe-back or refresher gesture settles with
740
+ * @since 0.2.0
741
+ */
742
+ export declare const SETTLE_EASING = "cubic-bezier(0.2, 0.8, 0.3, 1)";
743
+ /**
744
+ * Colour transitions and the reduced-motion cross-fade (ms); the overlay core's reduced fade.
745
+ *
746
+ * @summary The duration of colour transitions and the reduced-motion fade, in milliseconds
747
+ * @since 0.2.0
748
+ */
749
+ export declare const DURATION_FAST = 150;
750
+ /**
751
+ * Overlay enter/exit and the modal depth effect (ms); the overlay core's duration.
752
+ *
753
+ * @summary The duration of overlay enter and exit and the modal depth effect, in milliseconds
754
+ * @since 0.2.0
755
+ */
756
+ export declare const DURATION_OVERLAY = 260;
757
+ /**
758
+ * iOS push/pop (ms).
759
+ *
760
+ * @summary The duration of the iOS push and pop page transitions, in milliseconds
761
+ * @since 0.2.0
762
+ */
763
+ export declare const DURATION_PUSH = 500;
764
+ /**
765
+ * Material fade-up and the refresher settle (ms).
766
+ *
767
+ * @summary The duration of the Material fade-up and the refresher settle, in milliseconds
768
+ * @since 0.2.0
769
+ */
770
+ export declare const DURATION_MD = 220;
771
+ /**
772
+ * The iOS push and pop (ms), `DURATION_PUSH`.
773
+ *
774
+ * @summary The duration of the iOS push and pop stack transitions, in milliseconds
775
+ * @since 0.2.0
776
+ */
777
+ export declare const IOS_DURATION = 500;
778
+ /**
779
+ * Upper bound of the settle animation after a released swipe.
780
+ *
781
+ * @summary The longest a released swipe-back may take to settle, in milliseconds
782
+ * @since 0.2.0
783
+ */
784
+ export declare const MAX_COMPLETE_MS = 540;
785
+ /**
786
+ * Material fade-up.
787
+ *
788
+ * @summary The duration of the Material fade-up stack transition, in milliseconds
789
+ * @since 0.2.0
790
+ */
791
+ export declare const MD_DURATION = 220;
792
+ /**
793
+ * Cross-fade used under `prefers-reduced-motion`.
794
+ *
795
+ * @summary The duration of the cross-fade that replaces page motion under reduced motion
796
+ * @since 0.2.0
797
+ */
798
+ export declare const REDUCED_DURATION = 150;
799
+ /**
800
+ * A running set of animations that finish together.
801
+ *
802
+ * @summary A running set of page transition animations that finish together
803
+ * @since 0.2.0
804
+ */
805
+ interface BfStackTransition {
806
+ /** The Web Animations of the transition, one per moving layer. */
807
+ readonly animations: Animation[];
808
+ /** Their shared duration (ms). */
809
+ readonly duration: number;
810
+ /** Resolves when every animation finished or was cancelled; never rejects. */
811
+ readonly finished: Promise<void>;
812
+ }
813
+ /**
814
+ * The direction of a stack transition: a page pushed on, or popped off.
815
+ *
816
+ * @summary The direction of a stack transition, a page pushed on or popped off
817
+ * @since 0.2.0
818
+ */
819
+ type BfTransitionKind = 'push' | 'pop';
820
+ /**
821
+ * The iOS push or pop. `pop` is written as the literal reverse of a push but as forward
822
+ * keyframes, so `currentTime` maps directly to swipe progress (0 = nothing moved, duration = pop
823
+ * complete). Returns three animations: the top page (slide and edge shadow), the page under it
824
+ * (parallax) and the dim layer.
825
+ *
826
+ * @param kind `push` or `pop`.
827
+ * @param entering The page that becomes visible.
828
+ * @param leaving The page that goes away.
829
+ * @param dim The dimming layer between the two pages.
830
+ * @param width The width the pages travel (the outlet width, px).
831
+ * @param easing The curve of the transition.
832
+ * @returns The three running animations.
833
+ * @summary Builds the iOS push or pop with its slide, parallax and dimming layers
834
+ * @since 0.2.0
835
+ */
836
+ export declare function createTransition(kind: BfTransitionKind, entering: HTMLElement, leaving: HTMLElement, dim: HTMLElement, width: number, easing?: string): BfStackTransition;
837
+ /**
838
+ * Material fade-up: the entering page fades in while rising 16 px; a pop is the reverse on the
839
+ * leaving page. No parallax, no dim.
840
+ *
841
+ * @param kind `push` or `pop`.
842
+ * @param entering The page that becomes visible.
843
+ * @param leaving The page that goes away.
844
+ * @returns The running animation.
845
+ * @summary Builds the Material fade-up page transition of a push or a pop
846
+ * @since 0.2.0
847
+ */
848
+ export declare function mdTransition(kind: BfTransitionKind, entering: HTMLElement, leaving: HTMLElement): BfStackTransition;
849
+ /**
850
+ * Reduced motion: a 150 ms cross-fade of the two pages, nothing moves.
851
+ *
852
+ * @param entering The page that becomes visible.
853
+ * @param leaving The page that goes away.
854
+ * @returns The two running fades.
855
+ * @summary Builds the cross-fade that replaces page motion when the user reduces motion
856
+ * @since 0.2.0
857
+ */
858
+ export declare function reducedTransition(entering: HTMLElement, leaving: HTMLElement): BfStackTransition;
859
+ /**
860
+ * Frame values of the pop at progress `p` (0 = start, 1 = done), used to hand a scrubbed gesture
861
+ * over to a fresh eased animation on release.
862
+ *
863
+ * @param p The pop progress, 0 (start) to 1 (done).
864
+ * @param width The outlet width (px).
865
+ * @returns The top page offset, the page under it and the dim opacity.
866
+ * @summary The positions of the pop layers at a given progress, for scrubbing a swipe
867
+ * @since 0.2.0
868
+ */
869
+ export declare function popFramesAt(p: number, width: number): {
870
+ top: number;
871
+ under: number;
872
+ dim: number;
873
+ };
874
+ /**
875
+ * Animates top, under and dim from pop progress `from` to `to` with an ease-out.
876
+ *
877
+ * @param top The page being popped.
878
+ * @param under The page under it.
879
+ * @param dim The dimming layer.
880
+ * @param width The outlet width (px).
881
+ * @param from The progress at release, 0 to 1.
882
+ * @param to The progress to settle at: 1 completes the pop, 0 cancels it.
883
+ * @param duration The settle duration (ms), see `settleDuration`.
884
+ * @returns The three running animations.
885
+ * @summary Animates a released swipe-back from its progress to done or back to the start
886
+ * @since 0.2.0
887
+ */
888
+ export declare function settlePop(top: HTMLElement, under: HTMLElement, dim: HTMLElement, width: number, from: number, to: number, duration: number): BfStackTransition;
889
+ /**
890
+ * The release rule of the swipe-back: a flick (`velocity` above 0.2 px/ms) or a drag past half
891
+ * the width completes the pop; anything else settles back.
892
+ *
893
+ * @param velocity The release speed (px/ms, positive towards the end edge).
894
+ * @param delta The distance swiped (px).
895
+ * @param width The outlet width (px).
896
+ * @returns True when the pop completes.
897
+ * @summary Decides whether a released swipe-back completes the pop or settles back
898
+ * @since 0.2.0
899
+ */
900
+ export declare function shouldCompletePop(velocity: number, delta: number, width: number): boolean;
901
+ /**
902
+ * Duration of the settle animation after a release: the remaining distance at the release speed
903
+ * (at least 0.5 px/ms), clamped to 120 ms … `MAX_COMPLETE_MS`.
904
+ *
905
+ * @param remainingPx The distance left to travel (px).
906
+ * @param velocity The release speed (px/ms).
907
+ * @returns The duration (ms), 120 to `MAX_COMPLETE_MS`.
908
+ * @summary The duration of the settle animation after a released swipe-back gesture
909
+ * @since 0.2.0
910
+ */
911
+ export declare function settleDuration(remainingPx: number, velocity: number): number;
912
+ /**
913
+ * Emitted by `bf-stack-outlet` after every change of its stack.
914
+ *
915
+ * @summary What a stack outlet reports after its stack changed: the depth and the tab
916
+ * @since 0.2.0
917
+ */
918
+ interface BfStackChange {
919
+ /** Number of pages in the active stack. */
920
+ depth: number;
921
+ /** Key of the active tab's stack inside `bf-tabs`; null for an outlet outside `bf-tabs`. */
922
+ tabKey: string | null;
923
+ }
924
+ /**
925
+ * Emitted by `bf-stack-outlet` around a transition between two pages.
926
+ *
927
+ * @summary What a stack outlet reports around a page transition: its kind and animation
928
+ * @since 0.2.0
929
+ */
930
+ interface BfStackTransitionEvent {
931
+ /** `push` for a new page (also a `replaceUrl` navigation), `pop` for going back. */
932
+ kind: BfTransitionKind;
933
+ /** False when the pages switched without an animation (`animated=false`). */
934
+ animated: boolean;
935
+ }
936
+ /**
937
+ * A router outlet that keeps a stack of live pages: a push slides the new page in and parks the
938
+ * previous one (still in the DOM, so scroll and state survive), a pop slides the top page out and
939
+ * destroys it, and on iOS a finger's edge swipe scrubs the pop (touch only: a mouse or pen drag
940
+ * never arms it). `provideBfShell({ maxLivePages })` bounds the live pages of each stack: the
941
+ * deepest ones are destroyed and created again, scroll restored, on a pop back to them. Replaces
942
+ * `<router-outlet>` in a mobile app.
943
+ * Pages receive route params, query params and route data as inputs, bound by the outlet itself.
944
+ * Inside `bf-tabs` it keeps one stack per tab and switches between them without a transition.
945
+ * Outlets nest: an outlet inside a page (the tabs page) keeps its stacks while an outer outlet
946
+ * parks that page, and `BfNavController` follows the innermost outlet whose page is shown.
947
+ *
948
+ * @example
949
+ * <bf-stack-outlet />
950
+ * @summary Router outlet keeping a live page stack with slide transitions and iOS swipe back
951
+ * @category Navigation
952
+ * @since 0.2.0
953
+ */
954
+ export declare class BfStackOutletComponent implements RouterOutletContract, OnInit, AfterViewInit, OnDestroy {
955
+ /** Outlet name, as on `router-outlet`. */
956
+ readonly name: import("@angular/core").InputSignal<string>;
957
+ /** Enables the iOS edge swipe-back for this outlet (ignored in Material mode). */
958
+ readonly swipeGesture: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
959
+ /** Animates push and pop; false switches pages instantly (lifecycle events still fire). */
960
+ readonly animated: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
961
+ /** Emitted with the new depth after every change of the stack. */
962
+ readonly stackChanged: import("@angular/core").OutputEmitterRef<BfStackChange>;
963
+ /** Emitted when a transition between two pages starts (also the start of a swipe-back). */
964
+ readonly transitionStarted: import("@angular/core").OutputEmitterRef<BfStackTransitionEvent>;
965
+ /** Emitted when a transition between two pages has settled. */
966
+ readonly transitionEnded: import("@angular/core").OutputEmitterRef<BfStackTransitionEvent>;
967
+ /**
968
+ * Emitted with the new depth after every change of the stack, together with `stackChanged`.
969
+ * @deprecated 0.3.0 use stackChanged; removed in 0.4.0
970
+ */
971
+ readonly stackChange: import("@angular/core").OutputEmitterRef<BfStackChange>;
972
+ /**
973
+ * Emitted when a transition starts, together with `transitionStarted`.
974
+ * @deprecated 0.3.0 use transitionStarted; removed in 0.4.0
975
+ */
976
+ readonly transitionStart: import("@angular/core").OutputEmitterRef<BfStackTransitionEvent>;
977
+ /**
978
+ * Emitted when a transition has settled, together with `transitionEnded`.
979
+ * @deprecated 0.3.0 use transitionEnded; removed in 0.4.0
980
+ */
981
+ readonly transitionEnd: import("@angular/core").OutputEmitterRef<BfStackTransitionEvent>;
982
+ readonly supportsBindingToComponentInputs: true;
983
+ private readonly parentContexts;
984
+ private readonly router;
985
+ private readonly location;
986
+ private readonly nav;
987
+ private readonly overlays;
988
+ private readonly config;
989
+ private readonly platform;
990
+ private readonly host;
991
+ private readonly document;
992
+ private readonly tabContext;
993
+ /** The stack outlet around this one (this outlet is inside one of its pages), if any. */
994
+ private readonly parentOutlet;
995
+ /** The page of the parent outlet this outlet lives in, if any. */
996
+ private readonly outletHost;
997
+ /** Lifecycle of the page hosting this outlet (null for a root outlet); forwarded to our page. */
998
+ private readonly hostLifecycle;
999
+ /** Removes the listener on `hostLifecycle`. */
1000
+ private hostLifecycleOff;
1001
+ /** Number of stack outlets around this one: 0 for the root outlet. */
1002
+ private readonly level;
1003
+ /** False while the page hosting this outlet is parked, so none of its pages is shown. */
1004
+ private readonly shown;
1005
+ private readonly depthState;
1006
+ private readonly anchor;
1007
+ private readonly dim;
1008
+ private readonly mode;
1009
+ private readonly injector;
1010
+ /** Pages of one stack kept alive (`BfShellConfig.maxLivePages`): at least 1, else every page. */
1011
+ private readonly maxLivePages;
1012
+ /** One stack per tab key inside `bf-tabs`; a single stack under the `null` key otherwise. */
1013
+ private readonly stacks;
1014
+ /** Key of the stack that is shown; always null outside `bf-tabs`. */
1015
+ private activeTab;
1016
+ private active;
1017
+ private leaving;
1018
+ /**
1019
+ * The page deactivated while the host page was parked (an outer outlet pushed above it): kept,
1020
+ * with every stack, and resumed as it was when the host page comes back.
1021
+ */
1022
+ private suspended;
1023
+ private pending;
1024
+ private viewReady;
1025
+ /** The running transition and the completion that must run if it gets interrupted. */
1026
+ private current;
1027
+ /** Final frame of a completed swipe, held until the router re-activates the page below. */
1028
+ private held;
1029
+ /** Set while the swipe gesture has already animated the pop the router now performs. */
1030
+ private gestureCommitted;
1031
+ private gesture;
1032
+ private lastStart;
1033
+ private destroyed;
1034
+ /** Pending rAF of the deferred transition start. */
1035
+ private startFrame;
1036
+ /** Fallback timer after a completed swipe's `Location.back()`. */
1037
+ private backFallback;
1038
+ /** Unregisters this outlet from `BfNavController`; primary outlets only. */
1039
+ private navUnregister;
1040
+ /** Unregisters the host as a page root of `BfOverlayStack`; outermost outlets only. */
1041
+ private rootUnregister;
1042
+ /** History position after the last completed navigation (see `pageIdOf`). */
1043
+ private settledPageId;
1044
+ /** Element that had focus in the top page when a swipe was claimed, restored on cancel. */
1045
+ private swipeFocus;
1046
+ /** The stack that is shown (the active tab's stack inside `bf-tabs`). */
1047
+ private get stack();
1048
+ constructor();
1049
+ get isActivated(): boolean;
1050
+ get component(): object;
1051
+ get activatedRoute(): ActivatedRoute;
1052
+ get activatedRouteData(): Data;
1053
+ get activatedComponentRef(): ComponentRef<unknown> | null;
1054
+ ngOnInit(): void;
1055
+ ngAfterViewInit(): void;
1056
+ ngOnDestroy(): void;
1057
+ /**
1058
+ * The router tears down the active page. It is NOT destroyed here: it either stays under the
1059
+ * next page (push) or is removed after the pop animation (decided in `activateWith`).
1060
+ * @internal
1061
+ */
1062
+ deactivate(): void;
1063
+ /**
1064
+ * The router shows a page: pushed, popped to, or a new root (the router outlet contract).
1065
+ * @internal
1066
+ */
1067
+ activateWith(activatedRoute: ActivatedRoute, environmentInjector: EnvironmentInjector): void;
1068
+ /**
1069
+ * Only called by a store/retrieve `RouteReuseStrategy`; the stack itself never needs one.
1070
+ * @internal
1071
+ */
1072
+ detach(): ComponentRef<unknown>;
1073
+ /**
1074
+ * Re-attaches a page a store/retrieve `RouteReuseStrategy` kept (the router outlet contract).
1075
+ * @internal
1076
+ */
1077
+ attach(ref: ComponentRef<unknown>, activatedRoute: ActivatedRoute): void;
1078
+ /**
1079
+ * The URL of the top page of a tab's stack (inside `bf-tabs`), or null when that tab has no
1080
+ * stack yet. `bf-tabs` navigates there on a tab switch, so the tab comes back as it was left.
1081
+ * @param tabKey The key of the tab, the URL segment after `tabsPath`.
1082
+ */
1083
+ lastUrlOf(tabKey: string): string | null;
1084
+ /**
1085
+ * Pops the active stack back to its first page in one history step (`Location.historyGo(-n)`
1086
+ * to the entry before the second page was pushed), keeping that page alive. Returns false, and
1087
+ * does nothing, when the stack has one page or the history position is unknown.
1088
+ */
1089
+ popToRoot(): boolean;
1090
+ /**
1091
+ * Scrolls the active page's `bf-content` back to the top (a re-selected tab).
1092
+ * @param behavior `smooth` (the default) or `instant`.
1093
+ */
1094
+ scrollActiveContentToTop(behavior?: ScrollBehavior): void;
1095
+ /**
1096
+ * A navigation onto another tab's key: parks the whole current stack and shows the target
1097
+ * stack (its page for this URL, the pages above it dropped) or starts it with a new page. No
1098
+ * transition and no gesture; `fresh` (a `root` navigation) discards the target stack first.
1099
+ */
1100
+ private switchStack;
1101
+ /** Shows a page of the stack again: a live one as it was, a dormant one created anew. */
1102
+ private bringBack;
1103
+ /**
1104
+ * Creates a dormant page again from the route the router re-activated, in a new frame, keeping
1105
+ * its record (key, history position, URL); its scroller gets the `scrollTop` it had back after
1106
+ * the first render. Its nested outlets start empty ("deep pages come back fresh").
1107
+ */
1108
+ private revive;
1109
+ /**
1110
+ * Keeps at most `maxLivePages` pages of the shown stack alive: the deepest ones beyond it go
1111
+ * dormant (component destroyed, frame removed, record kept). The top pages stay alive.
1112
+ */
1113
+ private trimStack;
1114
+ private makeDormant;
1115
+ /** Shows a kept page again: new route, nested outlets re-attached, change detection back on. */
1116
+ private reactivate;
1117
+ private tabOf;
1118
+ private destroyAllStacks;
1119
+ private classify;
1120
+ private createEntry;
1121
+ /**
1122
+ * Moves the page host into its own positioned frame. The host stays a view of the anchor's
1123
+ * `ViewContainerRef` (Angular removes a destroyed host from whatever parent it has); the frame
1124
+ * is what gets animated, parked and focused, so the page host stays free of outlet state.
1125
+ */
1126
+ private wrap;
1127
+ /**
1128
+ * The outlet's own component-input binder: the router's (`RoutedComponentInputBinder` behind
1129
+ * the private `INPUT_BINDER` token) only serves `RouterOutlet`. Mirrors its Angular 22.1
1130
+ * behaviour with the default options, whether or not `withComponentInputBinding()` is present:
1131
+ * query params, then path params, then route data (including resolved data), each input set
1132
+ * (or cleared with `undefined`) on every emission. Not supported: the feature's
1133
+ * `queryParams: false` and `unmatchedInputBehavior` options and the experimental route
1134
+ * `resources`.
1135
+ */
1136
+ private bindInputs;
1137
+ private destroyEntry;
1138
+ private emitTransitionStart;
1139
+ private emitTransitionEnd;
1140
+ private emitDepth;
1141
+ /** Makes `entry` the active page; the page it replaces is parked for its nested outlets. */
1142
+ private setActive;
1143
+ /**
1144
+ * The host page is back (the outer outlet popped to it): shows the page that was active when
1145
+ * it was parked, as it was, when the router activates the same route key on the same stack.
1146
+ * Returns false for any other route, which then goes through the normal classification.
1147
+ */
1148
+ private resume;
1149
+ /**
1150
+ * The host page entered or left (the parent outlet parked or restored it): the page this outlet
1151
+ * shows follows it. Fires only on a real state change, so a page that just ran its own
1152
+ * transition (or its first activation) does not get an event twice.
1153
+ */
1154
+ private forwardHostEvent;
1155
+ private requireActive;
1156
+ /**
1157
+ * Layers the two pages, fires the lifecycle, animates (unless `kind` is null, `animated` is
1158
+ * off or a swipe already animated the pop), then destroys `removed`, parks `leaving` when it
1159
+ * stays in the stack and moves focus.
1160
+ */
1161
+ private runTransition;
1162
+ private createAnimation;
1163
+ /** A new activation during a running transition finishes the old one at once. */
1164
+ private interruptTransition;
1165
+ private clearBackFallback;
1166
+ private releaseHeld;
1167
+ private moveFocus;
1168
+ /** During a transition: both pages visible, only the entering one interactive. */
1169
+ private layer;
1170
+ /** Final state: only the top page visible and interactive; the rest parked. */
1171
+ private settleLayers;
1172
+ /**
1173
+ * Non-passive `touchmove` guard, attached only while a swipe is armed (which happens only inside
1174
+ * the 50 px edge zone). Once the swipe is claimed, native scrolling must not start: a horizontal
1175
+ * scroller under the finger (any `overflow-x-auto` row, which pans on its own) would take over
1176
+ * the touch and cancel the pointer stream. Inside the edge zone the gesture wins; outside it the
1177
+ * guard is never attached, so such scrollers keep their own pan.
1178
+ */
1179
+ private readonly touchMoveGuard;
1180
+ private readonly onPointerDown;
1181
+ private readonly onPointerMove;
1182
+ private readonly onPointerUp;
1183
+ private readonly onPointerCancel;
1184
+ /** Settles a swipe that did not pop: the top page stays, the page under it is parked again. */
1185
+ private cancelSwipe;
1186
+ /**
1187
+ * The history step that pops the top page in one navigation: back to the entry before the page
1188
+ * was pushed, skipping the entries it added itself (query-only or nested child navigations).
1189
+ * Null when unknown, and `Location.back()` is used instead.
1190
+ */
1191
+ private popDelta;
1192
+ private endGesture;
1193
+ /** The router refused a swiped pop (a guard): slide the top page back in over 300 ms. */
1194
+ private restoreAfterRefusedPop;
1195
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfStackOutletComponent, never>;
1196
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfStackOutletComponent, "bf-stack-outlet", never, {
1197
+ "name": {
1198
+ "alias": "name";
1199
+ "required": false;
1200
+ "isSignal": true;
1201
+ };
1202
+ "swipeGesture": {
1203
+ "alias": "swipeGesture";
1204
+ "required": false;
1205
+ "isSignal": true;
1206
+ };
1207
+ "animated": {
1208
+ "alias": "animated";
1209
+ "required": false;
1210
+ "isSignal": true;
1211
+ };
1212
+ }, {
1213
+ "stackChanged": "stackChanged";
1214
+ "transitionStarted": "transitionStarted";
1215
+ "transitionEnded": "transitionEnded";
1216
+ "stackChange": "stackChange";
1217
+ "transitionStart": "transitionStart";
1218
+ "transitionEnd": "transitionEnd";
1219
+ }, never, never, true, never>;
1220
+ }
1221
+ /**
1222
+ * The page frame of a mobile app: `bf-stack-outlet` positions one per stacked page and provides
1223
+ * its `BfViewLifecycle` through the element injector. Everything scrollable inside a page goes
1224
+ * into `bf-content`; `bf-page` is only the frame, the lifecycle signal and a per-page
1225
+ * `BfPageContext` (provided for its children, where `bf-content` registers its scroller). The
1226
+ * page an outlet shows makes its `bf-content` the document's `main` landmark. Used
1227
+ * standalone (outside an outlet, e.g. in a docs demo) it falls back to a local, inert lifecycle
1228
+ * instance instead of throwing, and exposes no `main` landmark.
1229
+ *
1230
+ * @example
1231
+ * <bf-page (bfViewDidEnter)="load()">
1232
+ * <p>Page content</p>
1233
+ * </bf-page>
1234
+ * @summary Frame for one stacked mobile screen that supplies lifecycle events and shared page state
1235
+ * @category Navigation
1236
+ * @since 0.2.0
1237
+ * @slot default The page: a `bf-header` and a `bf-content`.
1238
+ */
1239
+ export declare class BfPageComponent {
1240
+ private readonly lifecycle;
1241
+ /** The page's current lifecycle state, mirrored from `BfViewLifecycle`. */
1242
+ readonly viewState: import("@angular/core").Signal<import("@bitforgehq/ui/mobile").BfViewState>;
1243
+ /** Emitted when the page starts entering the top of the stack. */
1244
+ readonly bfViewWillEnter: import("@angular/core").OutputEmitterRef<void>;
1245
+ /** Emitted once the page is active at the top of the stack. */
1246
+ readonly bfViewDidEnter: import("@angular/core").OutputEmitterRef<void>;
1247
+ /** Emitted when the page starts leaving the top of the stack. */
1248
+ readonly bfViewWillLeave: import("@angular/core").OutputEmitterRef<void>;
1249
+ /** Emitted once the page has left the top of the stack. */
1250
+ readonly bfViewDidLeave: import("@angular/core").OutputEmitterRef<void>;
1251
+ constructor();
1252
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfPageComponent, never>;
1253
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfPageComponent, "bf-page", never, {}, {
1254
+ "bfViewWillEnter": "bfViewWillEnter";
1255
+ "bfViewDidEnter": "bfViewDidEnter";
1256
+ "bfViewWillLeave": "bfViewWillLeave";
1257
+ "bfViewDidLeave": "bfViewDidLeave";
1258
+ }, never, ["*"], true, never>;
1259
+ }
1260
+ /**
1261
+ * Per-page state shared between the parts of one `bf-page`. `bf-page` provides a fresh instance
1262
+ * for each page through its element injector; `bf-content` registers its scroll container here
1263
+ * on init (and clears it on destroy), so siblings such as `bf-header` can follow the page's
1264
+ * scroll without querying the DOM. A plain class, like `BfViewLifecycle`: it is only ever
1265
+ * provided per page, never from the root injector.
1266
+ *
1267
+ * @example
1268
+ * const scroller = inject(BfPageContext, { optional: true })?.scroller;
1269
+ * @since 0.2.0
1270
+ * @summary Per-page state that the header and content of one page share
1271
+ */
1272
+ export declare class BfPageContext {
1273
+ /** The page's scroll container (`bf-content`'s scroller), or `null` before one registers. */
1274
+ readonly scroller: import("@angular/core").WritableSignal<HTMLElement | null>;
1275
+ /**
1276
+ * Height (px) of a `translucent` `bf-header` drawn over the content, which `bf-content` pads its
1277
+ * scroller by (`--bf-header-height`); 0 while the header sits in the page's flow (or none).
1278
+ */
1279
+ readonly headerHeight: import("@angular/core").WritableSignal<number>;
1280
+ /**
1281
+ * Whether the page reaches the top of the screen, so its `bf-header` toolbar (and a `fullscreen`
1282
+ * `bf-content`) pads by the top safe area. True for a page; `bf-modal` in the `sheet`
1283
+ * presentation sets it to false, because its card already sits below the status bar.
1284
+ */
1285
+ readonly safeAreaTop: import("@angular/core").WritableSignal<boolean>;
1286
+ /**
1287
+ * Whether the page's `bf-content` scroller is the document's `main` landmark (`role="main"`).
1288
+ * True for the page a `bf-stack-outlet` shows; `bf-modal` sets it to false (content in a dialog
1289
+ * is not `main`), and so does a `bf-page` outside an outlet (a docs illustration) or nested in
1290
+ * another page, so the document keeps exactly one `main`: parked pages are `inert` and
1291
+ * `aria-hidden`, so only the shown page's landmark is exposed.
1292
+ */
1293
+ readonly mainLandmark: import("@angular/core").WritableSignal<boolean>;
1294
+ }
1295
+ /**
1296
+ * Provided by `bf-stack-outlet` for each stacked page: the page's outermost `bf-page` registers
1297
+ * its `BfPageContext` here (a nested `bf-page` finds the slot taken and leaves it), so the outlet
1298
+ * can reach the page's scroller, e.g. to scroll it to the top when its tab is re-selected.
1299
+ * Internal to the mobile entry.
1300
+ */
1301
+ declare class BfPageContextSlot {
1302
+ context: BfPageContext | null;
1303
+ }
1304
+ /**
1305
+ * Back button for a `bf-header` start slot (or anywhere else in a page): pops the shown stack,
1306
+ * or replaces it with `defaultHref` when there's nothing to pop back to, e.g. a deep link that
1307
+ * landed on this page directly. Hidden when neither applies. Its anatomy follows the shell mode:
1308
+ * iOS, a chevron with the `label` as text; Material, a bare arrow icon button named by `label`.
1309
+ *
1310
+ * @example
1311
+ * <bf-back-button defaultHref="/tabs/today" />
1312
+ * @summary Header back button that pops the page stack or falls back to a default route
1313
+ * @category Navigation
1314
+ * @since 0.2.0
1315
+ */
1316
+ export declare class BfBackButtonComponent {
1317
+ private readonly nav;
1318
+ private readonly labels;
1319
+ /** Destination `nav.root()` navigates to when there's no page to pop back to. */
1320
+ readonly defaultHref: import("@angular/core").InputSignal<string>;
1321
+ /**
1322
+ * The previous page's name: the text beside the chevron in iOS mode, the arrow button's
1323
+ * accessible name in Material mode. Empty falls back to `provideBfLabels()`'s `back` ("Back").
1324
+ */
1325
+ readonly label: import("@angular/core").InputSignal<string>;
1326
+ /** The shell mode (`provideBfShell({ mode })`, or the platform's for `'auto'`). */
1327
+ protected readonly mode: BfShellMode;
1328
+ protected readonly iosClasses: string;
1329
+ protected readonly chevronLeft: import("lucide").IconNode;
1330
+ protected readonly arrowLeft: import("lucide").IconNode;
1331
+ /** The rendered label: `label`, else the `back` label. */
1332
+ readonly name: import("@angular/core").Signal<string>;
1333
+ /** Shown when the stack has a page to go back to, or a `defaultHref` is set. */
1334
+ readonly visible: import("@angular/core").Signal<boolean>;
1335
+ /** Goes back one page, or to `defaultHref` when the stack has none to go back to. */
1336
+ go(): void;
1337
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfBackButtonComponent, never>;
1338
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfBackButtonComponent, "bf-back-button", never, {
1339
+ "defaultHref": {
1340
+ "alias": "defaultHref";
1341
+ "required": false;
1342
+ "isSignal": true;
1343
+ };
1344
+ "label": {
1345
+ "alias": "label";
1346
+ "required": false;
1347
+ "isSignal": true;
1348
+ };
1349
+ }, {}, never, never, true, never>;
1350
+ }
1351
+ /**
1352
+ * Sets `touch-action: pan-x pan-y` (and a `data-bf-horizontal-scroll` marker) on a horizontally
1353
+ * scrolling element inside a `bf-stack-outlet` page. Not needed: `touch-action` is not inherited,
1354
+ * and a touch's effective value is the intersection of the values from the touched element up to
1355
+ * its nearest scroll container only, so an `overflow-x-auto` row (a chips row, a carousel) pans
1356
+ * on its own under the outlet's `touch-action: pan-y`, on iOS and on Android. Only the 50 px
1357
+ * left-edge zone belongs to the swipe-back, with or without the directive.
1358
+ *
1359
+ * @example
1360
+ * <div bfHorizontalScroll class="flex gap-2 overflow-x-auto">
1361
+ * <bf-chip>All</bf-chip>
1362
+ * <bf-chip>Open</bf-chip>
1363
+ * </div>
1364
+ * @deprecated 0.3.0 use a plain overflow-x-auto scroller, which pans on its own; removed in 0.4.0
1365
+ * @category Navigation
1366
+ * @since 0.2.0
1367
+ * @summary Deprecated touch-action opt-in for horizontal scrollers in stack pages, not needed
1368
+ */
1369
+ export declare class BfHorizontalScrollDirective {
1370
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfHorizontalScrollDirective, never>;
1371
+ static ɵdir: i0.ɵɵDirectiveDeclaration<BfHorizontalScrollDirective, "[bfHorizontalScroll]", never, {}, {}, never, never, true, never>;
1372
+ }
1373
+ /**
1374
+ * The payload of `bf-content`'s `scrolled` output: the scroller's `scrollTop` after the scroll.
1375
+ *
1376
+ * @summary What a content scroll event carries: the scroller's current top offset
1377
+ * @since 0.3.0
1378
+ */
1379
+ interface BfContentScrollEvent {
1380
+ /** The scroller's `scrollTop`, in px. */
1381
+ scrollTop: number;
1382
+ }
1383
+ /**
1384
+ * The page's single scroll container: fills the rest of `bf-page` under the header, keeps the
1385
+ * focused text control clear of the soft keyboard (`bfKeyboardAssist`), pads for the horizontal
1386
+ * safe areas, for the floating tab bar (`--bf-tab-bar-inset`), for a `translucent` header drawn
1387
+ * over it (`--bf-header-height`, from `BfPageContext`) and at the bottom for the height a solid
1388
+ * `bf-header` has collapsed by (`--bf-header-collapse`, written by the header, so the scroll range
1389
+ * stays the same while the large title collapses), and contains overscroll so the document
1390
+ * never scrolls. On iOS (`ios.scrollEnabled: false`) it is the only thing that scrolls. The
1391
+ * projected content sits in a block body inside the scroller: in iOS mode the body is 1 px taller
1392
+ * than the scroller, so WebKit rubber-bands even a short page; in Material mode the scroller gets
1393
+ * `bfOverscrollStretch`, the Android edge stretch the WebView does not draw itself, except in iOS
1394
+ * WebKit (Safari or a home-screen app, platform `web`), which rubber-bands natively. Both follow the
1395
+ * engine (`BfPlatformService.mode()`), not `provideBfShell({ mode })`. In the page a
1396
+ * `bf-stack-outlet` shows, the scroller is the document's `main` landmark (`role="main"`; not in a
1397
+ * `bf-modal`, see `BfPageContext.mainLandmark`). While it overflows and holds nothing focusable,
1398
+ * it is a tab stop (`tabindex="0"`), so a keyboard can scroll it in Safari too (axe
1399
+ * `scrollable-region-focusable`); otherwise Tab reaches its controls and the arrow keys scroll it.
1400
+ *
1401
+ * @example
1402
+ * <bf-page>
1403
+ * <bf-content>
1404
+ * <bf-list>…</bf-list>
1405
+ * </bf-content>
1406
+ * </bf-page>
1407
+ * @summary Page's single scroll container that keeps focused fields clear of the soft keyboard
1408
+ * @category Navigation
1409
+ * @since 0.2.0
1410
+ * @slot default The page content, in the scroll container.
1411
+ */
1412
+ export declare class BfContentComponent {
1413
+ /** Extends the content under the status bar: adds the top safe-area padding (no header above). */
1414
+ readonly fullscreen: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1415
+ /** Keeps the focused text control clear of the soft keyboard; false for screens that handle it themselves. */
1416
+ readonly keyboardAssist: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1417
+ /** Emits `scrolled` on every scroll; off by default so plain pages add no listener. */
1418
+ readonly scrollEvents: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1419
+ /** The scroller's `scrollTop` on each scroll, only while `scrollEvents` is true. */
1420
+ readonly scrolled: import("@angular/core").OutputEmitterRef<BfContentScrollEvent>;
1421
+ private readonly scroller;
1422
+ private readonly pageContext;
1423
+ private readonly platform;
1424
+ private readonly iosWebKit;
1425
+ protected readonly ios: import("@angular/core").Signal<boolean>;
1426
+ /** The edge stretch only where nothing rubber-bands natively: never in iOS mode or iOS WebKit. */
1427
+ protected readonly stretch: import("@angular/core").Signal<boolean>;
1428
+ protected readonly bodyClasses: import("@angular/core").Signal<"" | "min-h-[calc(100%+1px)]">;
1429
+ /** The shown page's content is the document's `main` landmark; a modal's is not. */
1430
+ protected readonly role: import("@angular/core").Signal<"main" | null>;
1431
+ /** True while the scroller overflows and holds nothing a keyboard can Tab to. */
1432
+ protected readonly tabStop: import("@angular/core").WritableSignal<boolean>;
1433
+ /** A page-sheet modal already sits below the status bar (`BfPageContext.safeAreaTop`). */
1434
+ private readonly safeAreaTop;
1435
+ protected readonly scrollerClasses: import("@angular/core").Signal<string>;
1436
+ constructor();
1437
+ /**
1438
+ * Keeps `tabStop` current: re-checked once per frame after the scroller or its content resizes
1439
+ * or the content changes (rows added, a control enabled, shown, hidden or made inert). Hidden,
1440
+ * inert and unrendered controls do not count.
1441
+ */
1442
+ private watchKeyboardReach;
1443
+ /** The scroll container element, for code that needs to read or drive it directly. */
1444
+ get scrollElement(): HTMLElement;
1445
+ /**
1446
+ * Scrolls back to the top (e.g. on a second tap of the active tab).
1447
+ * @param behavior `smooth` (the default) or `instant`.
1448
+ */
1449
+ scrollToTop(behavior?: ScrollBehavior): void;
1450
+ /**
1451
+ * Scrolls to the given offset in px.
1452
+ * @param x The horizontal offset (px).
1453
+ * @param y The vertical offset (px).
1454
+ * @param behavior `smooth` (the default) or `instant`.
1455
+ */
1456
+ scrollToPoint(x: number, y: number, behavior?: ScrollBehavior): void;
1457
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfContentComponent, never>;
1458
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfContentComponent, "bf-content", never, {
1459
+ "fullscreen": {
1460
+ "alias": "fullscreen";
1461
+ "required": false;
1462
+ "isSignal": true;
1463
+ };
1464
+ "keyboardAssist": {
1465
+ "alias": "keyboardAssist";
1466
+ "required": false;
1467
+ "isSignal": true;
1468
+ };
1469
+ "scrollEvents": {
1470
+ "alias": "scrollEvents";
1471
+ "required": false;
1472
+ "isSignal": true;
1473
+ };
1474
+ }, {
1475
+ "scrolled": "scrolled";
1476
+ }, never, ["*"], true, never>;
1477
+ }
1478
+ /**
1479
+ * How `bfKeyboardAssist` scrolls the focused control into view: `smooth` or `instant`.
1480
+ *
1481
+ * @summary Whether the keyboard assist scrolls a focused field into view smoothly or at once
1482
+ * @since 0.3.0
1483
+ */
1484
+ type BfKeyboardAssistBehavior = 'smooth' | 'instant';
1485
+ /**
1486
+ * Keeps the focused text control of a scroll container clear of the soft keyboard. On keyboard
1487
+ * will-show it pads the scroller by the part below the keyboard's top edge
1488
+ * (`BfKeyboardService.keyboardTop()`: `padding-bottom`, plus `scroll-padding-bottom` with the
1489
+ * margin for engine scrolls), then scrolls the focused `input`, `textarea` or `[contenteditable]`
1490
+ * up until it sits `bfKeyboardAssistMargin` px above the keyboard (or down until it sits the margin
1491
+ * below the scroller's top edge; in a scroller too short for the control and both margins, the gap
1492
+ * above the control shrinks first, then the one above the keyboard, so a control shorter than the
1493
+ * scroller stays whole; a taller one keeps its bottom at the keyboard top). The covered part is
1494
+ * measured again at did-show and on every window or `visualViewport` resize, so a WebView that
1495
+ * resizes for the keyboard (Android) gets no padding and a padding never outlives the keyboard,
1496
+ * even on a detached page. A hidden host (a parked page, `visibility: hidden`) is never padded or
1497
+ * scrolled. The reveal waits for the engine's own focus scroll to settle (100 ms without a `scroll`
1498
+ * event, 120 ms if none arrives, at most 400 ms), then scrolls once; one correction follows at
1499
+ * did-show once the scroller is quiet (skipped while a reveal is pending). Focus moving to another
1500
+ * field while the keyboard is open re-arms the reveal, and both paddings go away on hide.
1501
+ * `refresh()` measures and corrects again for a container that moved on its own. `bf-content`
1502
+ * applies it to its own scroller; use it directly only on a custom scroll container.
1503
+ *
1504
+ * @example
1505
+ * <div class="h-full overflow-y-auto" bfKeyboardAssist [bfKeyboardAssistMargin]="32">
1506
+ * <bf-input label="Name" />
1507
+ * </div>
1508
+ * @category Navigation
1509
+ * @since 0.2.0
1510
+ * @summary Keeps the focused text field of a scroll container clear of the soft keyboard
1511
+ */
1512
+ export declare class BfKeyboardAssistDirective {
1513
+ /** Enables the assist; set it false for screens that manage the keyboard themselves (a chat composer). */
1514
+ readonly bfKeyboardAssist: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1515
+ /** Gap kept between the focused control and the top of the keyboard, in px. */
1516
+ readonly bfKeyboardAssistMargin: import("@angular/core").InputSignal<number>;
1517
+ /** Scroll behaviour of the reveal. */
1518
+ readonly bfKeyboardAssistBehavior: import("@angular/core").InputSignal<BfKeyboardAssistBehavior>;
1519
+ private readonly host;
1520
+ private readonly document;
1521
+ private readonly keyboard;
1522
+ private settleCallback;
1523
+ private quietTimer;
1524
+ private maxWaitTimer;
1525
+ private revealPending;
1526
+ private lastScrollAt;
1527
+ constructor();
1528
+ /**
1529
+ * The did-show correction's measurement: the scroll it needs now, or 0 when it is skipped (a
1530
+ * reveal is pending, the assist is off, the keyboard is no longer shown) or deferred until the
1531
+ * scroller is quiet.
1532
+ */
1533
+ private settledCorrection;
1534
+ /**
1535
+ * Measures the covered part again and, while the keyboard is up, corrects the reveal once
1536
+ * (instantly, after any scroll in progress). For a container that moves with the keyboard
1537
+ * outside the keyboard events — `bf-sheet` calls it once its lift above the keyboard has ended.
1538
+ */
1539
+ refresh(): void;
1540
+ /**
1541
+ * False for a host that is not rendered visibly. A parked page is `visibility: hidden`, which
1542
+ * `checkVisibility()` ignores unless asked with `visibilityProperty`.
1543
+ */
1544
+ private hostVisible;
1545
+ /** Part of the host below the keyboard's top edge, in px; 0 while hidden or not applicable. */
1546
+ private covered;
1547
+ /** Measures and applies the paddings at once, outside change detection (resize, `refresh()`). */
1548
+ private updatePadding;
1549
+ /** The keyboard height the paddings answer to and the part of the host it covers. */
1550
+ private measurePadding;
1551
+ private applyPadding;
1552
+ /**
1553
+ * Arms a single-shot reveal: it runs once the scroller has been quiet for `REVEAL_QUIET_MS`
1554
+ * after its last `scroll` event, `REVEAL_SETTLE_MS` after arming if none arrives, and at most
1555
+ * `REVEAL_MAX_WAIT_MS` after arming.
1556
+ */
1557
+ private scheduleReveal;
1558
+ /** Runs `callback` now if the scroller is quiet, else once it has been quiet for `REVEAL_QUIET_MS`. */
1559
+ private whenScrollSettled;
1560
+ private waitForQuiet;
1561
+ private restartQuietTimer;
1562
+ private finishSettle;
1563
+ /** Drops a pending reveal or correction and its timers. */
1564
+ private cancelReveal;
1565
+ /** Scrolls the focused text control so that its bottom plus the margin clears the keyboard top. */
1566
+ private reveal;
1567
+ /** How far the scroller must scroll for the focused text control to clear the keyboard; 0 when
1568
+ * nothing needs revealing. */
1569
+ private revealDelta;
1570
+ private scrollReveal;
1571
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfKeyboardAssistDirective, never>;
1572
+ static ɵdir: i0.ɵɵDirectiveDeclaration<BfKeyboardAssistDirective, "[bfKeyboardAssist]", never, {
1573
+ "bfKeyboardAssist": {
1574
+ "alias": "bfKeyboardAssist";
1575
+ "required": false;
1576
+ "isSignal": true;
1577
+ };
1578
+ "bfKeyboardAssistMargin": {
1579
+ "alias": "bfKeyboardAssistMargin";
1580
+ "required": false;
1581
+ "isSignal": true;
1582
+ };
1583
+ "bfKeyboardAssistBehavior": {
1584
+ "alias": "bfKeyboardAssistBehavior";
1585
+ "required": false;
1586
+ "isSignal": true;
1587
+ };
1588
+ }, {}, never, never, true, never>;
1589
+ }
1590
+ /**
1591
+ * Android-style edge stretch for a scroll container: a vertical touch drag past the top or bottom
1592
+ * edge scales the container's first element child (the content body) up along the y axis from
1593
+ * that edge — `scaleY(1 + 0.14 × (1 − e^(−pull / 240)))` — and springs it back on release (220 ms,
1594
+ * the settle curve; instant under `prefers-reduced-motion`). Touch only, with passive listeners:
1595
+ * it never prevents a touch, so scrolling is untouched. It follows the finger that started the
1596
+ * gesture and ignores any other. A horizontal-dominant gesture (decided after 8 px) is ignored,
1597
+ * and the top edge is left alone while an active `bf-refresher` (`[data-bf-refresher]`) inside
1598
+ * the container owns the top pull. `bf-content` applies it to its
1599
+ * scroller in Material mode, where the WebView draws no overscroll effect of its own.
1600
+ *
1601
+ * @example
1602
+ * <div class="h-full overflow-y-auto" bfOverscrollStretch>
1603
+ * <div>…</div>
1604
+ * </div>
1605
+ * @category Navigation
1606
+ * @since 0.2.0
1607
+ * @summary Android-style stretch of a scroll container dragged past its top or bottom edge
1608
+ */
1609
+ export declare class BfOverscrollStretchDirective {
1610
+ /** Enables the stretch; false leaves the container inert. */
1611
+ readonly bfOverscrollStretch: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1612
+ private readonly host;
1613
+ private readonly document;
1614
+ private gesture;
1615
+ private settle;
1616
+ constructor();
1617
+ private readonly onTouchStart;
1618
+ private readonly onTouchMove;
1619
+ private readonly onTouchEnd;
1620
+ private apply;
1621
+ private stopSettle;
1622
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfOverscrollStretchDirective, never>;
1623
+ static ɵdir: i0.ɵɵDirectiveDeclaration<BfOverscrollStretchDirective, "[bfOverscrollStretch]", never, {
1624
+ "bfOverscrollStretch": {
1625
+ "alias": "bfOverscrollStretch";
1626
+ "required": false;
1627
+ "isSignal": true;
1628
+ };
1629
+ }, {}, never, never, true, never>;
1630
+ }
1631
+ /**
1632
+ * The page header: a persistent bar (`start` | title | `end`) and, with `largeTitle` (the
1633
+ * default), the Meadow Sage large title below it that collapses into the bar's title as the
1634
+ * page's `bf-content` scrolls. The bar follows the shell mode (`provideBfShell({ mode })`, the
1635
+ * platform's for `'auto'`): iOS, at least 44 px with a semibold title centred on the bar whatever
1636
+ * the slots hold (symmetric insets of the wider slot's width plus 8 px, measured with a
1637
+ * `ResizeObserver`); Material, at least 64 px with a regular title leading after the `start` slot.
1638
+ * The bar grows with its content at large text sizes: the title wraps to at most two lines (the
1639
+ * bar is never shorter than the measured title, `--bf-header-title-height`), the `start` slot may
1640
+ * shrink (a back button drops its text before its chevron; in iOS mode capped by
1641
+ * `--bf-header-start-max` so the centred title keeps up to half the bar) and the `end` slot never
1642
+ * does. At
1643
+ * compact heights (`(max-height: 500px)`, phone landscape) it renders no large title: the title is
1644
+ * the bar's `h1`, the bar is 44 px in both modes and nothing collapses. Once content scrolls under
1645
+ * it (the large title fully collapsed; without one, `scrollTop > 0`, overscroll excluded) the
1646
+ * host gets `data-bf-scrolled`: iOS turns translucent with a blur and a 1 px hairline, Material
1647
+ * takes a tonal tint. Reads its sibling scroller through the page's `BfPageContext` (set by
1648
+ * `bf-content`) and, from a passive scroll listener, writes `--bf-header-progress` (0…1, over the
1649
+ * large title block's rendered height, bounded to 44–200 px (a taller title collapses faster), of the scroll position clamped to the
1650
+ * scrollable range, so overscroll never moves it, and 0 on a page that cannot scroll that far) on
1651
+ * its host and the large title block's height (its natural height, measured once and on resize,
1652
+ * times `1 − progress`), so at progress 1 the header is exactly the toolbar; scrolling schedules
1653
+ * no Angular change detection. Solid, it also writes the collapsed height as
1654
+ * `--bf-header-collapse` on the scroller, which `bf-content` adds to its bottom padding: the
1655
+ * scroller grows by what the header gives up, so its scroll range stays the same through the
1656
+ * collapse and the short-page rule reads one stable value. When a scroll ends part-way
1657
+ * (`scrollend`, or 120 ms without a `scroll` event) with nothing pressed on the scroller, it snaps
1658
+ * the scroller to fully expanded or fully collapsed, whichever is nearer, like UIKit. Solid
1659
+ * (default), it sits in the page's flow above the content; `translucent`, it is drawn over the
1660
+ * content and `bf-content` pads its scroller by the header's height (`--bf-header-height`).
1661
+ *
1662
+ * @example
1663
+ * <bf-header title="Today" subtitle="Wed, 23 Sep">
1664
+ * <bf-icon-button bfSlot="end" variant="text" label="Profile">
1665
+ * <bf-icon [icon]="userIcon" />
1666
+ * </bf-icon-button>
1667
+ * </bf-header>
1668
+ * @summary Page header toolbar with a large title that collapses into the toolbar on scroll
1669
+ * @category Navigation
1670
+ * @since 0.2.0
1671
+ * @slot start Toolbar buttons at the start, such as `bf-back-button`.
1672
+ * @slot default The toolbar title, when the `title` input is empty.
1673
+ * @slot end Toolbar buttons at the end.
1674
+ */
1675
+ export declare class BfHeaderComponent {
1676
+ /** The page title, rendered in the toolbar and, with `largeTitle`, in the large title block. */
1677
+ readonly title: import("@angular/core").InputSignal<string>;
1678
+ /** Eyebrow line above the large title (e.g. a date); rendered only with `largeTitle`. */
1679
+ readonly subtitle: import("@angular/core").InputSignal<string>;
1680
+ /**
1681
+ * Renders the collapsing large title block below the toolbar; never at compact heights
1682
+ * (`(max-height: 500px)`), where the title is the bar's `h1`.
1683
+ */
1684
+ readonly largeTitle: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1685
+ /**
1686
+ * Draws the header over the content (`absolute`) instead of in the page's flow, so content
1687
+ * scrolls under its scroll-under surface; `bf-content` pads its scroller by the header's height.
1688
+ */
1689
+ readonly translucent: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1690
+ private readonly host;
1691
+ private readonly pageContext;
1692
+ /** The status-bar band, unless the page sits below the status bar already (a page-sheet modal). */
1693
+ protected readonly toolbarClasses: import("@angular/core").Signal<"" | "pt-safe-top">;
1694
+ private readonly keyboard;
1695
+ private readonly document;
1696
+ private readonly toolbar;
1697
+ private readonly startSlot;
1698
+ private readonly endSlot;
1699
+ private readonly largeClip;
1700
+ private readonly largeBlock;
1701
+ private readonly titleText;
1702
+ private readonly titleSizer;
1703
+ /**
1704
+ * True at compact heights (`(max-height: 500px)`: phone landscape, split screen), read with
1705
+ * `matchMedia` and followed live: no large title, the title in the bar, a 44 px bar.
1706
+ */
1707
+ protected readonly compact: import("@angular/core").WritableSignal<boolean>;
1708
+ /** Whether the large title block renders: `largeTitle`, except at compact heights. */
1709
+ protected readonly showLarge: import("@angular/core").Signal<boolean>;
1710
+ /** The shell mode (`provideBfShell({ mode })`, or the platform's for `'auto'`), fixed per header. */
1711
+ protected readonly mode: BfShellMode;
1712
+ protected readonly barClasses: import("@angular/core").Signal<string>;
1713
+ protected readonly titleBoxClasses: string;
1714
+ protected readonly titleTextClasses: string;
1715
+ protected readonly startSlotClasses: string;
1716
+ protected readonly largeBlockClasses = "bf-large px-gutter pb-2 opacity-[calc(1_-_var(--bf-header-progress,0))] motion-safe:-translate-y-[calc(var(--bf-header-progress,0)_*_8px)]";
1717
+ protected readonly largeTitleClasses = "text-display text-[length:min(var(--text-display),80px)] leading-[min(var(--text-display--line-height),88px)] wrap-anywhere";
1718
+ protected readonly hostClasses: import("@angular/core").Signal<string>;
1719
+ /** Last written progress (0…1). */
1720
+ private progress;
1721
+ /** Natural height of the large title block, 0 until measured (or without one). */
1722
+ private largeHeight;
1723
+ /** The scroller `--bf-header-collapse` was last written on, so it can be cleared again. */
1724
+ private compensated;
1725
+ constructor();
1726
+ /**
1727
+ * The iOS `start` slot's cap (px), or `null` when the title fits on one line beside the slots
1728
+ * at their full width. A back button's text (`[data-bf-back-text]`) is the only part that gives
1729
+ * way: the cap is at least the slot's width with every back text gone (down to the button's own
1730
+ * minimum width) and at least one 44 px hit area.
1731
+ * @param width The bar's width.
1732
+ * @param titleWidth The title's one-line width.
1733
+ * @param start The start slot.
1734
+ * @param end The end slot.
1735
+ */
1736
+ private startCap;
1737
+ /**
1738
+ * The scroll distance (px) over which the large title collapses: its block's rendered height
1739
+ * (the eyebrow, the wrapped title and its bottom padding), so the collapse ends exactly when the
1740
+ * title has scrolled away, bounded to 44–200 px (a taller title collapses its whole height over
1741
+ * 200 px, so faster than it scrolls); 56 px until it is measured.
1742
+ */
1743
+ private collapseRange;
1744
+ /**
1745
+ * Collapses the large title block's height with the progress, so the header ends at exactly the
1746
+ * toolbar (left at its natural (auto) height until measured), and writes the height it gave up
1747
+ * as `--bf-header-collapse` on the page's scroller (`0px` at rest). Solid, the header is in the
1748
+ * page's column, so the scroller grows by that much and `bf-content` pads its bottom by the same
1749
+ * amount, keeping the scroll range constant; translucent, the header is drawn over the scroller,
1750
+ * which never resizes, so the compensation stays `0px`.
1751
+ */
1752
+ private applyCollapse;
1753
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfHeaderComponent, never>;
1754
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfHeaderComponent, "bf-header", never, {
1755
+ "title": {
1756
+ "alias": "title";
1757
+ "required": false;
1758
+ "isSignal": true;
1759
+ };
1760
+ "subtitle": {
1761
+ "alias": "subtitle";
1762
+ "required": false;
1763
+ "isSignal": true;
1764
+ };
1765
+ "largeTitle": {
1766
+ "alias": "largeTitle";
1767
+ "required": false;
1768
+ "isSignal": true;
1769
+ };
1770
+ "translucent": {
1771
+ "alias": "translucent";
1772
+ "required": false;
1773
+ "isSignal": true;
1774
+ };
1775
+ }, {}, never, ["[bfSlot=start]", "*", "[bfSlot=end]", "*"], true, never>;
1776
+ }
1777
+ /**
1778
+ * The payload of `bf-refresher`'s `refreshRequested` output: call `complete()` once the reload is
1779
+ * done to animate the disc away.
1780
+ *
1781
+ * @summary What a pull-to-refresh request carries: the callback that ends the refresh
1782
+ * @since 0.3.0
1783
+ */
1784
+ interface BfRefresherRefreshEvent {
1785
+ /** Ends the refresh: animates the disc away and resets the refresher. */
1786
+ complete: () => void;
1787
+ }
1788
+ /**
1789
+ * Pull-to-refresh, placed as the first child of `bf-content`. It tracks Pointer Events on the
1790
+ * page's scroller (read from `BfPageContext`, or its nearest scrolling ancestor when used without one)
1791
+ * only while the scroller is at `scrollTop === 0`: the disc resists the pull (half the pointer's
1792
+ * travel, capped) from a resting position above the clipped content to a 64 px threshold, ticks
1793
+ * `BfHapticsService.impact('light')` once on crossing it, and on release past the threshold
1794
+ * parks at the top with a spinner and emits `refreshRequested` — call `complete()` on the event to animate
1795
+ * the disc away and reset. A press by itself changes nothing: only once a pointermove clears an
1796
+ * 8 px downward slop (out-vertical'ing any horizontal travel) does it claim the gesture and
1797
+ * capture the pointer on the scroller, so a plain click on the content underneath (a row, a
1798
+ * button) still reaches it. For touch, a non-passive `touchmove` guard (attached only while a
1799
+ * press is tracked) keeps the browser from taking a downward drag at the top as a pan, which
1800
+ * would cancel the pointer stream; upward drags still scroll the list. The disc itself is
1801
+ * `aria-hidden`; a permanent, visually hidden `role="status"` region announces
1802
+ * `provideBfLabels()`'s `refreshing` ("Refreshing"). `prefers-reduced-motion` still follows the
1803
+ * pointer 1:1 during the pull (direct manipulation is not motion); only the settle, park and `complete()` animations
1804
+ * become instant.
1805
+ *
1806
+ * That pull is the Material (and mouse/pen) mode. A touch in iOS mode (`BfPlatformService.mode()`)
1807
+ * is the bounce mode instead: the refresher claims nothing (no capture, no `preventDefault`, no
1808
+ * guard), the scroller rubber-bands natively, and while the finger is down a negative `scrollTop`
1809
+ * shows the disc inside the gap the bounce opens, at its resting −48 px, with opacity and scale
1810
+ * (0.6 → 1) following `−scrollTop / 64` once it passes 8 px; one light haptic at 64 px. Lifting the
1811
+ * finger at 64 px or more parks the disc and emits `refreshRequested`, like `UIRefreshControl`; a bounce
1812
+ * with no finger down (a fling's overshoot) never shows it. The host carries `data-bf-refresher`
1813
+ * while enabled, so `bfOverscrollStretch` leaves the top edge to it.
1814
+ *
1815
+ * @example
1816
+ * <bf-content>
1817
+ * <bf-refresher (refreshRequested)="reload($event.complete)" />
1818
+ * <bf-list>…</bf-list>
1819
+ * </bf-content>
1820
+ * @summary Pull-to-refresh indicator with haptic feedback, native iOS bounce and an Android-style pull
1821
+ * @category Navigation
1822
+ * @since 0.2.0
1823
+ */
1824
+ export declare class BfRefresherComponent implements AfterViewInit {
1825
+ /** Disables pull tracking; the disc never moves and `refreshRequested` never emits. */
1826
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1827
+ /** Emitted when a pull past the threshold is released; call `complete()` to end it. */
1828
+ readonly refreshRequested: import("@angular/core").OutputEmitterRef<BfRefresherRefreshEvent>;
1829
+ /**
1830
+ * Emitted with the same event as `refreshRequested`, together with it.
1831
+ * @deprecated 0.3.0 use refreshRequested; removed in 0.4.0
1832
+ */
1833
+ readonly refresh: import("@angular/core").OutputEmitterRef<BfRefresherRefreshEvent>;
1834
+ private readonly host;
1835
+ private readonly disc;
1836
+ private readonly pageContext;
1837
+ private readonly haptics;
1838
+ protected readonly labels: import("@bitforgehq/ui").BfLabels;
1839
+ private readonly document;
1840
+ private readonly platform;
1841
+ private readonly ios;
1842
+ private readonly refreshingState;
1843
+ /** True from the moment a completed pull is released until `complete()` is called. */
1844
+ readonly refreshing: import("@angular/core").Signal<boolean>;
1845
+ private scroller;
1846
+ private gesture;
1847
+ private settleAnimation;
1848
+ private currentOffset;
1849
+ /** A finger is on the scroller (tracked in iOS mode only). */
1850
+ private touchActive;
1851
+ private bounce;
1852
+ constructor();
1853
+ /** Paints the disc's resting, hidden transform once the view exists (no template `style`). */
1854
+ ngAfterViewInit(): void;
1855
+ /** Emits one refresh event on `refreshRequested` and the deprecated `refresh`. */
1856
+ private requestRefresh;
1857
+ /** Ends a refresh: animates the disc away (skipped under reduced motion) and resets state. */
1858
+ complete(): void;
1859
+ private readonly onPointerDown;
1860
+ private readonly onTouchStart;
1861
+ /**
1862
+ * While a finger is down, a negative `scrollTop` is WebKit's rubber band at the top: the disc,
1863
+ * which sits in the content above its top edge, shows in the gap the bounce opens. Direct
1864
+ * manipulation (styles set straight from the scroll position, no animation).
1865
+ */
1866
+ private readonly onBounceScroll;
1867
+ private readonly onTouchEnd;
1868
+ private endBounce;
1869
+ private hideBounceDisc;
1870
+ /**
1871
+ * Non-passive `touchmove` guard, attached only while a press is tracked (the pattern of the
1872
+ * stack outlet's swipe guard). The scroller is `touch-pan-y`, so without it the browser takes a
1873
+ * downward drag as a pan and ends the pointer stream with `pointercancel`. It prevents a
1874
+ * cancelable move once the pull is claimed, or — before the claim — a downward-dominant move
1875
+ * while the scroller is at the top, where a pan has nothing to scroll anyway. Upward and
1876
+ * horizontal drags are left alone, so the list (and any horizontal scroller) keeps its pan.
1877
+ */
1878
+ private readonly touchMoveGuard;
1879
+ /**
1880
+ * A touch pointer is implicitly captured by the element under the finger; claiming it for the
1881
+ * scroller makes that child fire its own `lostpointercapture`, which bubbles here. Only the
1882
+ * scroller losing the capture it took ends the pull.
1883
+ */
1884
+ private readonly onLostPointerCapture;
1885
+ private readonly onPointerMove;
1886
+ private readonly onPointerUp;
1887
+ private readonly onPointerCancel;
1888
+ private endGesture;
1889
+ private removeDragListeners;
1890
+ private setOffset;
1891
+ private settleTo;
1892
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfRefresherComponent, never>;
1893
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfRefresherComponent, "bf-refresher", never, {
1894
+ "disabled": {
1895
+ "alias": "disabled";
1896
+ "required": false;
1897
+ "isSignal": true;
1898
+ };
1899
+ }, {
1900
+ "refreshRequested": "refreshRequested";
1901
+ "refresh": "refresh";
1902
+ }, never, never, true, never>;
1903
+ }
1904
+ /**
1905
+ * What `bf-tabs` tells the `bf-stack-outlet` inside it: which tab a URL belongs to. The outlet
1906
+ * keeps one stack per tab key and switches stacks when a navigation lands on another key.
1907
+ *
1908
+ * @since 0.2.0
1909
+ * @summary What the tabs page tells its stack outlet: which tab a URL belongs to
1910
+ */
1911
+ interface BfTabContext {
1912
+ /** The active tab's key (the URL segment after the tabs route), or null outside the tabs. */
1913
+ readonly tabKey: Signal<string | null>;
1914
+ /**
1915
+ * The tab key of `url` (query and fragment ignored), or null when it is not under the tabs route.
1916
+ * @param url The URL to read.
1917
+ */
1918
+ keyOf(url: string): string | null;
1919
+ }
1920
+ /**
1921
+ * Provided by `bf-tabs`; injected optionally by `bf-stack-outlet`.
1922
+ *
1923
+ * @summary Injection token through which the tabs page tells its outlet about the tabs
1924
+ * @since 0.2.0
1925
+ */
1926
+ export declare const BF_TAB_CONTEXT: InjectionToken<BfTabContext>;
1927
+ /**
1928
+ * The tabs page of a mobile app: one navigation stack per tab. It wraps a `bf-stack-outlet`, which
1929
+ * keeps a separate stack for every tab (keyed by the URL segment after `tabsPath`), and a
1930
+ * `bf-tab-bar`, which it drives through `BF_TAB_BAR_CONTROLLER`: the bar shows the tab of the
1931
+ * in-flight navigation's target, else of the current URL, and hides while the keyboard is open,
1932
+ * without anything writing into it. Selecting another tab brings
1933
+ * that tab back as it was left; re-selecting the active tab pops its stack to the root, or scrolls
1934
+ * its content to the top when it is already there. The bar hides while the soft keyboard is open
1935
+ * or about to open (a focused text control), and `--bf-tab-bar-inset` on the host tells
1936
+ * `bf-content` how much to pad its bottom (the bar's measured height, a `ResizeObserver` on its
1937
+ * `nav`, plus its bottom offset and 8 px; 64 px for the height until it is measured); the same value is mirrored on `<html>` as
1938
+ * `--bf-tab-bar-inset-global` for overlays (the toast), which render outside the host. It is removed when the tabs are destroyed.
1939
+ * It also provides `BF_TAB_LINKS`, so the projected bar is a `nav` of links to each tab's root URL
1940
+ * (`aria-current` on the active one: `page` at the tab's root, `true` on a child page of it)
1941
+ * instead of a `tablist`.
1942
+ *
1943
+ * @example
1944
+ * <bf-tabs tabsPath="tabs">
1945
+ * <bf-stack-outlet />
1946
+ * <bf-tab-bar>
1947
+ * <bf-tab id="today" label="Today"><bf-icon [icon]="Sun" /></bf-tab>
1948
+ * <bf-tab id="me" label="Me"><bf-icon [icon]="User" /></bf-tab>
1949
+ * </bf-tab-bar>
1950
+ * </bf-tabs>
1951
+ * @summary Tabs page with one navigation stack per tab, wiring the tab bar to the router
1952
+ * @category Navigation
1953
+ * @since 0.2.0
1954
+ * @slot default The tabs page body: a `bf-stack-outlet` and a `bf-tab-bar`.
1955
+ */
1956
+ export declare class BfTabsComponent implements BfTabContext, BfTabBarController {
1957
+ /** Route path of the tabs page (e.g. `'tabs'`); the URL segment after it is the tab key. */
1958
+ readonly tabsPath: import("@angular/core").InputSignal<string>;
1959
+ private readonly router;
1960
+ private readonly nav;
1961
+ private readonly haptics;
1962
+ private readonly keyboard;
1963
+ private readonly platform;
1964
+ private readonly config;
1965
+ private readonly host;
1966
+ private readonly document;
1967
+ private readonly overlays;
1968
+ private readonly locationStrategy;
1969
+ private readonly bar;
1970
+ private readonly barHost;
1971
+ /** The bar's measured height (px), `null` until its `nav` is first measured. */
1972
+ private readonly barHeight;
1973
+ private readonly outlet;
1974
+ /** The settled URL: the last successful navigation's (after redirects), else the router's. */
1975
+ private readonly url;
1976
+ /** The active tab's key, from the router URL; null while the URL is not under `tabsPath`. */
1977
+ readonly tabKey: Signal<string | null>;
1978
+ /**
1979
+ * The tab the bar shows: the in-flight navigation's target (after redirects once they are
1980
+ * applied), else the settled URL's. A refused or cancelled navigation ends, so the bar drops
1981
+ * back to the settled tab by itself. While neither is under `tabsPath` (a page pushed above the
1982
+ * tabs page) it keeps the last tab it showed.
1983
+ */
1984
+ private readonly currentTab;
1985
+ /** The tab the bar shows (read-only): the in-flight navigation's target, else the current URL's;
1986
+ * null when unknown. */
1987
+ readonly current: Signal<string | null>;
1988
+ /** Hide the bar while the keyboard is open or about to open (a focused text control: on Android
1989
+ * the WebView shrinks before will-show and would lift the fixed bar above the keyboard). */
1990
+ readonly hidden: Signal<boolean>;
1991
+ /** The bar hides animated on iOS, instantly on Android and the web. */
1992
+ readonly hideTransition: Signal<boolean>;
1993
+ constructor();
1994
+ /**
1995
+ * The tab key of `url`: the primary segment after `tabsPath`. Query, fragment, matrix params and
1996
+ * auxiliary routes (`(popup:…)`) are ignored.
1997
+ * @param url The URL to read.
1998
+ */
1999
+ keyOf(url: string): string | null;
2000
+ /** `keyOf` for a parsed URL. */
2001
+ private keyOfTree;
2002
+ /**
2003
+ * The URL of tab `id`'s root page (`/tabs/<id>`, with the app's base href), the `href` of its
2004
+ * link in the bar: a new browser tab opens the tab's root. A plain click still restores the page
2005
+ * the tab was left on.
2006
+ * @param id The `id` of the tab.
2007
+ */
2008
+ href(id: string): string;
2009
+ /**
2010
+ * Whether the current URL is tab `id`'s root page (`…/<tabsPath>/<id>` with nothing after it,
2011
+ * ignoring query, fragment and auxiliary routes); reactive through the router's signals.
2012
+ * @param id The `id` of the tab.
2013
+ */
2014
+ isRoot(id: string): boolean;
2015
+ /** The non-empty segments of `tabsPath`; empty when the tabs are mounted at the root URL. */
2016
+ private baseSegments;
2017
+ /**
2018
+ * Another tab, selected by the user in the bar: go back to where that tab was left (its stack's
2019
+ * top page), or its root. The bar shows the target while the navigation is in flight and drops
2020
+ * back by itself when a guard refuses it.
2021
+ * @param id The `id` of the selected tab.
2022
+ */
2023
+ select(id: string): void;
2024
+ /**
2025
+ * The active tab again: pop its stack back to its existing root page (a history step), or
2026
+ * replace the stack with the root when the history position is unknown; at the root, scroll its
2027
+ * content to the top.
2028
+ * @param id The `id` of the active tab.
2029
+ */
2030
+ reselect(id: string): void;
2031
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfTabsComponent, never>;
2032
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfTabsComponent, "bf-tabs", never, {
2033
+ "tabsPath": {
2034
+ "alias": "tabsPath";
2035
+ "required": true;
2036
+ "isSignal": true;
2037
+ };
2038
+ }, {}, ["bar", "barHost", "outlet"], ["*"], true, never>;
2039
+ }
2040
+ /** @deprecated 0.3.0 use BF_OVERLAY_DATA from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2041
+ export declare const BF_OVERLAY_DATA: import("@angular/core").InjectionToken<unknown>;
2042
+ /** @deprecated 0.3.0 use BfOverlayRef from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2043
+ export declare const BfOverlayRef: typeof core.BfOverlayRef;
2044
+ /** @deprecated 0.3.0 use BfOverlayRef from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2045
+ export type BfOverlayRef<T = unknown> = core.BfOverlayRef<T>;
2046
+ /** @deprecated 0.3.0 use BfComponentOverlayRef from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2047
+ export declare const BfComponentOverlayRef: typeof core.BfComponentOverlayRef;
2048
+ /** @deprecated 0.3.0 use BfComponentOverlayRef from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2049
+ export type BfComponentOverlayRef<C, T = unknown> = core.BfComponentOverlayRef<C, T>;
2050
+ /** @deprecated 0.3.0 use BfOverlayStack from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2051
+ export declare const BfOverlayStack: typeof core.BfOverlayStack;
2052
+ /** @deprecated 0.3.0 use BfOverlayStack from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2053
+ export type BfOverlayStack = core.BfOverlayStack;
2054
+ /** @deprecated 0.3.0 use BfOverlayStackOptions from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2055
+ type BfOverlayStackOptions = core.BfOverlayStackOptions;
2056
+ /** @deprecated 0.3.0 use BfStackedOverlay from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2057
+ type BfStackedOverlay = core.BfStackedOverlay;
2058
+ /** @deprecated 0.3.0 use BfOverlayService from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2059
+ export declare const BfOverlayService: typeof core.BfOverlayService;
2060
+ /** @deprecated 0.3.0 use BfOverlayService from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2061
+ export type BfOverlayService = core.BfOverlayService;
2062
+ /** @deprecated 0.3.0 use BfOverlayOptions from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2063
+ type BfOverlayOptions = core.BfOverlayOptions;
2064
+ /** @deprecated 0.3.0 use BfOverlayPosition from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2065
+ type BfOverlayPosition = core.BfOverlayPosition;
2066
+ /** @deprecated 0.3.0 use BfOverlayTemplateContext from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2067
+ type BfOverlayTemplateContext = core.BfOverlayTemplateContext;
2068
+ /** @deprecated 0.3.0 use OVERLAY_DURATION from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2069
+ export declare const OVERLAY_DURATION = 260;
2070
+ /** @deprecated 0.3.0 use OVERLAY_EASING from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2071
+ export declare const OVERLAY_EASING = "cubic-bezier(0.32, 0.72, 0, 1)";
2072
+ /** @deprecated 0.3.0 use fadeDown from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2073
+ export declare const fadeDown: typeof core.fadeDown;
2074
+ /** @deprecated 0.3.0 use fadeIn from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2075
+ export declare const fadeIn: typeof core.fadeIn;
2076
+ /** @deprecated 0.3.0 use fadeOut from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2077
+ export declare const fadeOut: typeof core.fadeOut;
2078
+ /** @deprecated 0.3.0 use fadeUp from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2079
+ export declare const fadeUp: typeof core.fadeUp;
2080
+ /** @deprecated 0.3.0 use scaleIn from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2081
+ export declare const scaleIn: typeof core.scaleIn;
2082
+ /** @deprecated 0.3.0 use slideDown from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2083
+ export declare const slideDown: typeof core.slideDown;
2084
+ /** @deprecated 0.3.0 use slideUp from '@bitforgehq/ui/overlay'; removed in 0.4.0 */
2085
+ export declare const slideUp: typeof core.slideUp;
2086
+ /** What `BfSheetService` does for a sheet ref; internal. */
2087
+ interface BfSheetController extends BfOverlayController {
2088
+ /** True while the underlying overlay is closing (backdrop, `Escape`, back button, drag). */
2089
+ isClosing(): boolean;
2090
+ }
2091
+ /**
2092
+ * Handle to an open bottom sheet, returned by `BfSheetService.open()` and injectable in the
2093
+ * sheet's content as `BfSheetRef` (and as `BfOverlayRef`). On top of `close(result)` and
2094
+ * `afterClosed` it moves the sheet between its snap points: `snapTo(index)` animates to a point
2095
+ * and `snapIndex()` tracks the current one (also after a drag).
2096
+ *
2097
+ * @example
2098
+ * const ref = sheets.open(FiltersComponent, { snapPoints: [0.4, 0.9] });
2099
+ * ref.snapTo(1);
2100
+ * const filters = await ref.afterClosed;
2101
+ * @since 0.2.0
2102
+ * @summary Handle on an open bottom sheet that moves it between snap points and closes it
2103
+ */
2104
+ export declare class BfSheetRef<T = unknown> extends BfOverlayRef$1<T> {
2105
+ private readonly sheetController;
2106
+ private readonly snapIndexState;
2107
+ /** Index of the snap point the sheet rests at (or is settling to). */
2108
+ readonly snapIndex: Signal<number>;
2109
+ private snapHandler;
2110
+ constructor(sheetController: BfSheetController, initialIndex?: number);
2111
+ /** True from the first close on, whichever way the sheet is being closed. */
2112
+ get isClosing(): boolean;
2113
+ /**
2114
+ * Animates the sheet to the snap point at `index` (clamped to the configured points).
2115
+ * @param index The position of the snap point in `snapPoints`.
2116
+ */
2117
+ snapTo(index: number): void;
2118
+ /** @internal Connects the `bf-sheet` container that performs `snapTo`. */
2119
+ connect(handler: (index: number) => void): void;
2120
+ /** @internal Set by `bf-sheet` whenever the sheet settles on a snap point. */
2121
+ setSnapIndex(index: number): void;
2122
+ }
2123
+ /** What `BfSheetService` hands the `bf-sheet` container (as its `BF_OVERLAY_DATA`); internal. */
2124
+ interface BfSheetConfig {
2125
+ content: Type<unknown> | TemplateRef<unknown>;
2126
+ /** Ascending fractions of the viewport height. */
2127
+ snapPoints: number[];
2128
+ initial: number;
2129
+ dismissible: boolean;
2130
+ /** The caller's data, re-provided to the content as `BF_OVERLAY_DATA`. */
2131
+ data: unknown;
2132
+ /** No `ariaLabel` was given: the panel is named by the content's first heading, if any. */
2133
+ labelledByHeading: boolean;
2134
+ ref: BfSheetRef<unknown>;
2135
+ }
2136
+ /**
2137
+ * The bottom-sheet container that `BfSheetService.open()` renders on the overlay core: a
2138
+ * bottom-anchored `bg-surface` card with a grabber, resting at snap points (fractions of the
2139
+ * viewport height, applied as `--bf-sheet-height`) and rendering the content component or
2140
+ * template with `BF_OVERLAY_DATA` and `BfSheetRef` injectable. Dragging the handle row, any
2141
+ * element marked `data-bf-sheet-drag` (a header) or the content (unless it can scroll up) moves
2142
+ * the sheet with Pointer Events under pointer capture: rubber-banded above the top point, released
2143
+ * onto the nearest point (a fling faster than 0.3 px/ms picks the direction), and dismissed when
2144
+ * released more than 25 % below the lowest point or flung down from it — if the sheet is
2145
+ * dismissible. The content scrolls only at the top snap point, and at every point while the soft
2146
+ * keyboard is up. While the keyboard overlays the sheet's bottom edge (iOS, a mobile browser) the
2147
+ * sheet is lifted by the covered height (`translate`, its bottom safe-area padding dropped); while
2148
+ * the keyboard is up its height is capped at the keyboard's top edge minus the safe-area top minus
2149
+ * 8 px (a drag starts from that capped height), and the content region's `bfKeyboardAssist`
2150
+ * scrolls the focused control 24 px clear of the keyboard. The lift follows the keyboard (250 ms,
2151
+ * instant under `prefers-reduced-motion`). Hiding the keyboard restores the snap height at once
2152
+ * (the drop is instant, so the top edge stays on screen) and scrolls content left scrolled below
2153
+ * the top point back to its top. With two or more snap points the grabber is a button: a press,
2154
+ * `Enter` or `Space` moves one point up (from the top point back to the lowest), the arrow keys
2155
+ * step, `Home` and `End` jump; it is named `expand` or `collapse` (`BF_LABELS`) after the next
2156
+ * press, then `sheetPosition`, and every settle on another point announces `sheetPosition`
2157
+ * politely. A dismissible sheet starts with a visually hidden Close (`BF_LABELS.close`) that screen
2158
+ * readers reach and a keyboard user sees when focused. Not used directly in templates.
2159
+ *
2160
+ * @example
2161
+ * const ref = inject(BfSheetService).open(NewTaskComponent, { snapPoints: [0.5, 0.92] });
2162
+ * @summary Bottom sheet with snap points, drag to dismiss and a backdrop
2163
+ * @category Overlays
2164
+ * @since 0.2.0
2165
+ */
2166
+ export declare class BfSheetComponent {
2167
+ private readonly config;
2168
+ private readonly host;
2169
+ private readonly document;
2170
+ private readonly keyboard;
2171
+ private readonly keyboardCover;
2172
+ private readonly contentElement;
2173
+ private readonly contentAssist;
2174
+ protected readonly template: TemplateRef<unknown> | null;
2175
+ protected readonly component: Type<unknown> | null;
2176
+ protected readonly contentInjector: import("@angular/core").DestroyableInjector;
2177
+ protected readonly templateContext: BfOverlayTemplateContext$1;
2178
+ private readonly lastIndex;
2179
+ protected readonly labels: import("@bitforgehq/ui").BfLabels;
2180
+ protected readonly dismissible: boolean;
2181
+ /** Two or more snap points: the grabber is a button that moves between them. */
2182
+ protected readonly adjustable: boolean;
2183
+ private readonly announcer;
2184
+ /**
2185
+ * What the next press does (collapse at the top point, else expand), then where the sheet is:
2186
+ * "Expand, Sheet at 1 of 2".
2187
+ */
2188
+ protected readonly grabberLabel: import("@angular/core").Signal<string>;
2189
+ /** A drag that started on the grabber button ends without the click that may follow it. */
2190
+ private suppressGrabberClick;
2191
+ /**
2192
+ * The content scrolls at the top snap point and whenever the keyboard is up (the sheet may be
2193
+ * capped below its content); otherwise drags move the sheet.
2194
+ */
2195
+ private readonly contentScrolls;
2196
+ protected readonly contentClass: import("@angular/core").Signal<string>;
2197
+ private index;
2198
+ /** Rendered height (px) and downward translation (px) below the lowest point. */
2199
+ private height;
2200
+ private offset;
2201
+ private gesture;
2202
+ private settleAnimation;
2203
+ constructor();
2204
+ /**
2205
+ * Lifts the sheet by the part of the viewport the keyboard covers and caps its height at the
2206
+ * keyboard's top edge; both go away with the keyboard, at once. Separate from
2207
+ * `--bf-sheet-height`, so drag and snap logic never see them.
2208
+ */
2209
+ private applyKeyboard;
2210
+ /** The content's keyboard assist measured a sheet still sliding up: it measures once more. */
2211
+ private readonly onTransitionEnd;
2212
+ protected close(): void;
2213
+ /**
2214
+ * A press: one point higher, or from the top point back to the lowest. The click a pointer drag
2215
+ * may leave behind is swallowed; a keyboard or assistive-technology click (`detail` 0) never is.
2216
+ */
2217
+ protected onGrabberClick(event: MouseEvent): void;
2218
+ /** Arrow keys step between points (never past the ends, never dismissing); Home and End jump. */
2219
+ protected onGrabberKeydown(event: KeyboardEvent): void;
2220
+ private snapTo;
2221
+ /** Viewport height with the keyboard hidden: the `100lvh` probe, else `innerHeight`. */
2222
+ private viewportHeight;
2223
+ private heights;
2224
+ private readonly onResize;
2225
+ private readonly onPointerDown;
2226
+ /**
2227
+ * Whether a content drag may move the sheet: always while the content does not scroll (below the
2228
+ * top snap point, keyboard hidden), and otherwise only downward while it is scrolled to 0.
2229
+ */
2230
+ private contentMayDrag;
2231
+ /**
2232
+ * Non-passive `touchmove` guard, attached only while a press is tracked (the refresher's
2233
+ * pattern): keeps the browser from taking the drag as a pan, which would end the pointer stream
2234
+ * with `pointercancel`. Content drags the sheet does not want (upward at the top point,
2235
+ * horizontal) are left to scroll.
2236
+ */
2237
+ private readonly touchMoveGuard;
2238
+ private readonly onPointerMove;
2239
+ /** Renders a proposed visible height: rubber-banded past the ends, translated below the lowest. */
2240
+ private show;
2241
+ private readonly onPointerUp;
2242
+ private readonly onPointerCancel;
2243
+ /** Only the host losing the capture it took ends the drag (a child's implicit capture bubbles). */
2244
+ private readonly onLostPointerCapture;
2245
+ /** Downward velocity (px/ms) over the last samples; 0 when they carry no elapsed time. */
2246
+ private velocity;
2247
+ private release;
2248
+ private nearest;
2249
+ /** Animates (instantly under reduced motion) to the snap point at `index`. */
2250
+ private settleTo;
2251
+ /**
2252
+ * The height the sheet shows: its snap height, or less while the keyboard caps it (`max-height`),
2253
+ * so a drag of a capped sheet moves it from the first pixel.
2254
+ */
2255
+ private renderedHeight;
2256
+ /** A press during a settle continues from where the animation had got to. */
2257
+ private captureAnimatedHeight;
2258
+ private apply;
2259
+ private endGesture;
2260
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfSheetComponent, never>;
2261
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfSheetComponent, "bf-sheet", never, {}, {}, never, never, true, never>;
2262
+ }
2263
+ /**
2264
+ * Where focus goes when a sheet opens: the sheet itself (`panel`), so no soft keyboard comes up
2265
+ * and a screen reader starts reading at the sheet, or its first field (`first-field`): the element
2266
+ * marked `[autofocus]`/`[cdkFocusInitial]`, else the first focusable element of the content, which
2267
+ * raises the keyboard on Android when it is a text field.
2268
+ *
2269
+ * @summary Where focus lands when a sheet opens, the sheet itself or its first field
2270
+ * @since 0.3.0
2271
+ */
2272
+ type BfSheetAutoFocus = 'panel' | 'first-field';
2273
+ /**
2274
+ * Options of `BfSheetService.open()`.
2275
+ *
2276
+ * @summary Options of a bottom sheet: where it rests, how it closes and its name
2277
+ * @since 0.2.0
2278
+ */
2279
+ interface BfSheetOptions {
2280
+ /**
2281
+ * Heights the sheet rests at, as fractions of the viewport height (default `[0.5, 0.92]`).
2282
+ * @default [0.5, 0.92]
2283
+ */
2284
+ snapPoints?: number[];
2285
+ /**
2286
+ * Index of the snap point the sheet opens at (default 0).
2287
+ * @default 0
2288
+ */
2289
+ initial?: number;
2290
+ /**
2291
+ * The backdrop, `Escape`, the hardware back button and a downward drag close the sheet
2292
+ * (default true). When false only `close()` does, or a navigation (see `closeOnNavigation`).
2293
+ * @default true
2294
+ */
2295
+ dismissible?: boolean;
2296
+ /** Injected into the content as `BF_OVERLAY_DATA`. */
2297
+ data?: unknown;
2298
+ /**
2299
+ * A navigation to another URL path (a pushed or popped page, a tab switch) closes the sheet with
2300
+ * no result (default true), also a non-dismissible one.
2301
+ * @default true
2302
+ */
2303
+ closeOnNavigation?: boolean;
2304
+ /**
2305
+ * Accessible name of the sheet. Without it the sheet is named by the first heading in its
2306
+ * content (`aria-labelledby`), else by `provideBfLabels()`'s `sheet` ("Sheet").
2307
+ */
2308
+ ariaLabel?: string;
2309
+ /**
2310
+ * Where focus goes on open: `panel` (default) focuses the sheet itself (a `role="dialog"` with a
2311
+ * name and `tabindex="-1"`), so a screen reader lands inside it and no soft keyboard hides it;
2312
+ * `first-field` focuses the element marked `[autofocus]`/`[cdkFocusInitial]`, else the first
2313
+ * focusable element of the content (never the sheet's own Close and grabber), which raises the
2314
+ * keyboard on Android when it is a text field.
2315
+ * @default 'panel'
2316
+ */
2317
+ autoFocus?: BfSheetAutoFocus;
2318
+ /**
2319
+ * Injector the sheet resolves its labels (`BF_LABELS`) from and the parent of its content's
2320
+ * injector (default the root injector). Pass the opening component's `inject(Injector)` so a
2321
+ * feature-level `provideBfLabels()` and other feature providers reach it.
2322
+ */
2323
+ injector?: Injector;
2324
+ }
2325
+ /**
2326
+ * Snap points used when none (or no valid ones) are given.
2327
+ *
2328
+ * @summary The snap points a bottom sheet rests at when none are given, half and full
2329
+ * @since 0.2.0
2330
+ */
2331
+ export declare const BF_SHEET_DEFAULT_SNAP_POINTS: readonly number[];
2332
+ /**
2333
+ * Opens bottom sheets: a component or template in a `bf-sheet` container on the overlay core,
2334
+ * bottom-anchored over a backdrop, resting at snap points (fractions of the viewport height).
2335
+ * The content injects `BF_OVERLAY_DATA` and `BfSheetRef` (also as `BfOverlayRef`) to read its
2336
+ * data, move between snap points and close with a result. A dismissible sheet (the default)
2337
+ * closes on a backdrop tap, `Escape`, the hardware back button and a drag below its lowest
2338
+ * point; a non-dismissible one only through `close()`, and swallows the back button while open.
2339
+ * A navigation to another URL path closes either (`closeOnNavigation`). On open, focus goes to the
2340
+ * sheet itself, so no soft keyboard comes up (`autoFocus: 'first-field'` focuses the first field).
2341
+ *
2342
+ * @example
2343
+ * const ref = inject(BfSheetService).open<NewTaskComponent, Task>(NewTaskComponent, {
2344
+ * snapPoints: [0.5, 0.92],
2345
+ * data: { listId },
2346
+ * });
2347
+ * const task = await ref.afterClosed;
2348
+ * @since 0.2.0
2349
+ * @summary Opens bottom sheets that rest at snap points and close with a result
2350
+ */
2351
+ export declare class BfSheetService {
2352
+ private readonly overlays;
2353
+ private readonly stack;
2354
+ private readonly backButton;
2355
+ private readonly injector;
2356
+ /**
2357
+ * Opens `content` (a component or a template) in a bottom sheet.
2358
+ * @param content The component or template to render in the sheet.
2359
+ * @param options Where the sheet rests, how it closes and its name.
2360
+ */
2361
+ open<C, T = unknown>(content: Type<C> | TemplateRef<unknown>, options?: BfSheetOptions): BfSheetRef<T>;
2362
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfSheetService, never>;
2363
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
2364
+ }
2365
+ /**
2366
+ * Where `bf-modal` sits: a page-sheet card, or edge to edge.
2367
+ *
2368
+ * @summary How a modal is presented: a page-sheet card over the stack, or fullscreen
2369
+ * @since 0.2.0
2370
+ */
2371
+ type BfModalPresentation = 'sheet' | 'fullscreen';
2372
+ /** What `BfModalService` hands the `bf-modal` container (as its `BF_OVERLAY_DATA`); internal. */
2373
+ interface BfModalConfig {
2374
+ content: Type<unknown>;
2375
+ presentation: BfModalPresentation;
2376
+ /** The caller's data, re-provided to the content as `BF_OVERLAY_DATA`. */
2377
+ data: unknown;
2378
+ /** No `ariaLabel` was given: the panel is named by the content's first heading, if any. */
2379
+ labelledByHeading: boolean;
2380
+ }
2381
+ /**
2382
+ * The modal frame that `BfModalService.open()` renders on the overlay core, `position:
2383
+ * 'fullscreen'`: a `sheet` presentation (default) is a card whose top sits 10 px below the top
2384
+ * safe area (UIKit's page-sheet inset; `bg-bg rounded-t-card shadow-floating`) over the parked page stack, which scales down and
2385
+ * grows rounded corners behind it (`--bf-modal-depth`, written by `BfOverlayStack`, consumed by
2386
+ * `bf-stack-outlet`'s host rule); `fullscreen` covers the viewport edge to edge with no scale.
2387
+ * Like `bf-page`, it provides a fresh `BfPageContext` so the content's `bf-header` and
2388
+ * `bf-content` work inside it (with `mainLandmark` false, so its content is no `main` landmark,
2389
+ * and in the `sheet` presentation with `safeAreaTop` false, so the header adds no status-bar band
2390
+ * inside the card) — the content supplies its own header (typically a close
2391
+ * `bf-icon-button` in `start`) and content region. While the soft keyboard overlays the bottom of
2392
+ * a `sheet` card (iOS, a mobile browser), the card is padded at the bottom by the covered height,
2393
+ * so the content's `bf-content` ends at the keyboard's top edge and its keyboard assist reveals
2394
+ * the focused control there. Not used directly in templates.
2395
+ *
2396
+ * @example
2397
+ * const ref = inject(BfModalService).open(EditTaskComponent, { data: { taskId } });
2398
+ * @summary Modal overlay shown as an inset card over the scaled-down page, or full screen
2399
+ * @category Overlays
2400
+ * @since 0.2.0
2401
+ */
2402
+ export declare class BfModalComponent {
2403
+ protected readonly config: BfModalConfig;
2404
+ private readonly outerRef;
2405
+ private readonly keyboardCover;
2406
+ protected readonly hostClasses: string;
2407
+ /** A sheet card ends at the keyboard's top edge; a fullscreen frame leaves it to `bf-content`. */
2408
+ protected readonly keyboardPadding: import("@angular/core").Signal<number | null>;
2409
+ protected readonly contentInjector: import("@angular/core").DestroyableInjector;
2410
+ constructor();
2411
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfModalComponent, never>;
2412
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfModalComponent, "bf-modal", never, {}, {}, never, never, true, never>;
2413
+ }
2414
+ /**
2415
+ * Options of `BfModalService.open()`.
2416
+ *
2417
+ * @summary Options of a modal: its data, presentation, dismissal and accessible name
2418
+ * @since 0.2.0
2419
+ */
2420
+ interface BfModalOptions {
2421
+ /** Injected into the content as `BF_OVERLAY_DATA`. */
2422
+ data?: unknown;
2423
+ /**
2424
+ * A page-sheet card over the parked page stack (default), or a fullscreen frame.
2425
+ * @default 'sheet'
2426
+ */
2427
+ presentation?: BfModalPresentation;
2428
+ /**
2429
+ * `Escape` and the hardware back button close the modal (default true); with false only the
2430
+ * content's own close control does, or a navigation (see `closeOnNavigation`), and back is
2431
+ * swallowed while the modal is open instead of
2432
+ * falling through to the page behind. There is no backdrop dismiss or drag-to-dismiss.
2433
+ * @default true
2434
+ */
2435
+ dismissible?: boolean;
2436
+ /**
2437
+ * A navigation to another URL path closes the modal with no result (default true).
2438
+ * @default true
2439
+ */
2440
+ closeOnNavigation?: boolean;
2441
+ /**
2442
+ * Accessible name of the modal panel. Without it the modal is named by the first heading in
2443
+ * its content (`aria-labelledby`, e.g. the `bf-header` title), else by `provideBfLabels()`'s
2444
+ * `modal` ("Modal").
2445
+ */
2446
+ ariaLabel?: string;
2447
+ /**
2448
+ * Injector the modal resolves its labels (`BF_LABELS`) from and the parent of its content's
2449
+ * injector (default the root injector). Pass the opening component's `inject(Injector)` so a
2450
+ * feature-level `provideBfLabels()` and other feature providers reach it.
2451
+ */
2452
+ injector?: Injector;
2453
+ }
2454
+ /**
2455
+ * Opens modals: a component in a `bf-modal` frame on the overlay core (`position: 'fullscreen'`,
2456
+ * no backdrop dismiss). `presentation: 'sheet'` (default) is a page-sheet card 10 px below the
2457
+ * top safe area over the parked page stack, which in iOS mode scales down and grows rounded corners
2458
+ * behind it (`countsAsModal: true`, driving `--bf-modal-depth` on the registered
2459
+ * `bf-stack-outlet` roots; Material mode leaves the page unscaled); `'fullscreen'` covers the
2460
+ * viewport edge to edge and does not count towards that depth. iOS mode
2461
+ * slides the card up and down; Material mode fades it up (and down) 16 px. The content supplies
2462
+ * its own `bf-header` (`largeTitle="false"`, typically a close `bf-icon-button` in `start`) and
2463
+ * `bf-content` — `bf-modal` provides a `BfPageContext` for them, like `bf-page`. It injects the
2464
+ * caller's `data` as `BF_OVERLAY_DATA` and closes itself with a result through the injected
2465
+ * `BfOverlayRef`, which `open()` also returns. A navigation to another URL path closes it with no
2466
+ * result (`closeOnNavigation`).
2467
+ *
2468
+ * @example
2469
+ * const ref = inject(BfModalService).open<EditTaskComponent, Task>(EditTaskComponent, {
2470
+ * data: { taskId },
2471
+ * });
2472
+ * const saved = await ref.afterClosed;
2473
+ * @since 0.2.0
2474
+ * @summary Opens a component as a modal page sheet over the stack, or fullscreen
2475
+ */
2476
+ export declare class BfModalService {
2477
+ private readonly overlays;
2478
+ private readonly stack;
2479
+ private readonly backButton;
2480
+ private readonly platform;
2481
+ private readonly injector;
2482
+ private readonly config;
2483
+ /**
2484
+ * Opens `component` as a modal.
2485
+ * @param component The component to render; it injects `BfOverlayRef` and `BF_OVERLAY_DATA`.
2486
+ * @param options The modal's data, presentation, dismissal and name.
2487
+ */
2488
+ open<C, T = unknown>(component: Type<C>, options?: BfModalOptions): BfOverlayRef$1<T>;
2489
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfModalService, never>;
2490
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
2491
+ }
2492
+ /**
2493
+ * Where the toast pill anchors in the viewport.
2494
+ *
2495
+ * @summary Where a mobile toast pill anchors in the viewport, at the bottom or top
2496
+ * @since 0.2.0
2497
+ */
2498
+ type BfToastPosition = 'bottom' | 'top';
2499
+ /** The action rendered as a real button inside the pill; internal. */
2500
+ interface BfToastActionConfig {
2501
+ label: string;
2502
+ run: () => void;
2503
+ }
2504
+ /** What holds a toast's timer: the pointer over it, or focus inside it; internal. */
2505
+ type BfToastHoldSource = 'pointer' | 'focus';
2506
+ /** What `BfToastService` hands the `bf-toast` container (as its `BF_OVERLAY_DATA`); internal. */
2507
+ interface BfToastConfig {
2508
+ message: string;
2509
+ action: BfToastActionConfig | null;
2510
+ position: BfToastPosition;
2511
+ /** Told when the pointer or focus enters (`held: true`) or leaves the pill; pauses the timer. */
2512
+ hold?: (source: BfToastHoldSource, held: boolean) => void;
2513
+ /** `Escape` pressed while focus is inside the pill; the service dismisses the toast. */
2514
+ escape?: () => void;
2515
+ }
2516
+ /**
2517
+ * The status pill that `BfToastService.show()` renders on the overlay core (`passive: true`, no
2518
+ * backdrop, no focus trap, no inert page and no back handler — it never steals focus): an ink
2519
+ * `bg-text text-bg rounded-full shadow-floating` pill holding the message (truncated to two lines)
2520
+ * and an optional action. The pill is not a live region: the service announces each toast once
2521
+ * through CDK `LiveAnnouncer`. The pointer over it or focus inside it pauses its timer, and
2522
+ * `Escape` with focus inside dismisses it. `position: 'bottom'` (default) sits 16 px above the
2523
+ * tab-bar inset (`--bf-tab-bar-inset-global`, published on `<html>` by `bf-tabs`, which leaves
2524
+ * 8 px above the floating bar, so the toast clears it by 24 px) and the soft keyboard
2525
+ * (`--bf-toast-keyboard` on the host: `BfKeyboardService.height()` where the keyboard overlays
2526
+ * the WebView — native iOS — and 0 where the WebView already shrinks); `position: 'top'` sits
2527
+ * 16 px below the status bar (a top margin of the safe-area inset plus 16 px, outside the pill)
2528
+ * instead. Not used directly in templates.
2529
+ *
2530
+ * @example
2531
+ * const ref = inject(BfToastService).show({ message: 'Saved' });
2532
+ * @summary Passive status pill with an optional action that never steals focus
2533
+ * @category Overlays
2534
+ * @since 0.2.0
2535
+ */
2536
+ export declare class BfToastComponent {
2537
+ protected readonly config: BfToastConfig;
2538
+ private readonly host;
2539
+ private readonly keyboard;
2540
+ protected readonly classes: string;
2541
+ constructor();
2542
+ protected hold(source: BfToastHoldSource, held: boolean): void;
2543
+ /** Focus moving between elements inside the pill still holds it. */
2544
+ protected focusLeft(event: Event): void;
2545
+ /** `Escape` with focus inside dismisses the toast; claimed, so no overlay underneath sees it. */
2546
+ protected keydown(event: Event): void;
2547
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfToastComponent, never>;
2548
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfToastComponent, "bf-toast", never, {}, {}, never, never, true, never>;
2549
+ }
2550
+ /**
2551
+ * Options of `BfToastService.show()`.
2552
+ *
2553
+ * @summary Options of a mobile toast: its message, an action, its duration and position
2554
+ * @since 0.2.0
2555
+ */
2556
+ interface BfToastOptions {
2557
+ /** Text of the pill, truncated to two lines. */
2558
+ message: string;
2559
+ /** An optional action button. */
2560
+ action?: BfToastAction$1;
2561
+ /**
2562
+ * Milliseconds before the toast auto-dismisses, not counting time the pointer is over it or
2563
+ * focus is inside it; `0` keeps it until dismissed or its action fires (default 3000 without an
2564
+ * action, `0` with one).
2565
+ * @default 3000
2566
+ */
2567
+ duration?: number;
2568
+ /**
2569
+ * Where the pill anchors (default `'bottom'`).
2570
+ * @default 'bottom'
2571
+ */
2572
+ position?: BfToastPosition;
2573
+ }
2574
+ /**
2575
+ * Queues status pills: `show(options)` renders `bf-toast` on the overlay core (`passive: true` —
2576
+ * no backdrop, no focus trap, the page stays interactive, and it never counts towards
2577
+ * `BfOverlayStack.count()`) and returns a `BfToastRef`. One toast is visible at a time; later
2578
+ * calls queue in order and show once the current one ends. A toast auto-dismisses after
2579
+ * `duration` ms (default 3000, resolving `'timeout'`); a toast with an action defaults to
2580
+ * `duration: 0`, which keeps it until `dismiss()`, `Escape` inside it (`'dismiss'`) or its action
2581
+ * button (`'action'`) ends it; such a persistent toast never blocks the queue — the next `show()`
2582
+ * replaces it (`'dismiss'`). The timer pauses while the pointer is over the toast or focus is
2583
+ * inside it and resumes with the remaining time. When a toast still holding focus closes, focus
2584
+ * returns to the element focused last outside it. Each toast is announced once, politely, through
2585
+ * CDK `LiveAnnouncer` as it shows. A navigation (a pushed or popped page, a tab switch) never
2586
+ * closes it.
2587
+ *
2588
+ * @example
2589
+ * const ref = inject(BfToastService).show({
2590
+ * message: 'Task deleted',
2591
+ * action: { label: 'Undo', handler: () => restore(task) },
2592
+ * });
2593
+ * const reason = await ref.afterDismissed;
2594
+ * @since 0.2.0
2595
+ * @summary Shows brief toast pills on phones, one at a time, queued in order
2596
+ */
2597
+ export declare class BfToastService {
2598
+ private readonly overlays;
2599
+ private readonly queue;
2600
+ /**
2601
+ * Queues `options` as a toast; shows it now if none is visible, else once the current one ends.
2602
+ * A persistent toast (`duration` 0, the default with an action) never blocks the queue: a later
2603
+ * `show()` dismisses it (`'dismiss'`), whether it is visible or still waiting.
2604
+ * @param options The toast's message, action, duration and position.
2605
+ * @returns The toast's ref, to dismiss it or await why it ended.
2606
+ */
2607
+ show(options: BfToastOptions): BfToastRef$1;
2608
+ /** Opens one passive overlay per toast, exactly as before the engine moved to `/overlay`. */
2609
+ private present;
2610
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfToastService, never>;
2611
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
2612
+ }
2613
+ /**
2614
+ * The role of an action sheet row: `destructive` renders it in `text-danger`, `cancel` makes it the
2615
+ * separate cancel button.
2616
+ *
2617
+ * @summary The role of an action sheet row, a destructive action or the cancel button
2618
+ * @since 0.3.0
2619
+ */
2620
+ type BfActionSheetActionRole = 'destructive' | 'cancel';
2621
+ /**
2622
+ * One row of an action sheet, or its cancel action when `role: 'cancel'`.
2623
+ *
2624
+ * @summary One row of an action sheet, or its cancel button, with its answer and role
2625
+ * @since 0.2.0
2626
+ */
2627
+ interface BfActionSheetAction {
2628
+ /** What `open()` resolves with when the row is tapped (default `label`); keeps the answer
2629
+ * stable when the label is translated or two rows share a label. Ignored on the cancel action,
2630
+ * which always resolves `undefined`. */
2631
+ id?: string;
2632
+ /** Row text; also what `open()` resolves with when the row is tapped and has no `id`. */
2633
+ label: string;
2634
+ /** Icon rendered in the row's leading slot. */
2635
+ icon?: IconNode;
2636
+ /**
2637
+ * `destructive` renders the row's label in `text-danger`; `cancel` renders it as the separate
2638
+ * cancel button instead of a row (a plain row when omitted).
2639
+ */
2640
+ role?: BfActionSheetActionRole;
2641
+ }
2642
+ /** What `BfActionSheetService` hands the `bf-action-sheet` container (as its `BF_OVERLAY_DATA`); internal. */
2643
+ interface BfActionSheetConfig {
2644
+ /** Heading above the rows, or `undefined` for none. */
2645
+ title: string | undefined;
2646
+ /** The caller's non-cancel actions, in order. */
2647
+ actions: BfActionSheetAction[];
2648
+ /** Label of the cancel button: the caller's `cancel`-role action, or "Cancel". */
2649
+ cancelLabel: string;
2650
+ }
2651
+ /**
2652
+ * The action sheet panel that `BfActionSheetService.open()` renders on the overlay core
2653
+ * (`position: 'bottom'`): an optional title above a `bf-list` of interactive rows for the
2654
+ * actions (destructive ones in `text-danger`, an icon in the leading slot) and a separate
2655
+ * `tonal` `bf-button` for the cancel action — rendered even when the caller passes none,
2656
+ * labelled "Cancel", which takes the initial focus. Tapping a row resolves the overlay with its
2657
+ * `id ?? label`; the cancel button, like
2658
+ * the backdrop, `Escape` and the hardware back button, resolves `undefined`. Not used directly
2659
+ * in templates.
2660
+ *
2661
+ * @example
2662
+ * const answer = await inject(BfActionSheetService).open({
2663
+ * title: 'Delete list?',
2664
+ * actions: [{ id: 'delete', label: 'Delete', role: 'destructive' }],
2665
+ * });
2666
+ * @summary Bottom panel of labelled actions with a separate cancel button, destructive ones shown in red
2667
+ * @category Overlays
2668
+ * @since 0.2.0
2669
+ */
2670
+ export declare class BfActionSheetComponent {
2671
+ protected readonly config: BfActionSheetConfig;
2672
+ private readonly ref;
2673
+ protected select(action: BfActionSheetAction): void;
2674
+ protected cancel(): void;
2675
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfActionSheetComponent, never>;
2676
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfActionSheetComponent, "bf-action-sheet", never, {}, {}, never, never, true, never>;
2677
+ }
2678
+ /**
2679
+ * Options of `BfActionSheetService.open()`.
2680
+ *
2681
+ * @summary Options of an action sheet: its title, its rows and when it closes
2682
+ * @since 0.2.0
2683
+ */
2684
+ interface BfActionSheetOptions {
2685
+ /** Heading above the rows; also the panel's accessible name (default `provideBfLabels()`'s
2686
+ * `actions`, "Actions"). */
2687
+ title?: string;
2688
+ /**
2689
+ * Rows, in order; a `cancel`-role entry becomes the separate cancel button instead of a row.
2690
+ * Only the first `cancel`-role entry is used; any further ones are ignored.
2691
+ */
2692
+ actions: BfActionSheetAction[];
2693
+ /**
2694
+ * A navigation to another URL path closes the sheet, resolving `undefined` (default true).
2695
+ * @default true
2696
+ */
2697
+ closeOnNavigation?: boolean;
2698
+ /**
2699
+ * Injector the action sheet resolves its labels (`BF_LABELS`) from and the parent of its content's
2700
+ * injector (default the root injector). Pass the opening component's `inject(Injector)` so a
2701
+ * feature-level `provideBfLabels()` and other feature providers reach it.
2702
+ */
2703
+ injector?: Injector;
2704
+ }
2705
+ /**
2706
+ * Opens action sheets: a bottom-anchored list of actions on the overlay core (`position:
2707
+ * 'bottom'`, not counted as a modal). Renders `title` above a `bf-list` of the non-cancel
2708
+ * `actions` as interactive rows (destructive ones in `text-danger`, an icon in the leading slot
2709
+ * from `icon`), and a separate `tonal` `bf-button` for the cancel action — the caller's
2710
+ * first `cancel`-role entry if any (further ones are ignored), else a synthesized one labelled `provideBfLabels()`'s `cancel` ("Cancel").
2711
+ * Focus starts on the cancel button. `open()` resolves with the tapped row's `id ?? label`; the
2712
+ * cancel button, a backdrop tap, `Escape`, the hardware back button and a navigation to another
2713
+ * URL path all resolve `undefined`.
2714
+ *
2715
+ * @example
2716
+ * const answer = await inject(BfActionSheetService).open({
2717
+ * title: 'Delete list?',
2718
+ * actions: [
2719
+ * { id: 'delete', label: 'Delete', role: 'destructive' },
2720
+ * { id: 'rename', label: 'Rename' },
2721
+ * ],
2722
+ * });
2723
+ * @since 0.2.0
2724
+ * @summary Opens bottom action sheets that resolve with the row the user tapped
2725
+ */
2726
+ export declare class BfActionSheetService {
2727
+ private readonly overlays;
2728
+ private readonly injector;
2729
+ /**
2730
+ * Opens the action sheet described by `options`; resolves with the tapped row's `id ?? label`,
2731
+ * or `undefined` when cancelled.
2732
+ * @param options The title and rows of the sheet.
2733
+ */
2734
+ open(options: BfActionSheetOptions): Promise<string | undefined>;
2735
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfActionSheetService, never>;
2736
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
2737
+ }
2738
+ /**
2739
+ * The role of an alert dialog button: `cancel` answers `Escape` and the hardware back button,
2740
+ * `destructive` renders `danger`.
2741
+ *
2742
+ * @summary The role of an alert dialog button, the cancel answer or a destructive action
2743
+ * @since 0.3.0
2744
+ */
2745
+ type BfAlertDialogButtonRole = 'cancel' | 'destructive';
2746
+ /**
2747
+ * A button of `BfAlertDialogService.open()`.
2748
+ *
2749
+ * @summary One button of an alert dialog: its answer, its label and its role
2750
+ * @since 0.2.0
2751
+ */
2752
+ interface BfAlertDialogButton {
2753
+ /** What `open()` resolves with when the button is tapped (default `label`); keeps the answer
2754
+ * stable when the label is translated or two buttons share a label. */
2755
+ id?: string;
2756
+ /** Button text; also the value `open()` resolves with when it is tapped and has no `id`. */
2757
+ label: string;
2758
+ /**
2759
+ * `cancel` renders as a `text` button, takes the initial focus and is what `Escape`/the
2760
+ * hardware back button answer with; `destructive` renders `danger` (a plain `primary`/`tonal` button when omitted).
2761
+ */
2762
+ role?: BfAlertDialogButtonRole;
2763
+ }
2764
+ /**
2765
+ * Options of `BfAlertDialogService.open()`.
2766
+ *
2767
+ * @summary Options of an alert dialog: its title, message, buttons and when it closes
2768
+ * @since 0.2.0
2769
+ */
2770
+ interface BfAlertDialogOptions {
2771
+ /** Dialog heading, rendered as the `h2` the panel's `aria-labelledby` points to. */
2772
+ title: string;
2773
+ /** Body text under the title. */
2774
+ message?: string;
2775
+ /** Buttons, left to right (default one button labelled `provideBfLabels()`'s `ok`, "OK"). */
2776
+ buttons?: BfAlertDialogButton[];
2777
+ /**
2778
+ * A navigation to another URL path closes the alert, resolving the cancel button's answer, or
2779
+ * `undefined` without one (default true).
2780
+ * @default true
2781
+ */
2782
+ closeOnNavigation?: boolean;
2783
+ /**
2784
+ * Injector the dialog resolves its labels (`BF_LABELS`) from and the parent of its content's
2785
+ * injector (default the root injector). Pass the opening component's `inject(Injector)` so a
2786
+ * feature-level `provideBfLabels()` and other feature providers reach it.
2787
+ */
2788
+ injector?: Injector;
2789
+ }
2790
+ /**
2791
+ * Opens alert dialogs: a centred, 300 px card on the overlay core (`position: 'center'`, no
2792
+ * backdrop dismiss). Renders `title` as an `h2`, an optional `message`, and `buttons` (default
2793
+ * one `ok` button from the app's `provideBfLabels()`, "OK") as a right-aligned row — `cancel`-role `text`, `destructive`-role
2794
+ * `danger`, the first plain button `primary`, further plain ones `tonal`. Focus starts on the
2795
+ * `cancel`-role button, else the first one. `open()` resolves with the tapped button's
2796
+ * `id ?? label`. `Escape` and the hardware back button resolve with the cancel button's answer
2797
+ * when `buttons` has one; with none, they are claimed and ignored — an alert
2798
+ * with no cancel button can only be answered by tapping a button, or closed by a navigation to
2799
+ * another URL path, which resolves the cancel button's answer, else `undefined`.
2800
+ *
2801
+ * @example
2802
+ * const answer = await inject(BfAlertDialogService).open({
2803
+ * title: 'Delete list?',
2804
+ * message: 'This cannot be undone.',
2805
+ * buttons: [
2806
+ * { id: 'cancel', label: 'Cancel', role: 'cancel' },
2807
+ * { id: 'delete', label: 'Delete', role: 'destructive' },
2808
+ * ],
2809
+ * });
2810
+ * @since 0.2.0
2811
+ * @summary Opens small centred alerts that resolve with the button the user tapped
2812
+ */
2813
+ export declare class BfAlertDialogService {
2814
+ private readonly overlays;
2815
+ private readonly stack;
2816
+ private readonly backButton;
2817
+ private readonly injector;
2818
+ /**
2819
+ * Opens the alert described by `options`; resolves with the tapped button's `id ?? label`, or
2820
+ * `undefined` when a navigation closes an alert that has no cancel button.
2821
+ * @param options The title, message and buttons of the alert.
2822
+ */
2823
+ open(options: BfAlertDialogOptions): Promise<string | undefined>;
2824
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfAlertDialogService, never>;
2825
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
2826
+ }
2827
+ /** A button of an alert dialog, with the variant `BfAlertDialogService` resolved for it. */
2828
+ interface BfAlertDialogButtonConfig {
2829
+ /** Button text. */
2830
+ label: string;
2831
+ /** What `open()` resolves with when it is tapped: the caller's `id ?? label`. */
2832
+ answer: string;
2833
+ /** `cancel` answers `Escape`/the hardware back button; `destructive` renders `danger`. */
2834
+ role?: BfAlertDialogButtonRole;
2835
+ variant: BfButtonVariant;
2836
+ /** Whether it takes the initial focus: the `cancel`-role button, else the first one. */
2837
+ initial: boolean;
2838
+ }
2839
+ /** What `BfAlertDialogService` hands the `bf-alert-dialog` container (as its `BF_OVERLAY_DATA`); internal. */
2840
+ interface BfAlertDialogConfig {
2841
+ title: string;
2842
+ message: string | undefined;
2843
+ /** Id of the `h2` title, referenced by the panel's `aria-labelledby`. */
2844
+ titleId: string;
2845
+ /** Id of the message `p`, referenced by the panel's `aria-describedby` when there is a message. */
2846
+ messageId: string;
2847
+ buttons: BfAlertDialogButtonConfig[];
2848
+ }
2849
+ /**
2850
+ * The alert dialog card that `BfAlertDialogService.open()` renders on the overlay core
2851
+ * (`position: 'center'`): an `h2.text-heading` title, an optional `text-body text-text-secondary`
2852
+ * message, and a right-aligned row of `bf-button`s (`cancel`-role `text`, `destructive`-role
2853
+ * `danger`, the first plain button `primary`, further plain ones `tonal`). Focus starts on the
2854
+ * `cancel`-role button, else the first one. Tapping a button resolves the overlay with its
2855
+ * `id ?? label`. There is no backdrop dismiss; `Escape` and the hardware
2856
+ * back button are handled by `BfAlertDialogService` (the cancel button's answer, or claimed and
2857
+ * ignored when there is none). Not used directly in templates.
2858
+ *
2859
+ * @example
2860
+ * const answer = await inject(BfAlertDialogService).open({
2861
+ * title: 'Delete list?',
2862
+ * message: 'This cannot be undone.',
2863
+ * buttons: [
2864
+ * { id: 'cancel', label: 'Cancel', role: 'cancel' },
2865
+ * { id: 'delete', label: 'Delete', role: 'destructive' },
2866
+ * ],
2867
+ * });
2868
+ * @summary Centred confirmation dialog with a title, message and a row of role-styled buttons
2869
+ * @category Overlays
2870
+ * @since 0.2.0
2871
+ */
2872
+ export declare class BfAlertDialogComponent {
2873
+ protected readonly config: BfAlertDialogConfig;
2874
+ private readonly ref;
2875
+ protected select(button: BfAlertDialogButtonConfig): void;
2876
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfAlertDialogComponent, never>;
2877
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfAlertDialogComponent, "bf-alert-dialog", never, {}, {}, never, never, true, never>;
2878
+ }
2879
+ /**
2880
+ * Options of `provideBfShellTesting()`.
2881
+ *
2882
+ * @summary Options of the shell test providers: the routes and the shell settings
2883
+ * @since 0.3.0
2884
+ */
2885
+ interface BfShellTestingOptions {
2886
+ /**
2887
+ * The routes of the test router.
2888
+ * @default []
2889
+ */
2890
+ routes?: Routes;
2891
+ /** Shell settings over the test defaults (`swipeBack: false`, `hapticsOnTabChange: false`). */
2892
+ config?: Partial<BfShellConfig>;
2893
+ }
2894
+ /**
2895
+ * Test providers for an app on the mobile shell: `provideRouter(routes ?? [],
2896
+ * withComponentInputBinding(), withBfShellRouting())` plus `provideBfShell({ swipeBack: false,
2897
+ * hapticsOnTabChange: false, ...config })`, an in-memory `BF_THEME_STORAGE` (so a theme change
2898
+ * never reaches `localStorage`), and the same document cleanup as `provideBfTesting()` from
2899
+ * `@bitforgehq/ui/testing` on teardown (`dark` and `cdk-global-scrollblock` on `<html>`, `inert` on
2900
+ * body children, stray overlay panes). Like that cleanup, it needs TestBed's default
2901
+ * `teardown: { destroyAfterEach: true }`. Use it instead of the app's own shell providers in
2902
+ * `TestBed.configureTestingModule()`.
2903
+ *
2904
+ * @example
2905
+ * TestBed.configureTestingModule({
2906
+ * providers: [provideBfShellTesting({ routes: [{ path: 'inbox', component: InboxPage }] })],
2907
+ * });
2908
+ * @param options The routes and the shell settings.
2909
+ * @returns The environment providers for `TestBed.configureTestingModule()`.
2910
+ * @summary Test providers for the mobile shell: router, shell, in-memory theme and cleanup
2911
+ * @since 0.3.0
2912
+ */
2913
+ export declare function provideBfShellTesting(options?: BfShellTestingOptions): EnvironmentProviders;
2914
+ export { type BfActionSheetAction, type BfActionSheetActionRole, type BfActionSheetOptions, type BfAlertDialogButton, type BfAlertDialogButtonRole, type BfAlertDialogOptions, type BfBackAtRoot, type BfContentScrollEvent, type BfHapticsImpactStyle, type BfHapticsNotificationType, type BfKeyboardAssistBehavior, type BfKeyboardPhase, type BfModalOptions, type BfModalPresentation, type BfNavDirection, type BfNavTarget, type BfOverlayOptions, type BfOverlayPosition, type BfOverlayStackOptions, type BfOverlayTemplateContext, type BfPlatform, type BfRefresherRefreshEvent, type BfSheetAutoFocus, type BfSheetOptions, type BfShellConfig, type BfShellConfigMode, type BfShellDynamicType, type BfShellDynamicTypeLimit, type BfShellMode, type BfShellTestingOptions, type BfStackChange, type BfStackTransition, type BfStackTransitionEvent, type BfStackedOverlay, type BfTabContext, type BfTheme, type BfToastAction, type BfToastDismissReason, type BfToastOptions, type BfToastPosition, BfToastRef, type BfTransitionKind, type BfViewEvent, type BfViewState, prefersReducedMotion };