@satinhq/kit 0.1.0-beta.2 → 0.1.0-beta.4

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 (309) hide show
  1. package/NOTICE +2 -2
  2. package/README.md +2 -3
  3. package/dist/acknowledgements/inventory.json +5 -5
  4. package/dist/actions/RowActions.d.ts +4 -4
  5. package/dist/actions/RowActions.js +93 -27
  6. package/dist/actions/fullSwipeContact.d.ts +73 -0
  7. package/dist/actions/fullSwipeContact.js +186 -0
  8. package/dist/actions/rowScrub.d.ts +7 -4
  9. package/dist/actions/rowScrub.js +39 -37
  10. package/dist/actions/types.d.ts +13 -7
  11. package/dist/app/InstallComponents.d.ts +4 -7
  12. package/dist/app/InstallComponents.js +7 -7
  13. package/dist/app/InstallationDiagnostics.d.ts +2 -1
  14. package/dist/app/InstallationDiagnostics.js +2 -1
  15. package/dist/app/appearance.d.ts +5 -3
  16. package/dist/app/appearance.js +5 -3
  17. package/dist/app/appearanceStore.d.ts +3 -2
  18. package/dist/app/buildInfo.d.ts +4 -4
  19. package/dist/app/buildInfo.js +2 -2
  20. package/dist/app/definition.d.ts +11 -3
  21. package/dist/app/definition.js +2 -0
  22. package/dist/app/head.d.ts +2 -1
  23. package/dist/app/head.js +13 -16
  24. package/dist/app/inlineCSP.d.ts +6 -0
  25. package/dist/app/inlineCSP.js +25 -0
  26. package/dist/app/install.d.ts +1 -0
  27. package/dist/app/install.js +5 -2
  28. package/dist/app/installCheck.js +32 -86
  29. package/dist/app/installContext.d.ts +10 -5
  30. package/dist/app/installContext.js +2 -0
  31. package/dist/app/installCustom.js +1 -0
  32. package/dist/app/installExperience.js +0 -60
  33. package/dist/app/installationFailure.d.ts +3 -2
  34. package/dist/app/installationFailure.js +1 -1
  35. package/dist/app/launchScreen.d.ts +6 -2
  36. package/dist/app/launchScreen.js +104 -1
  37. package/dist/app/launchScreenRuntime.d.ts +31 -4
  38. package/dist/app/launchScreenRuntime.js +150 -22
  39. package/dist/app/launchWatchdog.js +25 -65
  40. package/dist/app/platformScripts.js +11 -0
  41. package/dist/app/styles.d.ts +3 -0
  42. package/dist/app/styles.js +42 -0
  43. package/dist/app/viewportValue.d.ts +2 -1
  44. package/dist/app/vite.d.ts +4 -0
  45. package/dist/app/vite.js +22 -24
  46. package/dist/content/content.d.ts +35 -30
  47. package/dist/content/content.js +19 -16
  48. package/dist/content/layout.d.ts +10 -2
  49. package/dist/content/layout.js +4 -2
  50. package/dist/content/scaledMetric.d.ts +2 -1
  51. package/dist/content/scaledMetric.js +2 -1
  52. package/dist/controls/ColorPicker.d.ts +2 -4
  53. package/dist/controls/ColorPicker.js +2 -4
  54. package/dist/controls/DatePicker.d.ts +4 -4
  55. package/dist/controls/DatePicker.js +2 -2
  56. package/dist/controls/ProgressView.d.ts +4 -4
  57. package/dist/controls/ProgressView.js +1 -2
  58. package/dist/controls/civilDate.d.ts +1 -1
  59. package/dist/controls/civilDate.js +1 -1
  60. package/dist/data/database.d.ts +9 -8
  61. package/dist/data/database.js +4 -4
  62. package/dist/docs/components/file-importer.md +1 -1
  63. package/dist/docs/components/paste-button.md +1 -1
  64. package/dist/docs/components/photos-picker.md +1 -1
  65. package/dist/docs/components/share-link.md +1 -1
  66. package/dist/docs/limitations.md +1 -1
  67. package/dist/docs/push.md +3 -3
  68. package/dist/docs/reference.md +1888 -0
  69. package/dist/docs/tailwind.md +76 -0
  70. package/dist/docs/tokens.md +1 -1
  71. package/dist/gestures/GestureView.d.ts +3 -1
  72. package/dist/gestures/GestureView.js +2 -1
  73. package/dist/gestures/gesture.d.ts +22 -2
  74. package/dist/gestures/gesture.js +7 -2
  75. package/dist/glass/GlassEffect.d.ts +2 -1
  76. package/dist/glass/GlassEffect.js +2 -1
  77. package/dist/glass/GlassPresentation.d.ts +1 -0
  78. package/dist/glass/GlassPresentation.js +21 -4
  79. package/dist/glass/TabBar.js +23 -1
  80. package/dist/glass/errorAlert.js +2 -1
  81. package/dist/glass/errors.d.ts +3 -1
  82. package/dist/glass/fallback/runtime.d.ts +1 -0
  83. package/dist/glass/fallback/runtime.js +8 -1
  84. package/dist/glass/lens/controlLift.d.ts +1 -1
  85. package/dist/glass/lens/controlLift.js +1 -1
  86. package/dist/glass/lens/interactivePress.d.ts +2 -2
  87. package/dist/glass/lens/interactivePress.js +2 -2
  88. package/dist/glass/lens/menu-opening-native-fits.json +1 -1
  89. package/dist/glass/lens/menuContextFit.json +1 -1
  90. package/dist/glass/lens/menuDropFit.json +1 -1
  91. package/dist/glass/lens/menuField.d.ts +2 -2
  92. package/dist/glass/lens/menuField.js +3 -3
  93. package/dist/glass/lens/menuGlyphDropFit.json +1 -1
  94. package/dist/glass/lens/menuMorphFit.json +1 -1
  95. package/dist/glass/lens/menuMorphPhoneFit.json +1 -1
  96. package/dist/glass/lens/tabAccessoryMotion.d.ts +1 -1
  97. package/dist/glass/lens/tabSearchMember.d.ts +1 -1
  98. package/dist/glass/lens/tabSearchMember.js +1 -1
  99. package/dist/glass/liquidContext.d.ts +2 -0
  100. package/dist/glass/menuPresenter.d.ts +2 -0
  101. package/dist/glass/menuPresenter.js +1 -1
  102. package/dist/glass/regions.d.ts +3 -2
  103. package/dist/glass/regions.js +1 -1
  104. package/dist/glass/renderSpecs.d.ts +1 -0
  105. package/dist/glass/renderSpecs.js +1 -0
  106. package/dist/glass/shapeTrack.d.ts +1 -1
  107. package/dist/glass/submenuMotion.d.ts +1 -1
  108. package/dist/glass/submenuMotion.js +1 -1
  109. package/dist/glass/webgpu/controlRim.d.ts +29 -0
  110. package/dist/glass/webgpu/controlRim.js +68 -0
  111. package/dist/glass/webgpu/entry.worker.js +3 -6
  112. package/dist/glass/webgpu/frameClock.d.ts +6 -2
  113. package/dist/glass/webgpu/frameClock.js +9 -2
  114. package/dist/glass/webgpu/frameProbe.d.ts +1 -1
  115. package/dist/glass/webgpu/frameProbe.js +3 -3
  116. package/dist/glass/webgpu/passes.d.ts +2 -2
  117. package/dist/glass/webgpu/production.d.ts +1 -0
  118. package/dist/glass/webgpu/production.js +31 -1
  119. package/dist/glass/webgpu/raster.d.ts +18 -0
  120. package/dist/glass/webgpu/raster.js +105 -15
  121. package/dist/glass/webgpu/rasterMaterial.d.ts +4 -0
  122. package/dist/glass/webgpu/rasterMaterial.js +17 -1
  123. package/dist/glass/webgpu/rasterUniforms.js +9 -0
  124. package/dist/glass/webgpu/regionScene.d.ts +4 -1
  125. package/dist/glass/webgpu/regionScene.js +30 -1
  126. package/dist/glass/webgpu/renderer.js +23 -7
  127. package/dist/glass/webgpu/shaders.d.ts +2 -2
  128. package/dist/glass/webgpu/shaders.js +5 -1
  129. package/dist/haptics/SensoryButton.d.ts +4 -4
  130. package/dist/haptics/SensoryButton.js +3 -3
  131. package/dist/image/Image.d.ts +6 -3
  132. package/dist/image/Image.js +4 -3
  133. package/dist/image/asset.d.ts +2 -1
  134. package/dist/keyboard/adapter.d.ts +3 -4
  135. package/dist/keyboard/adapter.js +2 -2
  136. package/dist/keyboard/avoidance.d.ts +1 -1
  137. package/dist/keyboard/avoidance.js +1 -1
  138. package/dist/keyboard/geometry.d.ts +1 -1
  139. package/dist/keyboard/motion.d.ts +1 -1
  140. package/dist/keyboard/motion.js +1 -1
  141. package/dist/list-form/ListForm.d.ts +10 -9
  142. package/dist/list-form/ListForm.js +3 -3
  143. package/dist/list-form/ListItem.js +1 -1
  144. package/dist/list-form/RowLabel.d.ts +1 -1
  145. package/dist/list-form/RowLabel.js +1 -1
  146. package/dist/list-form/Slider.js +1 -1
  147. package/dist/list-form/editMotion.js +1 -1
  148. package/dist/list-form/editing.d.ts +10 -11
  149. package/dist/list-form/editing.js +5 -6
  150. package/dist/list-form/offsets.d.ts +2 -2
  151. package/dist/list-form/offsets.js +2 -2
  152. package/dist/media/react.d.ts +2 -1
  153. package/dist/media/react.js +2 -1
  154. package/dist/media/types.d.ts +6 -3
  155. package/dist/motion/TransitionView.d.ts +4 -2
  156. package/dist/motion/TransitionView.js +3 -2
  157. package/dist/motion/animationValue.d.ts +2 -2
  158. package/dist/motion/animationValue.js +9 -10
  159. package/dist/motion/matchedGeometry.d.ts +10 -9
  160. package/dist/motion/matchedGeometry.js +9 -9
  161. package/dist/motion/springTrack.d.ts +1 -2
  162. package/dist/motion/springTrack.js +10 -5
  163. package/dist/motion/transition.d.ts +4 -1
  164. package/dist/motion/transition.js +2 -0
  165. package/dist/navigation/DetailList.d.ts +1 -1
  166. package/dist/navigation/DetailList.js +1 -1
  167. package/dist/navigation/ScreenContainer.js +1 -1
  168. package/dist/navigation/Sidebar.d.ts +3 -1
  169. package/dist/navigation/Sidebar.js +1 -1
  170. package/dist/navigation/SidebarSymbol.d.ts +2 -1
  171. package/dist/navigation/SidebarSymbol.js +2 -1
  172. package/dist/navigation/chromeCurves.js +1 -1
  173. package/dist/navigation/navigationContext.d.ts +2 -1
  174. package/dist/navigation/navigationContext.js +2 -1
  175. package/dist/navigation/splitContext.d.ts +2 -1
  176. package/dist/navigation/splitContext.js +2 -1
  177. package/dist/navigation/toolbarMinimization.d.ts +4 -3
  178. package/dist/navigation/types.d.ts +8 -6
  179. package/dist/navigation/zoomGeometry.js +1 -1
  180. package/dist/navigation/zoomMotion.d.ts +1 -1
  181. package/dist/navigation/zoomMotion.js +2 -2
  182. package/dist/navigation/zoomTransition.js +3 -4
  183. package/dist/presentation/Presentation.d.ts +10 -9
  184. package/dist/presentation/Presentation.js +4 -3
  185. package/dist/presentation/model.d.ts +2 -1
  186. package/dist/presentation/presentationSource.js +1 -1
  187. package/dist/press/Pressable.d.ts +5 -1
  188. package/dist/press/Pressable.js +2 -0
  189. package/dist/press/stateMachine.d.ts +1 -1
  190. package/dist/public/Label.d.ts +2 -1
  191. package/dist/public/Label.js +2 -1
  192. package/dist/public/Screen.d.ts +4 -6
  193. package/dist/public/actions.d.ts +2 -1
  194. package/dist/public/actions.js +2 -1
  195. package/dist/public/buttonBorderShape.d.ts +2 -1
  196. package/dist/public/colors.d.ts +7 -4
  197. package/dist/public/colors.js +3 -2
  198. package/dist/public/controlStyle.d.ts +17 -14
  199. package/dist/public/controls.d.ts +29 -28
  200. package/dist/public/controls.js +25 -24
  201. package/dist/public/deviceActions.d.ts +6 -4
  202. package/dist/public/deviceActions.js +4 -2
  203. package/dist/public/environment.d.ts +16 -13
  204. package/dist/public/environment.js +11 -9
  205. package/dist/public/filePickers.d.ts +6 -4
  206. package/dist/public/filePickers.js +3 -2
  207. package/dist/public/glass.d.ts +8 -6
  208. package/dist/public/glass.js +2 -2
  209. package/dist/public/glassValue.d.ts +3 -4
  210. package/dist/public/glassValue.js +3 -4
  211. package/dist/public/keyboard.d.ts +4 -1
  212. package/dist/public/keyboard.js +2 -1
  213. package/dist/public/navigationTransition.d.ts +6 -6
  214. package/dist/public/navigationTransition.js +3 -3
  215. package/dist/public/presentation.d.ts +8 -7
  216. package/dist/public/presentation.js +5 -5
  217. package/dist/public/runtime.d.ts +9 -8
  218. package/dist/public/runtime.js +7 -7
  219. package/dist/public/scroll.d.ts +6 -3
  220. package/dist/public/scroll.js +3 -1
  221. package/dist/public/structure.d.ts +2 -2
  222. package/dist/public/toolbar.d.ts +15 -11
  223. package/dist/public/toolbar.js +13 -8
  224. package/dist/reachability/model.d.ts +4 -3
  225. package/dist/reachability/react.d.ts +4 -1
  226. package/dist/reachability/react.js +2 -1
  227. package/dist/root/SatinRoot.d.ts +3 -3
  228. package/dist/root/SatinRoot.js +12 -36
  229. package/dist/root/mountSatin.d.ts +1 -1
  230. package/dist/root/mountSatin.js +26 -35
  231. package/dist/root/runtimeContext.d.ts +2 -1
  232. package/dist/root/runtimeContext.js +2 -1
  233. package/dist/safe-area/Overlay.d.ts +3 -2
  234. package/dist/safe-area/Overlay.js +2 -1
  235. package/dist/safe-area/SafeAreaInset.d.ts +11 -7
  236. package/dist/safe-area/SafeAreaInset.js +10 -9
  237. package/dist/safe-area/context.d.ts +3 -3
  238. package/dist/safe-area/context.js +1 -1
  239. package/dist/safe-area/displayCorners.d.ts +4 -2
  240. package/dist/safe-area/displayCorners.js +4 -2
  241. package/dist/safe-area/modifiers.d.ts +14 -10
  242. package/dist/safe-area/modifiers.js +10 -6
  243. package/dist/safe-area/useSafeAreaMetrics.js +2 -2
  244. package/dist/scroll/ScrollSurface.d.ts +5 -5
  245. package/dist/scroll/ScrollSurface.js +6 -2
  246. package/dist/scroll/ScrollTarget.d.ts +1 -1
  247. package/dist/scroll/ScrollTarget.js +1 -1
  248. package/dist/scroll/edgePolicy.d.ts +2 -2
  249. package/dist/scroll/position.d.ts +5 -3
  250. package/dist/scroll/position.js +1 -1
  251. package/dist/scroll/screenGeometry.d.ts +1 -1
  252. package/dist/scroll/screenGeometry.js +1 -1
  253. package/dist/scroll/types.d.ts +1 -1
  254. package/dist/search/PadSearchDrawer.d.ts +7 -0
  255. package/dist/search/PadSearchDrawer.js +8 -0
  256. package/dist/search/PadSearchPresentationContext.d.ts +6 -0
  257. package/dist/search/PadSearchPresentationContext.js +4 -0
  258. package/dist/search/SearchDrawer.d.ts +1 -1
  259. package/dist/search/SearchDrawer.js +7 -2
  260. package/dist/search/SearchSuggestionsPopover.d.ts +6 -0
  261. package/dist/search/SearchSuggestionsPopover.js +42 -0
  262. package/dist/search/SearchToolbarField.d.ts +2 -1
  263. package/dist/search/SearchToolbarField.js +28 -7
  264. package/dist/search/padSearchBarMotion.d.ts +69 -0
  265. package/dist/search/padSearchBarMotion.js +73 -0
  266. package/dist/search/padSearchFieldSamples.json +491 -0
  267. package/dist/search/searchMotion.d.ts +1 -1
  268. package/dist/search/searchMotion.js +1 -1
  269. package/dist/search/searchPlacement.d.ts +3 -0
  270. package/dist/search/searchPlacement.js +7 -0
  271. package/dist/search/searchable.d.ts +14 -12
  272. package/dist/search/usePadSearchFieldMotion.d.ts +4 -0
  273. package/dist/search/usePadSearchFieldMotion.js +100 -0
  274. package/dist/search/useSearchPresentation.d.ts +2 -1
  275. package/dist/search/useSearchPresentation.js +24 -6
  276. package/dist/server.d.ts +4 -4
  277. package/dist/server.js +4 -4
  278. package/dist/shapes/corners.d.ts +3 -3
  279. package/dist/shapes/corners.js +2 -3
  280. package/dist/styles.css +8302 -8236
  281. package/dist/sw/vite.d.ts +4 -0
  282. package/dist/sw/vite.js +2 -0
  283. package/dist/symbols/Symbol.d.ts +7 -5
  284. package/dist/symbols/Symbol.js +5 -3
  285. package/dist/symbols/catalogue.d.ts +1 -1
  286. package/dist/symbols/types.d.ts +6 -4
  287. package/dist/tabs/TabSection.d.ts +3 -2
  288. package/dist/tabs/TabSection.js +2 -1
  289. package/dist/tabs/TabView.js +54 -51
  290. package/dist/tasks/useTask.d.ts +5 -4
  291. package/dist/tasks/useTask.js +4 -3
  292. package/dist/testing.d.ts +3 -2
  293. package/dist/testing.js +3 -2
  294. package/dist/text-input/TextEditor.js +7 -3
  295. package/dist/text-input/focusChain.d.ts +4 -3
  296. package/dist/text-input/focusChain.js +3 -2
  297. package/dist/text-input/kinds.d.ts +1 -1
  298. package/dist/web/WebView.d.ts +10 -3
  299. package/dist/web/WebView.js +3 -2
  300. package/dist/web/authentication.d.ts +12 -1
  301. package/dist/web/authentication.js +2 -1
  302. package/dist/web/openURL.d.ts +10 -4
  303. package/dist/web/openURL.js +4 -2
  304. package/dist/web/useWebAuthentication.d.ts +2 -1
  305. package/dist/web/useWebAuthentication.js +2 -1
  306. package/dist/zoom/Zoomable.d.ts +3 -3
  307. package/dist/zoom/Zoomable.js +2 -2
  308. package/package.json +4 -4
  309. package/dist/docs/swiftui-reference.md +0 -1895
