@octane-xplat/ui 0.4.0 → 0.6.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 (283) hide show
  1. package/README.md +3 -0
  2. package/dist/native/Absolute.native.tsrx.js +43 -0
  3. package/dist/native/Accordion.native.tsrx.js +75 -0
  4. package/dist/native/ActivityIndicator.native.tsrx.js +35 -0
  5. package/dist/native/Alert.native.tsrx.js +74 -0
  6. package/dist/native/Avatar.native.tsrx.js +76 -0
  7. package/dist/native/AvatarGroup.native.tsrx.js +84 -0
  8. package/dist/native/Badge.native.tsrx.js +29 -0
  9. package/dist/native/Banner.native.tsrx.js +80 -0
  10. package/dist/native/Breadcrumb.native.tsrx.js +66 -0
  11. package/dist/native/Button.native.tsrx.js +62 -0
  12. package/dist/native/CameraView.native.tsrx.js +165 -0
  13. package/dist/native/Card.native.tsrx.js +64 -0
  14. package/dist/native/Checkbox.native.tsrx.js +58 -0
  15. package/dist/native/CheckboxGroup.native.tsrx.js +70 -0
  16. package/dist/native/Chip.native.tsrx.js +83 -0
  17. package/dist/native/Collapsible.native.tsrx.js +74 -0
  18. package/dist/native/CommandPalette.native.tsrx.js +143 -0
  19. package/dist/native/ContextMenu.native.tsrx.js +140 -0
  20. package/dist/native/Drawer.native.tsrx.js +60 -0
  21. package/dist/native/DropdownMenu.native.tsrx.js +155 -0
  22. package/dist/native/Empty.native.tsrx.js +82 -0
  23. package/dist/native/FieldGroup.native.tsrx.js +39 -0
  24. package/dist/native/FormField.native.tsrx.js +53 -0
  25. package/dist/native/{ui8.js → Grid.native.tsrx.js} +19 -8
  26. package/dist/native/{ui56.js → Heading.native.tsrx.js} +2 -2
  27. package/dist/native/{ui55.js → Icon.native.tsrx.js} +4 -4
  28. package/dist/native/{ui29.js → Image.native.tsrx.js} +4 -4
  29. package/dist/native/InputNumber.native.tsrx.js +146 -0
  30. package/dist/native/InputRating.native.tsrx.js +74 -0
  31. package/dist/native/InputTags.native.tsrx.js +131 -0
  32. package/dist/native/Kbd.native.tsrx.js +29 -0
  33. package/dist/native/{ui48.js → KeyboardAvoiding.native.tsrx.js} +1 -1
  34. package/dist/native/{ui17.js → Link.native.tsrx.js} +1 -1
  35. package/dist/native/{ui52.js → Meter.native.tsrx.js} +2 -2
  36. package/dist/native/{ui22.js → NavLink.native.tsrx.js} +3 -3
  37. package/dist/native/NavigationMenu.native.tsrx.js +67 -0
  38. package/dist/native/{ui35.js → Overlay.native.tsrx.js} +3 -3
  39. package/dist/native/Pager.native.tsrx.js +282 -0
  40. package/dist/native/Pagination.native.tsrx.js +107 -0
  41. package/dist/native/PinInput.native.tsrx.js +94 -0
  42. package/dist/native/{ui38.js → Popover.native.tsrx.js} +5 -5
  43. package/dist/native/{ui16.js → Pressable.native.tsrx.js} +21 -15
  44. package/dist/native/ProgressGroup.native.tsrx.js +66 -0
  45. package/dist/native/RadioGroup.native.tsrx.js +85 -0
  46. package/dist/native/{ui15.js → RichText.native.tsrx.js} +15 -22
  47. package/dist/native/Row.native.tsrx.js +98 -0
  48. package/dist/native/{ui47.js → SafeArea.native.tsrx.js} +2 -2
  49. package/dist/native/{ui43.js → Screen.native.tsrx.js} +3 -3
  50. package/dist/native/{ui26.js → ScrollBox.native.tsrx.js} +1 -1
  51. package/dist/native/ScrollView.native.tsrx.js +233 -0
  52. package/dist/native/SearchInput.native.tsrx.js +151 -0
  53. package/dist/native/SegmentedControl.native.tsrx.js +75 -0
  54. package/dist/native/Select.native.tsrx.js +202 -0
  55. package/dist/native/Separator.native.tsrx.js +25 -0
  56. package/dist/native/{ui60.js → Sheet.native.tsrx.js} +15 -7
  57. package/dist/native/Skeleton.native.tsrx.js +28 -0
  58. package/dist/native/Slider.native.tsrx.js +98 -0
  59. package/dist/native/{ui13.js → Spacer.native.tsrx.js} +2 -2
  60. package/dist/native/{ui9.js → Stack.native.tsrx.js} +20 -9
  61. package/dist/native/Stepper.native.tsrx.js +75 -0
  62. package/dist/native/Switch.native.tsrx.js +33 -0
  63. package/dist/native/Table.native.tsrx.js +103 -0
  64. package/dist/native/Tabs.native.tsrx.js +163 -0
  65. package/dist/native/{ui14.js → Text.native.tsrx.js} +19 -3
  66. package/dist/native/{ui24.js → TextArea.native.tsrx.js} +19 -17
  67. package/dist/native/{ui23.js → TextInput.native.tsrx.js} +21 -16
  68. package/dist/native/Timeline.native.tsrx.js +112 -0
  69. package/dist/native/Tree.native.tsrx.js +140 -0
  70. package/dist/native/User.native.tsrx.js +95 -0
  71. package/dist/native/Video.native.tsrx.js +248 -0
  72. package/dist/native/{ui6.js → View.native.tsrx.js} +39 -25
  73. package/dist/native/WebView.native.tsrx.js +110 -0
  74. package/dist/native/aliases.native.tsrx.js +38 -0
  75. package/dist/native/android/BottomNavigationView.android.tsrx.js +171 -0
  76. package/dist/native/android/CircularProgressIndicator.android.tsrx.js +27 -0
  77. package/dist/native/{ui49.js → android/DrawerLayout.android.tsrx.js} +5 -7
  78. package/dist/native/android/MaterialDialog.android.tsrx.js +62 -0
  79. package/dist/native/android/MaterialSwitch.android.tsrx.js +28 -0
  80. package/dist/native/android/RecyclerView.android.tsrx.js +248 -0
  81. package/dist/native/android/SeekBar.android.tsrx.js +34 -0
  82. package/dist/native/android/index.js +9 -0
  83. package/dist/native/android/openModal.android.js +39 -0
  84. package/dist/native/camera-permission.native.js +47 -0
  85. package/dist/native/child-array.js +15 -0
  86. package/dist/native/{ui3.js → escape-props.native.js} +22 -1
  87. package/dist/native/icons.js +25 -0
  88. package/dist/native/{ui11.js → ios/LiquidGlass.ios.tsrx.js} +4 -4
  89. package/dist/native/{ui12.js → ios/LiquidGlassContainer.ios.tsrx.js} +4 -4
  90. package/dist/native/ios/SideDrawer.ios.tsrx.js +64 -0
  91. package/dist/native/{ui50.js → ios/UIActivityIndicatorView.ios.tsrx.js} +5 -5
  92. package/dist/native/{ui32.js → ios/UIModal.ios.tsrx.js} +10 -6
  93. package/dist/native/{ui53.js → ios/UISlider.ios.tsrx.js} +5 -5
  94. package/dist/native/{ui45.js → ios/UISwitch.ios.tsrx.js} +5 -5
  95. package/dist/native/ios/UITabBar.ios.tsrx.js +166 -0
  96. package/dist/native/ios/UITableView.ios.tsrx.js +270 -0
  97. package/dist/native/ios/index.js +11 -0
  98. package/dist/native/{ui33.js → ios/openModal.ios.js} +5 -4
  99. package/dist/native/modal-presenter.native.js +19 -0
  100. package/dist/native/native/index.js +4 -0
  101. package/dist/native/octane-client-build.json +1 -1
  102. package/dist/native/pan.native.tsrx.js +66 -0
  103. package/dist/native/platform.native.js +10 -0
  104. package/dist/native/refresh-metrics.js +9 -0
  105. package/dist/native/refresh.native.js +177 -0
  106. package/dist/native/{ui34.js → root-layout.native.js} +6 -1
  107. package/dist/native/{ui21.js → route.native.js} +96 -12
  108. package/dist/native/sheet-detents.native.js +102 -0
  109. package/dist/native/{ui61.js → sheet-service.native.js} +19 -9
  110. package/dist/native/sheet-snap.js +35 -0
  111. package/dist/native/text-write.native.js +27 -0
  112. package/dist/native/theme/status-bar-scheme.native.js +17 -0
  113. package/dist/{web/ui29.js → native/theme/theme-scheme.js} +2 -2
  114. package/dist/native/toast-anchor.native.tsrx.js +185 -0
  115. package/dist/native/translate.native.js +11 -0
  116. package/dist/native/ui.js +93 -52
  117. package/dist/native/use-back.native.tsrx.js +9 -0
  118. package/dist/native/useMeasure.native.tsrx.js +64 -0
  119. package/dist/native/video-chrome.native.tsrx.js +365 -0
  120. package/dist/web/Absolute.web.tsrx.js +47 -0
  121. package/dist/web/Accordion.web.tsrx.js +85 -0
  122. package/dist/web/{ui46.js → ActivityIndicator.web.tsrx.js} +1 -1
  123. package/dist/web/Alert.web.tsrx.js +79 -0
  124. package/dist/web/Avatar.web.tsrx.js +106 -0
  125. package/dist/web/AvatarGroup.web.tsrx.js +108 -0
  126. package/dist/web/Badge.web.tsrx.js +37 -0
  127. package/dist/web/Banner.web.tsrx.js +79 -0
  128. package/dist/web/Breadcrumb.web.tsrx.js +135 -0
  129. package/dist/web/Button.web.tsrx.js +45 -0
  130. package/dist/web/CameraView.web.tsrx.js +310 -0
  131. package/dist/web/Card.web.tsrx.js +73 -0
  132. package/dist/web/Checkbox.web.tsrx.js +89 -0
  133. package/dist/web/CheckboxGroup.web.tsrx.js +79 -0
  134. package/dist/web/Chip.web.tsrx.js +64 -0
  135. package/dist/web/Collapsible.web.tsrx.js +94 -0
  136. package/dist/web/CommandPalette.web.tsrx.js +125 -0
  137. package/dist/web/ContextMenu.web.tsrx.js +154 -0
  138. package/dist/web/{ui44.js → Drawer.web.tsrx.js} +13 -9
  139. package/dist/web/DropdownMenu.web.tsrx.js +162 -0
  140. package/dist/web/Empty.web.tsrx.js +89 -0
  141. package/dist/web/FieldGroup.web.tsrx.js +57 -0
  142. package/dist/web/FormField.web.tsrx.js +92 -0
  143. package/dist/web/Grid.web.tsrx.js +65 -0
  144. package/dist/web/{ui52.js → Heading.web.tsrx.js} +2 -2
  145. package/dist/web/Icon.web.tsrx.js +273 -0
  146. package/dist/web/{ui25.js → Image.web.tsrx.js} +2 -2
  147. package/dist/web/InputNumber.web.tsrx.js +99 -0
  148. package/dist/web/InputRating.web.tsrx.js +72 -0
  149. package/dist/web/InputTags.web.tsrx.js +122 -0
  150. package/dist/web/Kbd.web.tsrx.js +37 -0
  151. package/dist/web/{ui48.js → Meter.web.tsrx.js} +1 -1
  152. package/dist/web/{ui19.js → NavLink.web.tsrx.js} +1 -1
  153. package/dist/web/NavigationMenu.web.tsrx.js +118 -0
  154. package/dist/web/{ui31.js → Overlay.web.tsrx.js} +2 -2
  155. package/dist/web/Pager.web.tsrx.js +337 -0
  156. package/dist/web/Pagination.web.tsrx.js +80 -0
  157. package/dist/web/PinInput.web.tsrx.js +72 -0
  158. package/dist/web/{ui33.js → Popover.web.tsrx.js} +3 -3
  159. package/dist/web/{ui15.js → Pressable.web.tsrx.js} +68 -95
  160. package/dist/web/ProgressGroup.web.tsrx.js +109 -0
  161. package/dist/web/RadioGroup.web.tsrx.js +69 -0
  162. package/dist/web/{ui14.js → RichText.web.tsrx.js} +2 -2
  163. package/dist/web/Row.web.tsrx.js +250 -0
  164. package/dist/web/{ui42.js → SafeArea.web.tsrx.js} +1 -1
  165. package/dist/web/{ui38.js → Screen.web.tsrx.js} +1 -1
  166. package/dist/web/{ui24.js → ScrollBox.web.tsrx.js} +1 -1
  167. package/dist/web/ScrollView.web.tsrx.js +388 -0
  168. package/dist/web/SearchInput.web.tsrx.js +137 -0
  169. package/dist/web/SegmentedControl.web.tsrx.js +75 -0
  170. package/dist/web/Select.web.tsrx.js +149 -0
  171. package/dist/web/Separator.web.tsrx.js +42 -0
  172. package/dist/web/Sheet.web.tsrx.js +81 -0
  173. package/dist/web/Skeleton.web.tsrx.js +56 -0
  174. package/dist/web/Slider.web.tsrx.js +97 -0
  175. package/dist/web/{ui12.js → Spacer.web.tsrx.js} +1 -1
  176. package/dist/web/Stack.web.tsrx.js +47 -0
  177. package/dist/web/Stepper.web.tsrx.js +65 -0
  178. package/dist/web/Switch.web.tsrx.js +59 -0
  179. package/dist/web/Table.web.tsrx.js +161 -0
  180. package/dist/web/{ui39.js → Tabs.web.tsrx.js} +33 -16
  181. package/dist/web/{ui13.js → Text.web.tsrx.js} +79 -46
  182. package/dist/web/{ui21.js → TextArea.web.tsrx.js} +4 -4
  183. package/dist/web/{ui20.js → TextInput.web.tsrx.js} +8 -8
  184. package/dist/web/Timeline.web.tsrx.js +172 -0
  185. package/dist/web/Tree.web.tsrx.js +146 -0
  186. package/dist/web/User.web.tsrx.js +116 -0
  187. package/dist/web/Video.web.tsrx.js +400 -0
  188. package/dist/web/View.web.tsrx.js +250 -0
  189. package/dist/web/WebView.web.tsrx.js +235 -0
  190. package/dist/web/aliases.web.tsrx.js +24 -0
  191. package/dist/web/{ui35.js → anim.web.tsrx.js} +3 -2
  192. package/dist/web/child-array.js +15 -0
  193. package/dist/web/icons.js +25 -0
  194. package/dist/web/octane-client-build.json +1 -1
  195. package/dist/web/pan.web.tsrx.js +66 -0
  196. package/dist/web/platform.web.js +9 -0
  197. package/dist/web/refresh-metrics.js +9 -0
  198. package/dist/web/refresh.web.js +133 -0
  199. package/dist/web/{ui18.js → route.web.js} +14 -2
  200. package/dist/web/sheet-detents.web.js +103 -0
  201. package/dist/web/{ui58.js → sheet-service.web.js} +5 -1
  202. package/dist/web/sheet-snap.js +35 -0
  203. package/dist/{native/ui31.js → web/theme/theme-scheme.js} +2 -2
  204. package/dist/web/toast-anchor.web.tsrx.js +142 -0
  205. package/dist/web/transform.web.js +43 -0
  206. package/dist/web/translate.web.js +13 -0
  207. package/dist/web/ui.js +91 -51
  208. package/dist/web/use-back.web.tsrx.js +9 -0
  209. package/dist/web/useMeasure.web.tsrx.js +50 -0
  210. package/dist/web/video-chrome.web.tsrx.js +207 -0
  211. package/dist/web/web/Hoverable.web.tsrx.js +150 -0
  212. package/dist/web/web/Tooltip.web.tsrx.js +183 -0
  213. package/dist/web/web/index.js +3 -0
  214. package/package.json +34 -3
  215. package/src/theme/tokens.css +1599 -194
  216. package/types/android.d.ts +53 -0
  217. package/types/index.d.ts +39 -14
  218. package/types/index.native.d.ts +273 -0
  219. package/types/index.web.d.ts +272 -0
  220. package/types/ios.d.ts +59 -0
  221. package/types/native.d.ts +5 -0
  222. package/types/props.d.ts +989 -44
  223. package/types/web.d.ts +17 -0
  224. package/dist/native/ui10.js +0 -32
  225. package/dist/native/ui25.js +0 -141
  226. package/dist/native/ui27.js +0 -61
  227. package/dist/native/ui39.js +0 -105
  228. package/dist/native/ui4.js +0 -24
  229. package/dist/native/ui44.js +0 -267
  230. package/dist/native/ui54.js +0 -17
  231. package/dist/native/ui57.js +0 -14
  232. package/dist/native/ui7.js +0 -52
  233. package/dist/web/ui10.js +0 -46
  234. package/dist/web/ui11.js +0 -42
  235. package/dist/web/ui22.js +0 -108
  236. package/dist/web/ui23.js +0 -96
  237. package/dist/web/ui26.js +0 -45
  238. package/dist/web/ui3.js +0 -31
  239. package/dist/web/ui30.js +0 -34
  240. package/dist/web/ui34.js +0 -70
  241. package/dist/web/ui40.js +0 -43
  242. package/dist/web/ui43.js +0 -42
  243. package/dist/web/ui49.js +0 -47
  244. package/dist/web/ui5.js +0 -168
  245. package/dist/web/ui50.js +0 -17
  246. package/dist/web/ui51.js +0 -149
  247. package/dist/web/ui53.js +0 -17
  248. package/dist/web/ui57.js +0 -44
  249. package/dist/web/ui6.js +0 -94
  250. package/dist/web/ui7.js +0 -62
  251. package/dist/web/ui8.js +0 -46
  252. package/dist/web/ui9.js +0 -46
  253. /package/dist/native/{ui20.js → RouteHost.native.tsrx.js} +0 -0
  254. /package/dist/native/{ui40.js → anim.native.tsrx.js} +0 -0
  255. /package/dist/native/{ui2.js → cx.js} +0 -0
  256. /package/dist/native/{ui5.js → layout-child.native.js} +0 -0
  257. /package/dist/native/{ui51.js → meter-math.js} +0 -0
  258. /package/dist/native/{ui36.js → platformProps.native.js} +0 -0
  259. /package/dist/native/{ui37.js → popover-position.js} +0 -0
  260. /package/dist/native/{ui19.js → route-table.js} +0 -0
  261. /package/dist/native/{ui46.js → safeAreaInsets.native.tsrx.js} +0 -0
  262. /package/dist/native/{ui18.js → stacks.native.js} +0 -0
  263. /package/dist/native/{ui58.js → store.js} +0 -0
  264. /package/dist/native/{ui41.js → styled.native.tsrx.js} +0 -0
  265. /package/dist/native/{ui28.js → svg.native.js} +0 -0
  266. /package/dist/native/{ui30.js → theme/colorScheme.native.js} +0 -0
  267. /package/dist/native/{ui59.js → use-store.native.tsrx.js} +0 -0
  268. /package/dist/native/{ui42.js → windows.native.js} +0 -0
  269. /package/dist/web/{ui16.js → Link.web.tsrx.js} +0 -0
  270. /package/dist/web/{ui28.js → cx.js} +0 -0
  271. /package/dist/web/{ui2.js → escape-props.web.js} +0 -0
  272. /package/dist/web/{ui4.js → layout-child.web.js} +0 -0
  273. /package/dist/web/{ui47.js → meter-math.js} +0 -0
  274. /package/dist/web/{ui45.js → platformProps.web.js} +0 -0
  275. /package/dist/web/{ui32.js → popover-position.js} +0 -0
  276. /package/dist/web/{ui17.js → route-table.js} +0 -0
  277. /package/dist/web/{ui41.js → safeAreaInsets.web.tsrx.js} +0 -0
  278. /package/dist/web/{ui54.js → stacks.web.js} +0 -0
  279. /package/dist/web/{ui55.js → store.js} +0 -0
  280. /package/dist/web/{ui36.js → styled.web.tsrx.js} +0 -0
  281. /package/dist/web/{ui27.js → theme/colorScheme.web.js} +0 -0
  282. /package/dist/web/{ui56.js → use-store.web.tsrx.js} +0 -0
  283. /package/dist/web/{ui37.js → windows.web.js} +0 -0