@@ -1,8 +1,8 @@
1
1
  import { flushSync } from 'react-dom';
2
2
  import { createRoot } from 'react-dom/client';
3
- import { launchErrorLayer } from '../app/launchScreen.js';
3
+ import { prelaunchController, showLaunchFailure } from '../app/launchScreenRuntime.js';
4
4
  /** Mount once from the app entry point, after resolving its initial screen.
5
- * The first commit runs in this task so installed WebKit cannot defer it behind
5
+ * After managed styles load, the first commit runs synchronously so WebKit cannot defer it behind
6
6
  * its launch presentation. Later updates retain React's normal scheduling.
7
7
  * Do not call from a component or an effect, or suspend the initial screen.
8
8
  */
@@ -17,9 +17,29 @@ export function mountSatin(container, content, options) {
17
17
  reportError(error);
18
18
  },
19
19
  });
20
- performance.mark('satin-mount-start');
21
- flushSync(() => root.render(content));
22
- performance.mark('satin-mount-committed');
20
+ let disposed = false;
21
+ const unmount = root.unmount.bind(root);
22
+ root.unmount = () => {
23
+ disposed = true;
24
+ unmount();
25
+ };
26
+ const commit = () => {
27
+ if (disposed)
28
+ return;
29
+ performance.mark('satin-mount-start');
30
+ flushSync(() => root.render(content));
31
+ performance.mark('satin-mount-committed');
32
+ };
33
+ // A glass renderer cannot measure or present an unstyled React tree. The
34
+ // independent head environment owns this wait, including any load failure.
35
+ if (document.querySelector('link[data-satin-style]')) {
36
+ void prelaunchController().stylesReady().then(commit, error => {
37
+ if (!disposed)
38
+ showLaunchFailure(error instanceof Error ? error.message : String(error));
39
+ });
40
+ }
41
+ else
42
+ commit();
23
43
  return root;
24
44
  }
25
45
  /** An uncaught render or effect error unmounts the whole app. Without this the launch cover
@@ -27,34 +47,5 @@ export function mountSatin(container, content, options) {
27
47
  * above the launch cover, with the same presentation as a failed launch. */
28
48
  export function showAppFailure(error) {
29
49
  performance.mark('satin-app-failed');
30
- document.querySelector('[data-satin-app-failure]')?.remove();
31
- const panel = document.createElement('div');
32
- panel.dataset.satinRole = 'chrome';
33
- panel.dataset.satinLaunchError = 'true';
34
- panel.dataset.satinAppFailure = 'true';
35
- panel.setAttribute('role', 'alert');
36
- panel.style.zIndex = String(launchErrorLayer);
37
- const message = document.createElement('div');
38
- message.className = 'satin-launch-error-message';
39
- const title = document.createElement('h1');
40
- title.textContent = 'App Failed to Start';
41
- const detail = document.createElement('pre');
42
- detail.style.whiteSpace = 'pre-wrap';
43
- detail.style.overflowWrap = 'anywhere';
44
- detail.textContent = error instanceof Error ? error.message : String(error);
45
- const reload = document.createElement('button');
46
- reload.type = 'button';
47
- reload.textContent = 'Reload';
48
- reload.addEventListener('click', () => window.location.reload());
49
- message.append(title, detail, reload);
50
- const icon = document.querySelector('#satin-launch-screen .satin-launch-icon img');
51
- if (icon?.src) {
52
- const image = document.createElement('img');
53
- image.className = 'satin-launch-error-icon';
54
- image.src = icon.src;
55
- image.alt = '';
56
- panel.append(image);
57
- }
58
- panel.append(message);
59
- document.body.append(panel);
50
+ showLaunchFailure(error instanceof Error ? error.message : String(error), 'App Failed to Start');
60
51
  }