@@ -0,0 +1,133 @@
1
+ import { setTranslate } from "./translate.web.js";
2
+ import { dampenPull } from "./refresh-metrics.js";
3
+ //#region src/refresh.web.ts
4
+ var DOCK_ANIM_MS = 180;
5
+ /** Pointer/touch-driven pull-to-refresh for the DOM leaf — the web has no
6
+ * native overscroll, so drag distance translates the scroller inside the
7
+ * clipped wrapper while the self-drawn indicator slides into the gap.
8
+ * `touchmove` must be non-passive: `preventDefault` is what keeps the
9
+ * browser from taking the gesture as a scroll (or Chrome's own
10
+ * pull-to-refresh on Android). Mouse drags ride the pointer events. */
11
+ function createPullToRefresh(host) {
12
+ const { scroller, indicator, cfg } = host;
13
+ if (!scroller || !indicator) return {
14
+ sync: () => {},
15
+ detach: () => {}
16
+ };
17
+ let pulling = false;
18
+ let y0 = 0;
19
+ let pull = 0;
20
+ let docked = false;
21
+ let grace = null;
22
+ const threshold = () => cfg.current.threshold ?? 64;
23
+ /** Resting gap: the strip stays docked while the gesture docked it OR
24
+ * the controlled `refreshing` prop holds it open. */
25
+ const held = () => docked || !!cfg.current.refreshing;
26
+ const applyReveal = (reveal) => {
27
+ setTranslate(indicator, 0, reveal - 64);
28
+ setTranslate(scroller, 0, reveal);
29
+ };
30
+ const settle = (reveal) => {
31
+ for (const el of [scroller, indicator]) el.style.transition = `transform ${DOCK_ANIM_MS}ms ease-out`;
32
+ applyReveal(reveal);
33
+ setTimeout(() => {
34
+ for (const el of [scroller, indicator]) el.style.transition = "";
35
+ }, DOCK_ANIM_MS);
36
+ };
37
+ const dock = () => {
38
+ docked = true;
39
+ pull = 0;
40
+ settle(64);
41
+ };
42
+ const collapse = () => {
43
+ docked = false;
44
+ pull = 0;
45
+ settle(0);
46
+ };
47
+ /** `pull` is drag distance beyond the held baseline — a release only
48
+ * fires `onRefresh` when the user actually pulled (a resting release
49
+ * inside the dock re-fires nothing). */
50
+ const release = () => {
51
+ pulling = false;
52
+ const reveal = pull + (held() ? 64 : 0);
53
+ if (pull > 0 && reveal >= threshold()) {
54
+ cfg.current.onRefresh?.();
55
+ dock();
56
+ if (grace) clearTimeout(grace);
57
+ grace = setTimeout(() => {
58
+ if (!cfg.current.refreshing) collapse();
59
+ }, 350);
60
+ } else if (held()) {
61
+ docked = true;
62
+ pull = 0;
63
+ settle(64);
64
+ } else collapse();
65
+ };
66
+ const begin = (y, prevent) => {
67
+ if (scroller.scrollTop > 0) return;
68
+ pulling = true;
69
+ y0 = y;
70
+ pull = 0;
71
+ prevent?.();
72
+ };
73
+ const move = (y, prevent) => {
74
+ if (!pulling) return;
75
+ const dy = y - y0;
76
+ if (dy <= 0 || scroller.scrollTop > 0) {
77
+ pulling = false;
78
+ pull = 0;
79
+ applyReveal(held() ? 64 : 0);
80
+ return;
81
+ }
82
+ prevent();
83
+ pull = dampenPull(dy);
84
+ applyReveal(pull + (held() ? 64 : 0));
85
+ };
86
+ const end = () => {
87
+ if (pulling) release();
88
+ };
89
+ const touchStart = (e) => begin(e.touches[0].clientY);
90
+ const touchMove = (e) => move(e.touches[0].clientY, () => e.preventDefault());
91
+ const touchEnd = () => end();
92
+ const pointerDown = (e) => {
93
+ if (e.pointerType === "mouse" && e.button === 0) begin(e.clientY, () => e.preventDefault());
94
+ };
95
+ const pointerMove = (e) => {
96
+ if (e.pointerType === "mouse") move(e.clientY, () => e.preventDefault());
97
+ };
98
+ const pointerUp = (e) => {
99
+ if (e.pointerType === "mouse") end();
100
+ };
101
+ scroller.addEventListener("touchstart", touchStart, { passive: true });
102
+ scroller.addEventListener("touchmove", touchMove, { passive: false });
103
+ scroller.addEventListener("touchend", touchEnd);
104
+ scroller.addEventListener("touchcancel", touchEnd);
105
+ scroller.addEventListener("pointerdown", pointerDown);
106
+ scroller.addEventListener("pointermove", pointerMove);
107
+ scroller.addEventListener("pointerup", pointerUp);
108
+ scroller.addEventListener("pointercancel", pointerUp);
109
+ return {
110
+ sync: () => {
111
+ if (cfg.current.refreshing) {
112
+ if (grace) clearTimeout(grace);
113
+ if (!docked && !pulling) dock();
114
+ } else if (docked && !pulling) collapse();
115
+ },
116
+ detach: () => {
117
+ if (grace) clearTimeout(grace);
118
+ scroller.removeEventListener("touchstart", touchStart);
119
+ scroller.removeEventListener("touchmove", touchMove);
120
+ scroller.removeEventListener("touchend", touchEnd);
121
+ scroller.removeEventListener("touchcancel", touchEnd);
122
+ scroller.removeEventListener("pointerdown", pointerDown);
123
+ scroller.removeEventListener("pointermove", pointerMove);
124
+ scroller.removeEventListener("pointerup", pointerUp);
125
+ scroller.removeEventListener("pointercancel", pointerUp);
126
+ scroller.style.transition = "";
127
+ indicator.style.transition = "";
128
+ applyReveal(0);
129
+ }
130
+ };
131
+ }
132
+ //#endregion
133
+ export { createPullToRefresh };
@@ -1,4 +1,4 @@
1
- import { RouteRedirect, buildRoutePath, layoutChain, linkPath, matchUrl } from "./ui17.js";
1
+ import { RouteRedirect, buildRoutePath, layoutChain, linkPath, matchUrl } from "./route-table.js";
2
2
  import { hookSlots, useSyncExternalStore } from "octane";
3
3
  //#region src/route.web.ts
4
4
  var screens = {};
@@ -162,6 +162,18 @@ function presentationFor(name) {
162
162
  function popRoute(_stack = "root") {
163
163
  history.back();
164
164
  }
165
+ var backInterceptorWarned = false;
166
+ /** No-op twin of the native leaf. Browser back is already real history —
167
+ * there is no hardware-back event to intercept on web, so registered
168
+ * interceptors never fire. Warns once so a mistaken call site isn't
169
+ * silently absent. */
170
+ function addBackInterceptor(_fn) {
171
+ if (!backInterceptorWarned) {
172
+ backInterceptorWarned = true;
173
+ console.warn("[octane-xplat] addBackInterceptor is a no-op on web — browser back is URL history, not an interceptable event.");
174
+ }
175
+ return () => {};
176
+ }
165
177
  window.addEventListener("popstate", () => {
166
178
  saveScroll();
167
179
  historyDepth = history.state?.__octaneXplatDepth ?? 0;
@@ -237,4 +249,4 @@ var _h$0 = /* @__PURE__ */ Symbol(_hs$);
237
249
  var _h$1 = /* @__PURE__ */ Symbol(_hs$ + 1);
238
250
  var _h$2 = /* @__PURE__ */ Symbol(_hs$ + 2);
239
251
  //#endregion
240
- export { canGoBack, currentModalRoute, currentRoute, hrefFor, layoutsFor, popRoute, pushDeepLink, pushRoute, redirect, registerRoutes, registerScreens, routeFor, routeStacks, screenFor, useCanGoBack, useModalRoute, useRoute };
252
+ export { addBackInterceptor, canGoBack, currentModalRoute, currentRoute, hrefFor, layoutsFor, popRoute, pushDeepLink, pushRoute, redirect, registerRoutes, registerScreens, routeFor, routeStacks, screenFor, useCanGoBack, useModalRoute, useRoute };
@@ -0,0 +1,103 @@
1
+ import { setTranslate } from "./translate.web.js";
2
+ import { detentOffset, normalizeDetents, snapDetentIndex } from "./sheet-snap.js";
3
+ //#region src/sheet-detents.web.ts
4
+ var SNAP_MS = 200;
5
+ /** Drag-to-snap detents on a `.vx-sheet` panel: a self-drawn grabber strip
6
+ * (the only drag target — it never fights inner scrolling) drives the
7
+ * panel's translateY; the panel is sized to the largest detent and parked
8
+ * at the offset for the current one. `closeNow` fires after the dismiss
9
+ * slide-out — the caller decides what closing means (declarative
10
+ * `onDismiss` or the `openSheet` resolution). In-window on every target —
11
+ * the OS detent presentations (UISheetPresentationController /
12
+ * BottomSheetDialog) host a modal VC/dialog window, not a RootLayout
13
+ * child, so the snap mechanics stay self-drawn for pixel parity. */
14
+ function attachSheetDetents(panel, detents, closeNow) {
15
+ const sorted = normalizeDetents(detents);
16
+ if (!sorted.length) return { detach: () => {} };
17
+ const vh = () => panel.parentElement?.clientHeight || window.innerHeight || 1;
18
+ const max = sorted[sorted.length - 1];
19
+ panel.classList.add("vx-sheet-detents");
20
+ panel.style.height = `${max * 100}%`;
21
+ const grabber = document.createElement("div");
22
+ grabber.className = "vx-sheet-grabber";
23
+ const grip = document.createElement("div");
24
+ grip.className = "vx-sheet-grip";
25
+ grabber.appendChild(grip);
26
+ panel.appendChild(grabber);
27
+ let cur = 0;
28
+ let ty = 0;
29
+ let dragging = false;
30
+ let y0 = 0;
31
+ let ty0 = 0;
32
+ let vy = 0;
33
+ let lastY = 0;
34
+ let lastT = 0;
35
+ const applyTy = (value) => {
36
+ ty = value;
37
+ setTranslate(panel, 0, value);
38
+ };
39
+ const animateTo = (value, then) => {
40
+ panel.style.transition = `transform ${SNAP_MS}ms ease-out`;
41
+ applyTy(value);
42
+ setTimeout(() => {
43
+ panel.style.transition = "";
44
+ then?.();
45
+ }, SNAP_MS);
46
+ };
47
+ const down = (e) => {
48
+ if (e.pointerType === "mouse" && e.button !== 0) return;
49
+ dragging = true;
50
+ grabber.setPointerCapture?.(e.pointerId);
51
+ y0 = e.clientY;
52
+ lastY = e.clientY;
53
+ lastT = Date.now();
54
+ ty0 = ty;
55
+ vy = 0;
56
+ panel.style.transition = "";
57
+ e.preventDefault();
58
+ };
59
+ const move = (e) => {
60
+ if (!dragging) return;
61
+ const now = Date.now();
62
+ const dt = (now - lastT) / 1e3;
63
+ if (dt > 0) vy = vy * .7 + (e.clientY - lastY) / dt * .3;
64
+ lastY = e.clientY;
65
+ lastT = now;
66
+ applyTy(Math.min(Math.max(ty0 + (e.clientY - y0), 0), vh()));
67
+ e.preventDefault();
68
+ };
69
+ const up = () => {
70
+ if (!dragging) return;
71
+ dragging = false;
72
+ const next = snapDetentIndex(ty, vy, sorted, vh());
73
+ if (next < 0) animateTo(vh(), closeNow);
74
+ else {
75
+ cur = next;
76
+ animateTo(detentOffset(sorted, cur, vh()));
77
+ }
78
+ };
79
+ const pinGrabber = () => {
80
+ grabber.style.top = `${panel.scrollTop}px`;
81
+ };
82
+ panel.addEventListener("scroll", pinGrabber);
83
+ grabber.addEventListener("pointerdown", down);
84
+ grabber.addEventListener("pointermove", move);
85
+ grabber.addEventListener("pointerup", up);
86
+ grabber.addEventListener("pointercancel", up);
87
+ applyTy(vh());
88
+ const raf = requestAnimationFrame(() => animateTo(detentOffset(sorted, cur, vh())));
89
+ return { detach: () => {
90
+ cancelAnimationFrame(raf);
91
+ panel.removeEventListener("scroll", pinGrabber);
92
+ grabber.removeEventListener("pointerdown", down);
93
+ grabber.removeEventListener("pointermove", move);
94
+ grabber.removeEventListener("pointerup", up);
95
+ grabber.removeEventListener("pointercancel", up);
96
+ grabber.remove();
97
+ panel.classList.remove("vx-sheet-detents");
98
+ panel.style.height = "";
99
+ panel.style.transition = "";
100
+ } };
101
+ }
102
+ //#endregion
103
+ export { attachSheetDetents };
@@ -1,4 +1,5 @@
1
- import { applyThemeClasses } from "./ui29.js";
1
+ import { applyThemeClasses } from "./theme/theme-scheme.js";
2
+ import { attachSheetDetents } from "./sheet-detents.web.js";
2
3
  import { createRoot } from "octane";
3
4
  //#region src/sheet-service.web.ts
4
5
  var active = /* @__PURE__ */ new Set();
@@ -13,12 +14,14 @@ var openSheet = (Component, params, options = {}) => new Promise((resolve) => {
13
14
  const unbindTheme = applyThemeClasses(layer, "vx-sheet-layer");
14
15
  const panel = document.createElement("div");
15
16
  panel.className = "vx-sheet";
17
+ if (options.detents?.length) panel.classList.add("vx-sheet-detents");
16
18
  let finished = false;
17
19
  const finish = (result) => {
18
20
  if (finished) return;
19
21
  finished = true;
20
22
  active.delete(entry);
21
23
  unbindTheme();
24
+ detents?.detach();
22
25
  root.unmount();
23
26
  layer.remove();
24
27
  resolve(result);
@@ -35,6 +38,7 @@ var openSheet = (Component, params, options = {}) => new Promise((resolve) => {
35
38
  }
36
39
  layer.appendChild(panel);
37
40
  document.body.appendChild(layer);
41
+ const detents = options.detents?.length ? attachSheetDetents(panel, options.detents, () => finish()) : null;
38
42
  const root = createRoot(panel);
39
43
  root.render(Component, {
40
44
  params,
@@ -0,0 +1,35 @@
1
+ /** Sorted, filtered, deduped detent fractions. Empty → the caller keeps
2
+ * the content-sized sheet behavior (detents off). */
3
+ function normalizeDetents(input) {
4
+ if (!input?.length) return [];
5
+ return [...new Set(input.filter((d) => d > 0 && d <= 1))].sort((a, b) => a - b);
6
+ }
7
+ /** Resting translateY for a detent: the panel is `max * vh` tall, so the
8
+ * portion below the screen edge is `(max - detent) * vh`. */
9
+ function detentOffset(detents, index, vh) {
10
+ return (detents[detents.length - 1] - detents[index]) * vh;
11
+ }
12
+ /** Snap target for a release at translateY `ty` with vertical velocity
13
+ * `vy` (positive = dragging down). Returns the detent index, or -1 to
14
+ * dismiss: released below half of the smallest detent, or a downward
15
+ * fling while at/below it. */
16
+ function snapDetentIndex(ty, vy, detents, vh) {
17
+ const max = detents[detents.length - 1];
18
+ const frac = Math.min(Math.max(max - ty / vh, 0), 1);
19
+ if (vy > 500) {
20
+ let i = -1;
21
+ while (i + 1 < detents.length && detents[i + 1] < frac - 1e-6) i++;
22
+ return i;
23
+ }
24
+ if (vy < -500) {
25
+ let i = detents.length - 1;
26
+ while (i - 1 >= 0 && detents[i - 1] > frac + 1e-6) i--;
27
+ return i;
28
+ }
29
+ if (frac < detents[0] * .5) return -1;
30
+ let best = 0;
31
+ for (let i = 1; i < detents.length; i++) if (Math.abs(detents[i] - frac) < Math.abs(detents[best] - frac)) best = i;
32
+ return best;
33
+ }
34
+ //#endregion
35
+ export { detentOffset, normalizeDetents, snapDetentIndex };
@@ -1,5 +1,5 @@
1
- import { cx } from "./ui2.js";
2
- import { getColorScheme, subscribeSystemScheme } from "./ui30.js";
1
+ import { getColorScheme, subscribeSystemScheme } from "./colorScheme.web.js";
2
+ import { cx } from "../cx.js";
3
3
  import { hookSlots, useSyncExternalStore } from "octane";
4
4
  //#region src/theme/theme-scheme.ts
5
5
  var preference = "system";
@@ -0,0 +1,142 @@
1
+ import { cx } from "./cx.js";
2
+ import { applyThemeClasses } from "./theme/theme-scheme.js";
3
+ import { Popover } from "./Popover.web.tsrx.js";
4
+ import { bag1, bag3, clone, componentSlot, componentSlotVoid, createRoot, ifBlock, markChildrenBlock, template } from "octane";
5
+ import { childTextHoleUpdate } from "octane/internal/client";
6
+ //#region src/toast-anchor.web.tsrx
7
+ var _t$0 = /* @__PURE__ */ template("<div class=\"vx-toast\"></div>");
8
+ function __then$3(__props, __s, __extra) {
9
+ const props = __extra[0];
10
+ let _b = __s.slots[0];
11
+ if (_b === void 0) {
12
+ let _m0;
13
+ const _root = clone(_t$0);
14
+ _m0 = _root;
15
+ _b = bag3(__s, _root, _m0, null, void 0);
16
+ }
17
+ {
18
+ const _v = props.content;
19
+ _b.b = childTextHoleUpdate(__s, 1, _b.a, _v, _b.b, _b.c);
20
+ _b.c = _v;
21
+ }
22
+ }
23
+ function __else$5(__props, __s, __extra) {
24
+ const Component = __extra[0].content;
25
+ let _b = __s.slots[0];
26
+ if (_b === void 0) {
27
+ let _m0;
28
+ const _root = clone(_t$0);
29
+ _m0 = _root;
30
+ _b = bag1(__s, _root, _m0);
31
+ }
32
+ componentSlot(__s, 1, _b.a, Component, {}, void 0, void 0, void 0, void 0, void 0, "c:46bd91a2");
33
+ }
34
+ var __childrenBody = {};
35
+ function __then$0(__props, __s, __extra) {
36
+ const __block = __s.block;
37
+ const props = __extra[0];
38
+ function __children$2(__props, __s, __extra) {
39
+ const __block = __s.block;
40
+ ifBlock(__s, 0, __block.parentNode, typeof props.content === "string", __then$3, __else$5, __block.endMarker, [props]);
41
+ }
42
+ componentSlotVoid(__s, 0, __block.parentNode, Popover, {
43
+ "open": props.open,
44
+ "anchor": props.options.anchor,
45
+ "placement": props.options.placement ?? placementFor(props.options.position),
46
+ "dismissOnOutsideTap": false,
47
+ "children": markChildrenBlock(__children$2, __childrenBody)
48
+ }, __block.endMarker, void 0, void 0, void 0, void 0, "c:fb0a2e5d");
49
+ }
50
+ function __then$9(__props, __s, __extra) {
51
+ const props = __extra[0];
52
+ let _b = __s.slots[0];
53
+ if (_b === void 0) {
54
+ let _m0;
55
+ const _root = clone(_t$0);
56
+ _m0 = _root;
57
+ _b = bag3(__s, _root, _m0, null, void 0);
58
+ }
59
+ {
60
+ const _v = props.content;
61
+ _b.b = childTextHoleUpdate(__s, 1, _b.a, _v, _b.b, _b.c);
62
+ _b.c = _v;
63
+ }
64
+ }
65
+ function __else$11(__props, __s, __extra) {
66
+ const Component = __extra[0].content;
67
+ let _b = __s.slots[0];
68
+ if (_b === void 0) {
69
+ let _m0;
70
+ const _root = clone(_t$0);
71
+ _m0 = _root;
72
+ _b = bag1(__s, _root, _m0);
73
+ }
74
+ componentSlot(__s, 1, _b.a, Component, {}, void 0, void 0, void 0, void 0, void 0, "c:75cbf224");
75
+ }
76
+ function __else$8(__props, __s, __extra) {
77
+ const __block = __s.block;
78
+ const props = __extra[0];
79
+ ifBlock(__s, 0, __block.parentNode, typeof props.content === "string", __then$9, __else$11, __block.endMarker, __extra);
80
+ }
81
+ var queue = [];
82
+ var active = false;
83
+ var ToastBody = function ToastBody(props, __s, __extra) {
84
+ const __block = __s.block;
85
+ ifBlock(__s, 0, __block.parentNode, props.options.anchor, __then$0, __else$8, __block.endMarker, [props]);
86
+ };
87
+ function placementFor(position = "bottom") {
88
+ return position.startsWith("top") ? "top" : "bottom";
89
+ }
90
+ function applyWebProps(host, props) {
91
+ for (const [key, value] of Object.entries(props ?? {})) if (key.includes("-")) host.setAttribute(key, String(value));
92
+ else host[key] = value;
93
+ }
94
+ function alignmentFor(position = "bottom") {
95
+ if (position.endsWith("-start")) return "flex-start";
96
+ if (position.endsWith("-end")) return "flex-end";
97
+ return "center";
98
+ }
99
+ function showNext() {
100
+ if (active || queue.length === 0) return;
101
+ active = true;
102
+ const entry = queue.shift();
103
+ const anchored = Boolean(entry.options.anchor);
104
+ const host = document.createElement("div");
105
+ const position = entry.options.position ?? "bottom";
106
+ const unbindTheme = applyThemeClasses(host, cx("vx-toast-host", placementFor(position) === "top" ? "vx-toast-top" : "vx-toast-bottom"));
107
+ applyWebProps(host, entry.options.web);
108
+ if (anchored) host.style.display = "none";
109
+ else host.style.justifyContent = alignmentFor(position);
110
+ document.body.appendChild(host);
111
+ const root = createRoot(host);
112
+ root.render(ToastBody, {
113
+ ...entry,
114
+ open: true
115
+ });
116
+ const finish = () => {
117
+ const cleanup = () => {
118
+ unbindTheme();
119
+ root.unmount();
120
+ host.remove();
121
+ active = false;
122
+ showNext();
123
+ };
124
+ if (anchored) {
125
+ root.render(ToastBody, {
126
+ ...entry,
127
+ open: false
128
+ });
129
+ setTimeout(cleanup, 0);
130
+ } else cleanup();
131
+ };
132
+ setTimeout(finish, Math.max(0, entry.options.duration ?? 3e3));
133
+ }
134
+ function showToast(content, options = {}) {
135
+ queue.push({
136
+ content,
137
+ options
138
+ });
139
+ showNext();
140
+ }
141
+ //#endregion
142
+ export { showToast };
@@ -0,0 +1,43 @@
1
+ //#region src/transform.web.ts
2
+ /** Per-element transform composition for imperative writes. The DOM has a
3
+ * single `transform` string where native has discrete view props, so web
4
+ * keeps the last-written value per transform prop and re-joins them —
5
+ * an AnimatedValue on `rotate` and a setTranslate drag on the same
6
+ * element don't clobber each other. */
7
+ var transformProps = {
8
+ translateX: (v) => `translateX(${v}px)`,
9
+ translateY: (v) => `translateY(${v}px)`,
10
+ translateZ: (v) => `translateZ(${v}px)`,
11
+ scale: (v) => `scale(${v})`,
12
+ scaleX: (v) => `scaleX(${v})`,
13
+ scaleY: (v) => `scaleY(${v})`,
14
+ rotate: (v) => `rotate(${v}deg)`,
15
+ rotateX: (v) => `rotateX(${v}deg)`,
16
+ rotateY: (v) => `rotateY(${v}deg)`,
17
+ skewX: (v) => `skewX(${v}deg)`,
18
+ skewY: (v) => `skewY(${v}deg)`
19
+ };
20
+ var transformStates = /* @__PURE__ */ new WeakMap();
21
+ /** Write one transform prop without disturbing the element's other
22
+ * transform components (or its stylesheet/base transform). */
23
+ function writeTransformProp(el, prop, value) {
24
+ if (Object.prototype.hasOwnProperty.call(transformProps, prop)) {
25
+ const transformProp = prop;
26
+ let state = transformStates.get(el);
27
+ if (!state) {
28
+ const computed = getComputedStyle(el).transform;
29
+ state = {
30
+ base: computed === "none" ? "" : computed,
31
+ values: /* @__PURE__ */ new Map()
32
+ };
33
+ transformStates.set(el, state);
34
+ }
35
+ state.values.set(transformProp, value);
36
+ const transforms = Object.entries(transformProps).filter(([name]) => state.values.has(name)).map(([name, toTransform]) => toTransform(state.values.get(name)));
37
+ el.style.transform = [state.base, ...transforms].filter(Boolean).join(" ");
38
+ return;
39
+ }
40
+ el.style[prop] = value;
41
+ }
42
+ //#endregion
43
+ export { writeTransformProp };
@@ -0,0 +1,13 @@
1
+ import { writeTransformProp } from "./transform.web.js";
2
+ //#region src/translate.web.ts
3
+ /** Imperative translate write on a bound view — the gesture seam. Called
4
+ * per frame from pan handlers (docs/animation-gestures.md: animation
5
+ * writes imperative, state stays declarative). Composes with other
6
+ * transform writes on the same element via ./transform.web. */
7
+ var setTranslate = (el, x = 0, y = 0) => {
8
+ if (!el) return;
9
+ writeTransformProp(el, "translateX", x);
10
+ writeTransformProp(el, "translateY", y);
11
+ };
12
+ //#endregion
13
+ export { setTranslate };