@@ -22,5 +22,6 @@ export declare function useSatinLayoutRuntime(): Omit<SatinRuntime, 'metrics'> &
22
22
  export declare function useSatinRuntime(): SatinRuntime;
23
23
  /** Classes follow the layout viewport; keyboard occlusion and zoom do not select panes. */
24
24
  export declare function useLayoutClass(): LayoutClass;
25
- /** Register app-managed unsaved state while it exists. Native inputs are checked automatically. */
25
+ /** Tells Satin the app has unsaved work while `unsaved` is true, so a pending app update waits
26
+ * instead of reloading over it. Edits in text fields are detected without this hook. */
26
27
  export declare function useUnsavedChanges(unsaved: boolean): void;
@@ -19,7 +19,8 @@ export function useSatinRuntime() {
19
19
  export function useLayoutClass() {
20
20
  return useSatinLayoutRuntime().layoutClass;
21
21
  }
22
- /** Register app-managed unsaved state while it exists. Native inputs are checked automatically. */
22
+ /** Tells Satin the app has unsaved work while `unsaved` is true, so a pending app update waits
23
+ * instead of reloading over it. Edits in text fields are detected without this hook. */
23
24
  export function useUnsavedChanges(unsaved) {
24
25
  const { registerUnsavedChanges } = useSatinLayoutRuntime();
25
26
  useEffect(() => {
@@ -1,9 +1,10 @@
1
1
  import { type HTMLAttributes, type ReactNode } from 'react';
2
2
  import type { ContentAlignment } from '../content/content.js';
3
- /** `overlay(alignment:content:)`: children determine the frame; content respects its safe area. */
3
+ /** The layered `content` and its alignment. The children set the frame. */
4
4
  export type OverlayProps = Omit<HTMLAttributes<HTMLDivElement>, 'content'> & Readonly<{
5
5
  alignment?: ContentAlignment;
6
6
  content: ReactNode;
7
7
  }>;
8
- /** An overlay in SafeAreaInset shares its reduced safe area and keyboard carrier with the composer. */
8
+ /** Layers `content` over its children without changing their frame. Inside a `SafeAreaInset`, the
9
+ * overlay keeps to the reduced safe area and moves with the keyboard, like the composer. */
9
10
  export declare function Overlay({ alignment, content, children, ...props }: OverlayProps): import("react").JSX.Element;
@@ -4,7 +4,8 @@ import { BottomInsetContext } from './SafeAreaInset.js';
4
4
  // Overlay content is already inside the parent's reduced safe area. Its descendants consume
5
5
  // only their own local insets and inherit the parent's keyboard transform.
6
6
  const CONTENT_SCOPE = { consumed: true };
7
- /** An overlay in SafeAreaInset shares its reduced safe area and keyboard carrier with the composer. */
7
+ /** Layers `content` over its children without changing their frame. Inside a `SafeAreaInset`, the
8
+ * overlay keeps to the reduced safe area and moves with the keyboard, like the composer. */
8
9
  export function Overlay({ alignment = 'center', content, children, ...props }) {
9
10
  const { geometry, consumed } = useContext(BottomInsetContext);
10
11
  const layer = useRef(null);
@@ -5,21 +5,25 @@ export declare const BottomInsetContext: import("react").Context<{
5
5
  consumed: boolean;
6
6
  geometry?: ReturnType<typeof createBottomInsetGeometry>;
7
7
  }>;
8
- /** `VerticalEdge`/`HorizontalEdge`: `leading` and `trailing` follow the layout direction. */
8
+ /** The edge a `SafeAreaInset` accessory sits on. `leading` and `trailing` follow the layout
9
+ * direction. */
9
10
  export type SafeAreaInsetEdge = 'top' | 'bottom' | 'leading' | 'trailing';
10
11
  /** The edge, the accessory (`content`) and its spacing; `children` is the content it insets. */
11
12
  export type SafeAreaInsetProps = Omit<HTMLAttributes<HTMLDivElement>, 'content'> & Readonly<{
12
13
  edge: SafeAreaInsetEdge;
13
14
  content: ReactNode;
15
+ /** Room between the content and the accessory, in points. Defaults to the system spacing,
16
+ * 8 pt. */
14
17
  spacing?: number;
15
18
  }>;
16
19
  /**
17
- * `safeAreaInset(edge:spacing:content:)`. The accessory takes room from the content's safe
18
- * area on its edge; a scroll view inside still spans the whole frame and scrolls under it.
20
+ * Pins an accessory, such as a composer or a filter bar, to one edge of its content. The
21
+ * accessory takes room from the content's safe area on its edge; a scroll view inside still
22
+ * spans the whole frame and scrolls under it.
19
23
  *
20
- * Bottom: content can scroll under the accessory; its terminal anchor clears it.
21
- * The accessory's height reaches the content's scroll inset in the same frame it changes (CSS
22
- * `--satin-inset-accessory-height`, written by its resize observer), so a composer that grows by
23
- * a line keeps the newest message above it with no frame between.
24
+ * At the bottom, content scrolls under the accessory and its last item stays clear of it. When
25
+ * the accessory resizes, the scroll inset changes in the same frame (through
26
+ * `--satin-inset-accessory-height`), so a composer that grows by a line keeps the newest message
27
+ * in view.
24
28
  */
25
29
  export declare function SafeAreaInset({ edge, content, spacing, children, ...props }: SafeAreaInsetProps): import("react").JSX.Element;
@@ -6,17 +6,18 @@ import { IgnoresSafeAreaContext } from './context.js';
6
6
  import { createContext, useContext, useLayoutEffect, useRef, useMemo, useCallback, } from 'react';
7
7
  /** Whether an enclosing SafeAreaInset already owns the bottom boundary (keyboard, home indicator). */
8
8
  export const BottomInsetContext = createContext({ consumed: false });
9
- /** SwiftUI's system spacing between content and a safe-area inset (`spacing: nil`). */
9
+ /** Default spacing between content and a safe-area inset. */
10
10
  const SYSTEM_INSET_SPACING_PX = 8;
11
11
  const ACCESSORY_INSET_SCOPE = { consumed: true };
12
12
  /**
13
- * `safeAreaInset(edge:spacing:content:)`. The accessory takes room from the content's safe
14
- * area on its edge; a scroll view inside still spans the whole frame and scrolls under it.
13
+ * Pins an accessory, such as a composer or a filter bar, to one edge of its content. The
14
+ * accessory takes room from the content's safe area on its edge; a scroll view inside still
15
+ * spans the whole frame and scrolls under it.
15
16
  *
16
- * Bottom: content can scroll under the accessory; its terminal anchor clears it.
17
- * The accessory's height reaches the content's scroll inset in the same frame it changes (CSS
18
- * `--satin-inset-accessory-height`, written by its resize observer), so a composer that grows by
19
- * a line keeps the newest message above it with no frame between.
17
+ * At the bottom, content scrolls under the accessory and its last item stays clear of it. When
18
+ * the accessory resizes, the scroll inset changes in the same frame (through
19
+ * `--satin-inset-accessory-height`), so a composer that grows by a line keeps the newest message
20
+ * in view.
20
21
  */
21
22
  export function SafeAreaInset({ edge, content, spacing = SYSTEM_INSET_SPACING_PX, children, ...props }) {
22
23
  if (edge !== 'bottom')
@@ -41,7 +42,7 @@ function BottomInset({ content, spacing, children, ...props }) {
41
42
  geometry.publish((parent.geometry?.value ?? 0) + measuredHeight.current + spacing + extension);
42
43
  }, [geometry, parent.geometry, spacing]);
43
44
  // `IgnoresSafeArea regions="keyboard"` around the inset: the boundary stays above the home
44
- // indicator while the keyboard is up, as SwiftUI's `ignoresSafeArea(.keyboard)`.
45
+ // indicator while the keyboard is up `ignoresSafeArea(.keyboard)`.
45
46
  const keyboardIgnored = useContext(IgnoresSafeAreaContext).keyboard;
46
47
  const inset = useRef(null);
47
48
  const accessory = useRef(null);
@@ -112,7 +113,7 @@ function BottomInset({ content, spacing, children, ...props }) {
112
113
  * native adds it to the scroll view's adjusted inset (iOS 27 native reference `inset-top`: 116 + 44.33 + 8);
113
114
  * - leading/trailing: the accessory is a column of the safe area's height and the content's frame
114
115
  * gives up its width plus `spacing` (`inset-leading`: strip 0–60, cards from 68).
115
- * A background drawn by the accessory's root view reaches the screen's top edge, as a SwiftUI
116
+ * A background drawn by the accessory's root view reaches the screen's top edge. An accessory
116
117
  * `background` ignores the safe area by default (`inset-top`: the yellow fills 0–160.33).
117
118
  */
118
119
  function EdgeInset({ edge, content, spacing, children, ...props }) {
@@ -1,12 +1,12 @@
1
- /** `Edge`. `leading` and `trailing` follow the layout direction. */
1
+ /** A logical edge. `leading` and `trailing` follow the layout direction. */
2
2
  export type Edge = 'top' | 'bottom' | 'leading' | 'trailing';
3
- /** `EdgeInsets` in points, by layout direction. */
3
+ /** Optional lengths per logical edge, in points. */
4
4
  export type EdgeLengths = Readonly<Partial<Record<Edge, number>>>;
5
5
  export type Lengths = Readonly<Record<Edge, number>>;
6
6
  export declare const NO_LENGTHS: Lengths;
7
7
  /** Safe-area padding the enclosing modifiers add to the next scroll view's content, per edge. */
8
8
  export declare const SafeAreaPaddingContext: import("react").Context<Readonly<Record<Edge, number>>>;
9
- /** `contentMargins(for: .scrollContent)` in effect for every scroll view below, per edge. */
9
+ /** The content margins in effect for every scroll view below, per edge. */
10
10
  export declare const ContentMarginsContext: import("react").Context<Readonly<Partial<Record<Edge, number>>>>;
11
11
  /** The safe-area regions and edges an enclosing `IgnoresSafeArea` gives up. */
12
12
  export declare const IgnoresSafeAreaContext: import("react").Context<{
@@ -2,7 +2,7 @@ import { createContext } from 'react';
2
2
  export const NO_LENGTHS = { top: 0, bottom: 0, leading: 0, trailing: 0 };
3
3
  /** Safe-area padding the enclosing modifiers add to the next scroll view's content, per edge. */
4
4
  export const SafeAreaPaddingContext = createContext(NO_LENGTHS);
5
- /** `contentMargins(for: .scrollContent)` in effect for every scroll view below, per edge. */
5
+ /** The content margins in effect for every scroll view below, per edge. */
6
6
  export const ContentMarginsContext = createContext({});
7
7
  /** The safe-area regions and edges an enclosing `IgnoresSafeArea` gives up. */
8
8
  export const IgnoresSafeAreaContext = createContext({ container: new Set(), keyboard: false });
@@ -15,7 +15,9 @@ export type DisplayCornerMetrics = Readonly<{
15
15
  export declare function resolveDisplayCornerMetrics(display: DisplayGeometry): DisplayCornerMetrics;
16
16
  /** Framework token for the screen containing this app. Display Zoom and unknown models fall back to zero. */
17
17
  export declare function readDisplayCornerMetrics(): DisplayCornerMetrics;
18
- /** Updates after rotation, window moves and DPR changes announced by a resize. */
18
+ /** The corner radius of the device screen in points, or 0 when the model is unknown. It updates
19
+ * after rotation, window moves and pixel-ratio changes that fire a resize. */
19
20
  export declare function useDisplayCornerRadius(): number;
20
- /** Radius for a shape inset equally from a rounded container. Insets consume, never invert, corners. */
21
+ /** The corner radius for a shape inset evenly inside a rounded container, so the two corners stay
22
+ * concentric. The result never goes below 0; a negative or non-finite argument throws. */
21
23
  export declare function concentricRadius(containerRadius: number, inset: number): number;
@@ -44,7 +44,8 @@ export function readDisplayCornerMetrics() {
44
44
  scale: window.devicePixelRatio,
45
45
  });
46
46
  }
47
- /** Updates after rotation, window moves and DPR changes announced by a resize. */
47
+ /** The corner radius of the device screen in points, or 0 when the model is unknown. It updates
48
+ * after rotation, window moves and pixel-ratio changes that fire a resize. */
48
49
  export function useDisplayCornerRadius() {
49
50
  const [radius, setRadius] = useState(() => readDisplayCornerMetrics().radius);
50
51
  useLayoutEffect(() => {
@@ -59,7 +60,8 @@ export function useDisplayCornerRadius() {
59
60
  }, []);
60
61
  return radius;
61
62
  }
62
- /** Radius for a shape inset equally from a rounded container. Insets consume, never invert, corners. */
63
+ /** The corner radius for a shape inset evenly inside a rounded container, so the two corners stay
64
+ * concentric. The result never goes below 0; a negative or non-finite argument throws. */
63
65
  export function concentricRadius(containerRadius, inset) {
64
66
  if (!Number.isFinite(containerRadius) ||
65
67
  containerRadius < 0 ||
@@ -4,22 +4,23 @@ import { type HTMLAttributes, type ReactNode } from 'react';
4
4
  export type { Edge, EdgeLengths } from './context.js';
5
5
  /** A logical edge, an axis pair or all edges. */
6
6
  export type EdgeSetMember = Edge | 'horizontal' | 'vertical' | 'all';
7
- /** `Edge.Set`: one member or several. */
7
+ /** One edge group or a list of them. */
8
8
  export type EdgeSet = EdgeSetMember | readonly EdgeSetMember[];
9
- /** The content and standard DOM attributes of a layout modifier wrapper. */
9
+ /** The children and plain div attributes every layout wrapper takes. */
10
10
  export type LayoutModifierProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & Readonly<{
11
11
  children?: ReactNode;
12
12
  }>;
13
13
  /** Which edges to pad, and by how much. */
14
14
  export type SafeAreaPaddingProps = LayoutModifierProps & Readonly<{
15
- /** Edges to pad. Defaults to all edges, as `safeAreaPadding()`. */
15
+ /** Edges to pad. Defaults to all edges. */
16
16
  edges?: EdgeSet;
17
17
  /** Points. Defaults to the system padding, 16 pt. */
18
18
  length?: number;
19
- /** `safeAreaPadding(_ insets: EdgeInsets)`; overrides `edges` and `length`. */
19
+ /** A length per edge. Overrides `edges` and `length`. */
20
20
  insets?: EdgeLengths;
21
21
  }>;
22
- /** Adds to the content safe area. Scroll views keep their frame and inset content; other content is padded. Nested padding adds up. */
22
+ /** Grows the safe area of the content inside it. Scroll views keep their frame and inset their
23
+ * content; other content is padded. Nested padding adds up. */
23
24
  export declare function SafeAreaPadding({ edges, length, insets, children, ...props }: SafeAreaPaddingProps): import("react").JSX.Element;
24
25
  /** Which edges get a margin, how much, and whether it applies to content or indicators. */
25
26
  export type ContentMarginsProps = LayoutModifierProps & Readonly<{
@@ -27,26 +28,29 @@ export type ContentMarginsProps = LayoutModifierProps & Readonly<{
27
28
  /** Points. */
28
29
  length: number;
29
30
  /**
30
- * `ContentMarginPlacement`. `scrollContent` (and `automatic`) margins the content;
31
+ * What the margin applies to. `scrollContent` (and `automatic`) margins the content;
31
32
  * `scrollIndicators` only moves the indicator, which Satin draws in the screen frame and does
32
33
  * not inset, so it has no effect yet.
33
34
  */
34
35
  placement?: 'automatic' | 'scrollContent' | 'scrollIndicators';
35
36
  }>;
36
- /** Sets margins for descendant scroll views. Lists use horizontal layout margins; the innermost value for each edge wins. */
37
+ /** Sets content margins for every scroll view inside it. A `List` takes a horizontal margin as its
38
+ * layout margin. The innermost value for each edge wins. */
37
39
  export declare function ContentMargins({ edges, length, placement, children, ...props }: ContentMarginsProps): import("react").JSX.Element;
38
40
  /** A `SafeAreaInset` limited to the top or bottom edge, with no spacing. */
39
41
  export type SafeAreaBarProps = Omit<SafeAreaInsetProps, 'edge' | 'spacing'> & Readonly<{
40
42
  edge: 'top' | 'bottom';
41
43
  }>;
42
- /** Places a top or bottom safe-area inset with no spacing and its own scroll-edge material. */
44
+ /** A bar on the top or bottom edge that content scrolls under. It is a `SafeAreaInset` with no
45
+ * spacing and its own scroll-edge blur. */
43
46
  export declare function SafeAreaBar({ edge, ...props }: SafeAreaBarProps): import("react").JSX.Element;
44
47
  /** Which safe-area regions and edges the content ignores. */
45
48
  export type IgnoresSafeAreaProps = LayoutModifierProps & Readonly<{
46
- /** `SafeAreaRegions`. Defaults to `'all'`. */
49
+ /** `container` (the bars and screen edges), `keyboard`, or `all`, the default. */
47
50
  regions?: 'all' | 'container' | 'keyboard';
48
51
  /** Defaults to all edges. */
49
52
  edges?: EdgeSet;
50
53
  }>;
51
- /** Extends content through selected safe-area edges. Container edges and keyboard avoidance can be controlled independently. */
54
+ /** Lets content extend through the safe area on the chosen edges, for full-bleed backgrounds and
55
+ * media. The container edges and keyboard avoidance can be ignored separately. */
52
56
  export declare function IgnoresSafeArea({ regions, edges, children, ...props }: IgnoresSafeAreaProps): import("react").JSX.Element;
@@ -3,7 +3,7 @@ import { startsScreenContent } from '../scroll/screenGeometry.js';
3
3
  import { SafeAreaInset } from './SafeAreaInset.js';
4
4
  import { ContentMarginsContext, IgnoresSafeAreaContext, NO_LENGTHS, SafeAreaPaddingContext, } from './context.js';
5
5
  import { useContext, useLayoutEffect, useRef } from 'react';
6
- /** SwiftUI's default padding amount (`padding()` and `safeAreaPadding()` with no length). */
6
+ /** Default padding used when no length is supplied. */
7
7
  const SYSTEM_PADDING_PX = 16;
8
8
  function edgesOf(set) {
9
9
  const edges = new Set();
@@ -29,7 +29,8 @@ function lengthsOf(edges, length, insets) {
29
29
  trailing: set.has('trailing') ? amount : 0,
30
30
  };
31
31
  }
32
- /** Adds to the content safe area. Scroll views keep their frame and inset content; other content is padded. Nested padding adds up. */
32
+ /** Grows the safe area of the content inside it. Scroll views keep their frame and inset their
33
+ * content; other content is padded. Nested padding adds up. */
33
34
  export function SafeAreaPadding({ edges, length, insets, children, ...props }) {
34
35
  const parent = useContext(SafeAreaPaddingContext);
35
36
  const own = lengthsOf(edges, length, insets);
@@ -47,7 +48,8 @@ export function SafeAreaPadding({ edges, length, insets, children, ...props }) {
47
48
  ['--satin-padding-trailing']: `${own.trailing}px`,
48
49
  }, "data-satin-safe-area-padding": "true", children: _jsx(SafeAreaPaddingContext, { value: total, children: children }) }));
49
50
  }
50
- /** Sets margins for descendant scroll views. Lists use horizontal layout margins; the innermost value for each edge wins. */
51
+ /** Sets content margins for every scroll view inside it. A `List` takes a horizontal margin as its
52
+ * layout margin. The innermost value for each edge wins. */
51
53
  export function ContentMargins({ edges = 'all', length, placement = 'automatic', children, ...props }) {
52
54
  const parent = useContext(ContentMarginsContext);
53
55
  const set = edgesOf(edges);
@@ -57,18 +59,20 @@ export function ContentMargins({ edges = 'all', length, placement = 'automatic',
57
59
  margins[edge] = length;
58
60
  return (_jsx("div", { ...props, "data-satin-content-margins": "true", children: _jsx(ContentMarginsContext, { value: margins, children: children }) }));
59
61
  }
60
- /** Places a top or bottom safe-area inset with no spacing and its own scroll-edge material. */
62
+ /** A bar on the top or bottom edge that content scrolls under. It is a `SafeAreaInset` with no
63
+ * spacing and its own scroll-edge blur. */
61
64
  export function SafeAreaBar({ edge, ...props }) {
62
65
  return _jsx(SafeAreaInset, { ...props, edge: edge, spacing: 0, "data-satin-safe-area-bar": edge });
63
66
  }
64
- /** Extends content through selected safe-area edges. Container edges and keyboard avoidance can be controlled independently. */
67
+ /** Lets content extend through the safe area on the chosen edges, for full-bleed backgrounds and
68
+ * media. The container edges and keyboard avoidance can be ignored separately. */
65
69
  export function IgnoresSafeArea({ regions = 'all', edges = 'all', children, ...props }) {
66
70
  const parent = useContext(IgnoresSafeAreaContext);
67
71
  const set = edgesOf(edges);
68
72
  const container = regions === 'keyboard' ? new Set() : set;
69
73
  const keyboard = regions !== 'container' && set.has('bottom');
70
74
  const element = useRef(null);
71
- // Only a view that reaches the safe edge extends past it, as SwiftUI's does.
75
+ // Only a view that reaches the safe edge extends past it.
72
76
  useLayoutEffect(() => {
73
77
  const node = element.current;
74
78
  if (!node)
@@ -60,7 +60,7 @@ function readInsets(element) {
60
60
  };
61
61
  }
62
62
  // Native home-indicator boundaries, in points. Phone: Foundation 00, iPhone 17 Pro Max,
63
- // iOS 27 portrait. Pad: a SwiftUI .safeAreaInset(edge: .bottom) composer on iPad Pro
63
+ // iOS 27 portrait. Pad: a .safeAreaInset(edge: .bottom) composer on iPad Pro
64
64
  // 12.9-inch, iPadOS 27, which keeps 25 pt in portrait and in landscape.
65
65
  const PHONE_HOME_INDICATOR_INSET = 34;
66
66
  const PAD_HOME_INDICATOR_INSET = 25;
@@ -72,7 +72,7 @@ const PAD_FITTED_STATUS_BAND = 32;
72
72
  * With viewport-fit auto/contain, the system takes the status band outside the viewport,
73
73
  * but content still reaches the screen bottom and every env() inset reads zero. Without
74
74
  * this boundary, bottom bars and composers sit in the home-indicator band: on iPad a
75
- * composer sat 25 pt lower than the same SwiftUI layout, its trailing edge in the corner
75
+ * composer sat 25 pt lower than the same layout, its trailing edge in the corner
76
76
  * that carries the window-resize grabber. Device identity comes from the shared
77
77
  * resolver, never from screen dimensions.
78
78
  */
@@ -28,15 +28,15 @@ export type ScrollSurfaceProps = Omit<HTMLAttributes<HTMLDivElement>, 'id'> & Sc
28
28
  /**
29
29
  * Whether this is the screen's primary scroll view, which gets the large title, the bar's
30
30
  * content inset and the scroll edge effect. By default the outermost vertical scroll view at the
31
- * top of the screen's content is primary, as in SwiftUI.
31
+ * top of the screen's content is primary.
32
32
  */
33
33
  primary?: boolean;
34
- /** SwiftUI `scrollEdgeEffectHidden(_:for: .top)`: no scroll edge effect under the bar. */
34
+ /** Hide the scroll edge effect under the top bar. */
35
35
  scrollEdgeEffectHidden?: ScrollEdgeEffectHidden;
36
36
  /** Soft/automatic select the existing top treatment. Hard is explicitly unsupported. */
37
37
  scrollEdgeEffectStyle?: ScrollEdgeEffectStyleSelection;
38
38
  }>;
39
- /** SwiftUI `ScrollView`: a named scroll surface whose position is retained by the framework. */
39
+ /** A named scroll surface whose position is retained by the framework. */
40
40
  export declare const ScrollSurface: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "id"> & Readonly<{
41
41
  defaultScrollAnchor?: 'top' | 'bottom';
42
42
  maintainVisibleContentPosition?: boolean;
@@ -52,10 +52,10 @@ export declare const ScrollSurface: import("react").ForwardRefExoticComponent<Om
52
52
  /**
53
53
  * Whether this is the screen's primary scroll view, which gets the large title, the bar's
54
54
  * content inset and the scroll edge effect. By default the outermost vertical scroll view at the
55
- * top of the screen's content is primary, as in SwiftUI.
55
+ * top of the screen's content is primary.
56
56
  */
57
57
  primary?: boolean;
58
- /** SwiftUI `scrollEdgeEffectHidden(_:for: .top)`: no scroll edge effect under the bar. */
58
+ /** Hide the scroll edge effect under the top bar. */
59
59
  scrollEdgeEffectHidden?: ScrollEdgeEffectHidden;
60
60
  /** Soft/automatic select the existing top treatment. Hard is explicitly unsupported. */
61
61
  scrollEdgeEffectStyle?: ScrollEdgeEffectStyleSelection;
@@ -15,9 +15,10 @@ import { TabActivityContext, TabRegistrationContext } from '../tabs/context.js';
15
15
  import { SearchDrawer } from '../search/SearchDrawer.js';
16
16
  import { ContentAdmission } from '../image/ContentAdmission.js';
17
17
  import { SearchToolbarField } from '../search/SearchToolbarField.js';
18
+ import { readDeviceIdiom } from '../layout/deviceIdiom.js';
18
19
  import { resolveSearchPlacement } from '../search/searchPlacement.js';
19
20
  import { Children, createContext, forwardRef, isValidElement, useCallback, useContext, useImperativeHandle, useLayoutEffect, useRef, useState, useSyncExternalStore, } from 'react';
20
- import { ScreenContext, SystemScrollRegistryContext, useScreenScrollRegistry, } from '../navigation/navigationContext.js';
21
+ import { NavigationPaneContext, ScreenContext, SystemScrollRegistryContext, useScreenScrollRegistry, } from '../navigation/navigationContext.js';
21
22
  import { readScrollOffset } from './registry.js';
22
23
  import { installScrollPressOwnership } from './pressOwnership.js';
23
24
  /** Inside another scroll surface: never the screen's primary scroll view. */
@@ -27,7 +28,7 @@ export const ListNavigationContext = createContext(undefined);
27
28
  /** A scroll view's content is inside its safe area: modifiers above it stop at its frame. */
28
29
  const NO_IGNORED = { container: new Set(), keyboard: false };
29
30
  const cssLength = (value) => typeof value === 'number' ? `${value}px` : (value ?? '0px');
30
- /** SwiftUI `ScrollView`: a named scroll surface whose position is retained by the framework. */
31
+ /** A named scroll surface whose position is retained by the framework. */
31
32
  export const ScrollSurface = forwardRef(function ScrollSurface({ axis = 'vertical', chain = false, children, primary, scrollEdgeEffectHidden, scrollEdgeEffectStyle, refreshable, scrollDismissesKeyboard = 'never', id, defaultScrollAnchor, maintainVisibleContentPosition, scrollPosition, onScrollGeometryChange, ...props }, forwardedRef) {
32
33
  const refresh = refreshable;
33
34
  if (axis !== 'vertical' &&
@@ -151,8 +152,11 @@ export const ScrollSurface = forwardRef(function ScrollSurface({ axis = 'vertica
151
152
  ? (listNavigation?.searchable ?? chrome.searchable)
152
153
  : undefined;
153
154
  const tabbed = useContext(TabRegistrationContext) !== null;
155
+ const searchPane = useContext(NavigationPaneContext);
154
156
  const searchPlacement = searchable
155
157
  ? resolveSearchPlacement(searchable.placement, {
158
+ idiom: readDeviceIdiom(),
159
+ pane: searchPane,
156
160
  compact: chrome.horizontalSizeClass === 'compact',
157
161
  bottomBarItems: chrome.hasBottomBar === true,
158
162
  searchToolbarItem: chrome.searchToolbarItem !== undefined,
@@ -1,6 +1,6 @@
1
1
  import { type HTMLAttributes } from 'react';
2
2
  export declare const ScrollTargetContext: import("react").Context<((id: string, element: HTMLDivElement | null) => void) | null>;
3
- /** A stable identity in a vertical ScrollView's normal-flow target layout. */
3
+ /** Marks content a vertical `ScrollView` can scroll to by `id`. */
4
4
  export declare function ScrollTarget({ id, ...props }: HTMLAttributes<HTMLDivElement> & {
5
5
  id: string;
6
6
  }): import("react").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useCallback, useContext } from 'react';
3
3
  export const ScrollTargetContext = createContext(null);
4
- /** A stable identity in a vertical ScrollView's normal-flow target layout. */
4
+ /** Marks content a vertical `ScrollView` can scroll to by `id`. */
5
5
  export function ScrollTarget({ id, ...props }) {
6
6
  const register = useContext(ScrollTargetContext);
7
7
  if (!register)
@@ -1,8 +1,8 @@
1
- /** `Edge`: a logical edge of a scroll view. */
1
+ /** A logical edge of a scroll view. */
2
2
  export type ScrollEdge = 'top' | 'bottom' | 'leading' | 'trailing';
3
3
  /** One or more scroll edges, or all edges. */
4
4
  export type ScrollEdgeSelection = ScrollEdge | 'all' | readonly ScrollEdge[];
5
- /** `ScrollEdgeEffectStyle`: the requested edge material treatment. */
5
+ /** The material under bars at a scroll view's edge: `soft`, `hard` or `automatic`. */
6
6
  export type ScrollEdgeEffectStyle = 'soft' | 'hard' | 'automatic';
7
7
  /** Whether to hide scroll edge material, optionally for specific edges. */
8
8
  export type ScrollEdgeEffectHidden = boolean | {
@@ -1,4 +1,4 @@
1
- /** `UnitPoint`: the vertical alignment of a scroll target. */
1
+ /** Where a scroll target lines up in the viewport: `top`, `center` or `bottom`. */
2
2
  export type ScrollAnchor = 'top' | 'center' | 'bottom';
3
3
  /** Vertical scroll geometry: the current viewport and content offset in points. */
4
4
  export type VerticalScrollGeometry = Readonly<{
@@ -7,13 +7,15 @@ export type VerticalScrollGeometry = Readonly<{
7
7
  containerHeight: number;
8
8
  distanceToBottom: number;
9
9
  }>;
10
- /** `ScrollPosition`: a target identity and the callback that receives its changes. */
10
+ /** A controlled scroll position: the id of the target in view, its anchor and the callback that
11
+ * receives changes. */
11
12
  export type ScrollPositionBinding = Readonly<{
12
13
  id: string | null;
13
14
  anchor?: ScrollAnchor;
14
15
  onChange(id: string | null): void;
15
16
  }>;
16
- /** A scroll target binding, anchor and geometry observation policy. */
17
+ /** The scroll view's position options: where it starts, whether it keeps visible content in
18
+ * place, a controlled position and a geometry callback. */
17
19
  export type ScrollPositionOptions = Readonly<{
18
20
  defaultScrollAnchor?: 'top' | 'bottom';
19
21
  maintainVisibleContentPosition?: boolean;
@@ -84,7 +84,7 @@ export function createScrollPositionController(surface, content, targets, option
84
84
  pending = undefined;
85
85
  const targetTop = top(target);
86
86
  const height = target.getBoundingClientRect().height;
87
- // Targets align within the content insets, as SwiftUI's do: a screen's primary scroll view
87
+ // Targets align within the content insets, within the owned scroll region: a screen's primary scroll view
88
88
  // reaches under the bar and the bottom bars, and its padding is the bar's and the bottom inset
89
89
  // chain's content inset. Other scroll views only clear the enclosing bottom insets' accessories.
90
90
  const style = getComputedStyle(surface);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Whether a scroll view starts its screen's content, as a SwiftUI scroll view that reaches the
2
+ * Whether a scroll view starts its screen's content, as a scroll view that reaches the
3
3
  * top safe-area edge does. Only such a scroll view extends under the navigation bar and takes the
4
4
  * bar's content inset; one placed below other content keeps its own frame, like a Form under a
5
5
  * header in a VStack.
@@ -11,7 +11,7 @@ function occupiesFlow(element) {
11
11
  return position !== 'absolute' && position !== 'fixed';
12
12
  }
13
13
  /**
14
- * Whether a scroll view starts its screen's content, as a SwiftUI scroll view that reaches the
14
+ * Whether a scroll view starts its screen's content, as a scroll view that reaches the
15
15
  * top safe-area edge does. Only such a scroll view extends under the navigation bar and takes the
16
16
  * bar's content inset; one placed below other content keeps its own frame, like a Form under a
17
17
  * header in a VStack.
@@ -6,7 +6,7 @@ export type ScrollOffset = Readonly<{
6
6
  y: number;
7
7
  }>;
8
8
  export type ScrollSnapshot = ReadonlyMap<string, ScrollOffset>;
9
- /** Options for restoring a named scroll surface to its top. */
9
+ /** Options for `scrollToTop`: whether to animate. */
10
10
  export type ScrollToTopOptions = Readonly<{
11
11
  animated?: boolean;
12
12
  }>;
@@ -0,0 +1,7 @@
1
+ import { type RefObject } from 'react';
2
+ import type { Searchable } from './searchable.js';
3
+ /** A column-owned field. Its host stays in this scroll surface, never a sibling pane. */
4
+ export declare function PadSearchDrawer({ configuration, scroller, }: {
5
+ configuration: Searchable;
6
+ scroller: RefObject<HTMLDivElement | null>;
7
+ }): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { SearchToolbarField } from './SearchToolbarField.js';
4
+ /** A column-owned field. Its host stays in this scroll surface, never a sibling pane. */
5
+ export function PadSearchDrawer({ configuration, scroller, }) {
6
+ const [host, setHost] = useState(null);
7
+ return (_jsx("div", { ref: setHost, "data-satin-search-pad-drawer": "", "data-satin-search-toolbar-host": "", children: host && (_jsx(SearchToolbarField, { configuration: configuration, scroller: scroller, host: host, navigation: true, drawer: true })) }));
8
+ }
@@ -0,0 +1,6 @@
1
+ /** Internal coordination between a retained search destination and its owning tab bar. */
2
+ export declare const PadSearchPresentationContext: import("react").Context<{
3
+ owner: string | null;
4
+ setOwner: (owner: string | null) => void;
5
+ } | null>;
6
+ export declare const PadSearchTabContext: import("react").Context<string | null>;
@@ -0,0 +1,4 @@
1
+ import { createContext } from 'react';
2
+ /** Internal coordination between a retained search destination and its owning tab bar. */
3
+ export const PadSearchPresentationContext = createContext(null);
4
+ export const PadSearchTabContext = createContext(null);