@octane-xplat/ui 0.7.2 → 0.9.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 (219) hide show
  1. package/README.md +4 -3
  2. package/dist/native/Button.tsrx.js +1 -1
  3. package/dist/native/CommandPalette.tsrx.js +7 -1
  4. package/dist/native/Grid.tsrx.js +31 -2
  5. package/dist/native/KeyboardAvoiding.mobile.tsrx.js +2 -2
  6. package/dist/native/Markdown.tsrx.js +233 -0
  7. package/dist/native/Overlay.tsrx.js +15 -26
  8. package/dist/native/Pagination.tsrx.js +15 -12
  9. package/dist/native/PinInput.tsrx.js +25 -7
  10. package/dist/native/Popover.tsrx.js +33 -23
  11. package/dist/native/Pressable.tsrx.js +4 -1
  12. package/dist/native/Screen.tsrx.js +1 -1
  13. package/dist/native/SearchInput.tsrx.js +6 -3
  14. package/dist/native/Sheet.tsrx.js +23 -38
  15. package/dist/native/Slider.tsrx.js +23 -14
  16. package/dist/native/Text.tsrx.js +16 -0
  17. package/dist/native/TextArea.tsrx.js +6 -3
  18. package/dist/native/TextInput.tsrx.js +6 -3
  19. package/dist/native/VirtualList.tsrx.js +305 -121
  20. package/dist/native/WebView.tsrx.js +17 -2
  21. package/dist/native/_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js +9 -0
  22. package/dist/native/escape-props.js +2 -0
  23. package/dist/native/grid-auto-placement.js +83 -0
  24. package/dist/native/grid-placement.js +20 -0
  25. package/dist/native/index.shared.js +7 -5
  26. package/dist/native/keyboard-inset.mobile.js +5 -5
  27. package/dist/native/navigation-request.js +26 -0
  28. package/dist/native/octane-client-build.json +1 -1
  29. package/dist/native/overlay-lifetime.mobile.js +65 -0
  30. package/dist/native/pan.tsrx.js +16 -2
  31. package/dist/native/route-table.js +90 -10
  32. package/dist/native/route.js +26 -16
  33. package/dist/native/shared.js +7 -5
  34. package/dist/native/sheet-service.js +2 -2
  35. package/dist/native/svg.mobile.js +1 -1
  36. package/dist/native/{tap-to-blur.mobile.js → tap-to-blur.ios.js} +20 -32
  37. package/dist/native/text-focus.js +10 -0
  38. package/dist/native/text-write.js +18 -11
  39. package/dist/native/toast-anchor.tsrx.js +1 -1
  40. package/dist/native/ui.js +7 -6
  41. package/dist/native/useMeasure.tsrx.js +17 -18
  42. package/dist/native/vendor/ui-svg/index.android.js +2 -2
  43. package/dist/native/vendor/ui-svg/index.ios.js +2 -2
  44. package/dist/native/vendor/ui-svg/{index.common.js → src/index.common.js} +1 -1
  45. package/dist/native/virtual-list-cell-pool.js +63 -0
  46. package/dist/web/Button.web.tsrx.js +1 -1
  47. package/dist/web/KeyboardAvoiding.web.tsrx.js +78 -0
  48. package/dist/web/Markdown.tsrx.js +98 -0
  49. package/dist/web/Overlay.web.tsrx.js +81 -32
  50. package/dist/web/PinInput.web.tsrx.js +24 -10
  51. package/dist/web/Pressable.web.tsrx.js +169 -53
  52. package/dist/web/SearchInput.web.tsrx.js +2 -2
  53. package/dist/web/Sheet.web.tsrx.js +20 -7
  54. package/dist/web/TextArea.web.tsrx.js +22 -17
  55. package/dist/web/TextInput.web.tsrx.js +2 -2
  56. package/dist/web/VirtualList.web.tsrx.js +220 -109
  57. package/dist/web/WebView.web.tsrx.js +3 -3
  58. package/dist/web/{index.shared.js → index.shared.web.js} +7 -5
  59. package/dist/web/modal-focus.web.js +95 -0
  60. package/dist/web/navigation-request.js +26 -0
  61. package/dist/web/octane-client-build.json +1 -1
  62. package/dist/web/pan.web.tsrx.js +27 -10
  63. package/dist/web/route-table.js +90 -10
  64. package/dist/web/route.web.js +88 -22
  65. package/dist/web/sheet-service.web.js +8 -0
  66. package/dist/web/theme/colorScheme.web.js +31 -4
  67. package/dist/web/ui.js +8 -6
  68. package/dist/web/virtual-list-cell-pool.js +63 -0
  69. package/package.json +21 -19
  70. package/platforms/android/native-api-usage.json +7 -7
  71. package/src/CommandPalette.tsrx +8 -1
  72. package/src/Grid.tsrx +32 -1
  73. package/src/Icon.macos.tsrx +1 -0
  74. package/src/KeyboardAvoiding.macos.tsrx +7 -1
  75. package/src/KeyboardAvoiding.mobile.tsrx +2 -2
  76. package/src/KeyboardAvoiding.tsrx +15 -0
  77. package/src/KeyboardAvoiding.web.tsrx +15 -0
  78. package/src/Markdown.tsrx +121 -0
  79. package/src/Meter.tsrx +1 -0
  80. package/src/Overlay.tsrx +15 -30
  81. package/src/Overlay.web.tsrx +12 -3
  82. package/src/Pagination.tsrx +6 -4
  83. package/src/PinInput.macos.tsrx +20 -6
  84. package/src/PinInput.mobile.test.ts +107 -0
  85. package/src/PinInput.tsrx +20 -6
  86. package/src/PinInput.web.test.tsrx +42 -0
  87. package/src/PinInput.web.tsrx +20 -6
  88. package/src/Popover.tsrx +36 -22
  89. package/src/Pressable.tsrx +1 -1
  90. package/src/Pressable.web.test.tsrx +36 -0
  91. package/src/Pressable.web.tsrx +37 -6
  92. package/src/RouteHost.macos.tsrx +1 -0
  93. package/src/Screen.tsrx +1 -1
  94. package/src/SearchInput.tsrx +4 -3
  95. package/src/SearchInput.web.tsrx +1 -1
  96. package/src/Sheet.tsrx +21 -42
  97. package/src/Sheet.web.tsrx +9 -1
  98. package/src/Slider.tsrx +13 -11
  99. package/src/Text.tsrx +36 -0
  100. package/src/TextArea.tsrx +6 -5
  101. package/src/TextArea.web.test.tsrx +39 -0
  102. package/src/TextArea.web.tsrx +7 -5
  103. package/src/TextInput.tsrx +6 -6
  104. package/src/TextInput.web.tsrx +1 -1
  105. package/src/VirtualList.macos.tsrx +93 -6
  106. package/src/VirtualList.mobile.test.tsrx +232 -0
  107. package/src/VirtualList.tsrx +285 -81
  108. package/src/VirtualList.web.tsrx +131 -25
  109. package/src/WebView.tsrx +20 -10
  110. package/src/WebView.web.tsrx +3 -0
  111. package/src/android/BottomNavigationView.android.tsrx +1 -0
  112. package/src/android/MaterialDialog.android.tsrx +1 -0
  113. package/src/anim.macos.tsrx +1 -0
  114. package/src/apply-native-modifiers.native.ts +4 -1
  115. package/src/child-array.ts +12 -7
  116. package/src/colorScheme.macos.ts +1 -0
  117. package/src/controls.macos.tsrx +4 -1
  118. package/src/data-driver.mobile.test.ts +120 -0
  119. package/src/data-lifecycle.mobile.test.ts +251 -0
  120. package/src/escape-props.ts +13 -1
  121. package/src/grid-auto-placement.ts +163 -0
  122. package/src/grid-placement.ts +29 -0
  123. package/src/hosted-unsupported.macos.tsrx +1 -0
  124. package/src/index.macos.ts +23 -3
  125. package/src/index.mobile.ts +0 -1
  126. package/src/index.shared.ts +22 -1
  127. package/src/index.shared.web.ts +291 -0
  128. package/src/index.web.ts +1 -1
  129. package/src/input-readiness.web.test.tsrx +82 -0
  130. package/src/ios/UITabBar.ios.tsrx +1 -0
  131. package/src/keyboard-inset.mobile.test.ts +62 -0
  132. package/src/keyboard-inset.mobile.ts +63 -43
  133. package/src/layout-shells.macos.tsrx +1 -5
  134. package/src/macos-extras.macos.tsrx +2 -0
  135. package/src/modal-focus.web.test.tsrx +63 -0
  136. package/src/modal-focus.web.ts +162 -0
  137. package/src/navigation-request.ts +37 -0
  138. package/src/overlay-lifecycle.mobile.test.ts +316 -0
  139. package/src/overlay-lifetime.mobile.ts +107 -0
  140. package/src/pan.mobile.test.tsrx +116 -0
  141. package/src/pan.tsrx +20 -2
  142. package/src/pan.web.tsrx +35 -7
  143. package/src/platformProps.ts +1 -0
  144. package/src/popover.mobile.test.ts +9 -1
  145. package/src/pressable-accessibility.mobile.test.ts +30 -0
  146. package/src/props.ts +163 -3
  147. package/src/refresh.ts +6 -1
  148. package/src/refresh.web.test.ts +77 -77
  149. package/src/route-android.test.ts +162 -0
  150. package/src/route-history.web.test.ts +80 -0
  151. package/src/route-navigation.web.test.ts +173 -0
  152. package/src/route-table.test.ts +188 -9
  153. package/src/route-table.ts +138 -10
  154. package/src/route.macos.ts +56 -13
  155. package/src/route.ts +54 -24
  156. package/src/route.web.ts +141 -24
  157. package/src/sheet-detents.ts +5 -3
  158. package/src/sheet-service.macos.ts +5 -1
  159. package/src/sheet-service.ts +1 -1
  160. package/src/sheet-service.web.ts +8 -0
  161. package/src/sheet-snap.test.ts +23 -23
  162. package/src/sheet-snap.ts +6 -1
  163. package/src/svg.mobile.ts +9 -3
  164. package/src/tap-to-blur.ios.ts +106 -0
  165. package/src/tap-to-blur.mobile.ts +21 -95
  166. package/src/text-focus.ts +12 -0
  167. package/src/text-input.mobile.test.ts +89 -0
  168. package/src/text-write.ts +21 -11
  169. package/src/theme/colorScheme.linux.ts +2 -4
  170. package/src/theme/colorScheme.web.ts +51 -4
  171. package/src/theme/theme-scheme.macos.ts +8 -2
  172. package/src/theme/tokens.css +1740 -1718
  173. package/src/translate.macos.ts +4 -1
  174. package/src/useMeasure.tsrx +20 -21
  175. package/src/virtual-list-cell-pool.test.ts +53 -0
  176. package/src/virtual-list-cell-pool.ts +81 -0
  177. package/src/virtual-list-layout.test.ts +11 -8
  178. package/src/virtual-list-layout.ts +4 -8
  179. package/src/windows.linux.ts +7 -2
  180. package/src/windows.macos.ts +1 -0
  181. package/types/generated/.tsrx-typegen-manifest.json +16 -3
  182. package/types/generated/Grid.d.ts +0 -1
  183. package/types/generated/KeyboardAvoiding.d.ts +3 -0
  184. package/types/generated/KeyboardAvoiding.web.d.ts +2 -0
  185. package/types/generated/Markdown.d.ts +59 -0
  186. package/types/generated/TextArea.d.ts +2 -2
  187. package/types/generated/TextArea.web.d.ts +1 -1
  188. package/types/generated/TextInput.d.ts +2 -3
  189. package/types/generated/VirtualList.d.ts +3 -3
  190. package/types/generated/escape-props.d.ts +4 -0
  191. package/types/generated/grid-auto-placement.d.ts +13 -0
  192. package/types/generated/grid-placement.d.ts +5 -0
  193. package/types/generated/index.mobile.d.ts +0 -1
  194. package/types/generated/index.shared.d.ts +6 -3
  195. package/types/generated/index.shared.web.d.ts +114 -0
  196. package/types/generated/index.web.d.ts +1 -1
  197. package/types/generated/modal-focus.web.d.ts +3 -0
  198. package/types/generated/navigation-request.d.ts +10 -0
  199. package/types/generated/overlay-lifetime.mobile.d.ts +10 -0
  200. package/types/generated/props.d.ts +111 -3
  201. package/types/generated/route-table.d.ts +14 -3
  202. package/types/generated/svg.mobile.d.ts +2 -2
  203. package/types/generated/tap-to-blur.ios.d.ts +13 -0
  204. package/types/generated/tap-to-blur.mobile.d.ts +1 -15
  205. package/types/generated/text-focus.d.ts +3 -0
  206. package/types/generated/text-write.d.ts +3 -1
  207. package/types/generated/theme/colorScheme.web.d.ts +5 -0
  208. package/types/generated/virtual-list-cell-pool.d.ts +18 -0
  209. package/types/index.macos.d.ts +15 -3
  210. /package/src/vendor/ui-svg/{index.android.ts → src/index.android.ts} +0 -0
  211. /package/src/vendor/ui-svg/{index.common.ts → src/index.common.ts} +0 -0
  212. /package/src/vendor/ui-svg/{index.ios.ts → src/index.ios.ts} +0 -0
  213. /package/src/vendor/ui-svg/{index.ts → src/index.ts} +0 -0
  214. /package/src/vendor/ui-svg/{typings → src/typings}/SVGKit.d.ts +0 -0
  215. /package/src/vendor/ui-svg/{typings → src/typings}/android.d.ts +0 -0
  216. /package/src/vendor/ui-svg/{typings → src/typings}/ios.d.ts +0 -0
  217. /package/types/generated/vendor/ui-svg/{index.common.d.ts → src/index.common.d.ts} +0 -0
  218. /package/types/generated/vendor/ui-svg/{index.d.ts → src/index.d.ts} +0 -0
  219. /package/types/generated/vendor/ui-svg/{index.ios.d.ts → src/index.ios.d.ts} +0 -0
@@ -0,0 +1,291 @@
1
+ // Generated by scripts/sync-ui-barrels.mjs from index.shared.ts. Do not edit.
2
+ // Foundations and common controls
3
+ export { View } from './View'
4
+ export { View as Column } from './View'
5
+ export { Row } from './Row'
6
+ export { Grid } from './Grid'
7
+ export { Stack } from './Stack'
8
+ export { Absolute } from './Absolute'
9
+ export type { PanEvent, SwipeEvent, SetTranslate } from './props'
10
+ export { setTranslate } from './translate.web'
11
+ export { Spacer } from './Spacer'
12
+ export { Text } from './Text'
13
+ export { Markdown, MarkdownScreen } from './Markdown'
14
+ export type { MdDoc, MdNode, MdInline } from './Markdown'
15
+ export { RichText, RichTextSpan } from './RichText'
16
+ export { Pressable } from './Pressable'
17
+ export { Button } from './Button'
18
+ export { Collapsible } from './Collapsible'
19
+ export { Accordion } from './Accordion'
20
+ export { Checkbox } from './Checkbox'
21
+ export { RadioGroup } from './RadioGroup'
22
+ export { DropdownMenu } from './DropdownMenu'
23
+ export { ContextMenu } from './ContextMenu'
24
+ export { Badge } from './Badge'
25
+ export { Separator } from './Separator'
26
+ export { Skeleton } from './Skeleton'
27
+ export { Avatar } from './Avatar'
28
+ export { AvatarGroup } from './AvatarGroup'
29
+ export type {
30
+ AccordionItemSpec,
31
+ AccordionProps,
32
+ AvatarGroupProps,
33
+ AvatarProps,
34
+ BadgeProps,
35
+ ButtonProps,
36
+ CheckboxProps,
37
+ CollapsibleProps,
38
+ ContextMenuProps,
39
+ DropdownMenuProps,
40
+ MenuItem,
41
+ RadioGroupProps,
42
+ RadioOption,
43
+ SegmentedControlProps,
44
+ SeparatorProps,
45
+ SkeletonProps,
46
+ } from './props'
47
+
48
+ // Forms and data entry
49
+ export { FormField } from './FormField'
50
+ export { FieldGroup } from './FieldGroup'
51
+ export { ListItem } from './ListItem'
52
+ export { InputNumber } from './InputNumber'
53
+ export { PinInput } from './PinInput'
54
+ export { Select } from './Select'
55
+ export { SelectMenu, Combobox, InputMenu } from './aliases'
56
+ export { InputTags } from './InputTags'
57
+ export { InputRating } from './InputRating'
58
+ export { CheckboxGroup } from './CheckboxGroup'
59
+ export type {
60
+ CheckboxGroupProps,
61
+ FieldGroupProps,
62
+ ListItemComponent,
63
+ ListItemProps,
64
+ ListItemSlotProps,
65
+ FormFieldProps,
66
+ InputNumberProps,
67
+ InputRatingProps,
68
+ InputTagsProps,
69
+ PinInputProps,
70
+ SelectOption,
71
+ SelectProps,
72
+ } from './props'
73
+
74
+ // Navigation and command surfaces
75
+ export { Breadcrumb } from './Breadcrumb'
76
+ export { Pagination } from './Pagination'
77
+ export { Stepper } from './Stepper'
78
+ export { NavigationMenu } from './NavigationMenu'
79
+ export { CommandPalette } from './CommandPalette'
80
+ export type {
81
+ BreadcrumbItem,
82
+ BreadcrumbProps,
83
+ CommandPaletteProps,
84
+ NavigationMenuItem,
85
+ NavigationMenuProps,
86
+ PaginationProps,
87
+ StepperProps,
88
+ StepperStep,
89
+ } from './props'
90
+
91
+ // Content and display
92
+ export { Table } from './Table'
93
+ export { Timeline } from './Timeline'
94
+ export { Tree } from './Tree'
95
+ export { Alert } from './Alert'
96
+ export { Card } from './Card'
97
+ export { Chip } from './Chip'
98
+ export { Kbd } from './Kbd'
99
+ export { Empty } from './Empty'
100
+ export { Banner } from './Banner'
101
+ export { User } from './User'
102
+ export { ProgressGroup } from './ProgressGroup'
103
+ export type {
104
+ AlertProps,
105
+ BannerProps,
106
+ CardProps,
107
+ ChipProps,
108
+ EmptyProps,
109
+ KbdProps,
110
+ ProgressGroupProps,
111
+ TableColumn,
112
+ TableProps,
113
+ TimelineItem,
114
+ TimelineProps,
115
+ TreeNode,
116
+ TreeProps,
117
+ UserProps,
118
+ } from './props'
119
+
120
+ // Links, input, scrolling, media, and overlays
121
+ export { Link } from './Link'
122
+ export { NavLink } from './NavLink'
123
+ export { TextInput } from './TextInput'
124
+ export { TextArea } from './TextArea'
125
+ export { SearchInput } from './SearchInput'
126
+ export { SegmentedControl } from './SegmentedControl'
127
+ export { ScrollBox } from './ScrollBox'
128
+ export { ScrollView } from './ScrollView'
129
+ export { VirtualList } from './VirtualList'
130
+ export type { VirtualListProps } from './props'
131
+ export { Image } from './Image'
132
+ export { WebView } from './WebView'
133
+ export type { WebViewContentSize, WebViewHandle, WebViewLoadEvent, WebViewProps } from './props'
134
+ export { Overlay } from './Overlay'
135
+ export { Popover } from './Popover'
136
+ export { Hoverable } from './Hoverable'
137
+ export { Tooltip } from './Tooltip'
138
+ export { showToast } from './toast-anchor'
139
+ export type {
140
+ HoverableProps,
141
+ OverlayProps,
142
+ PopoverAnchorRef,
143
+ PopoverProps,
144
+ PopoverPlacement,
145
+ ToastContent,
146
+ ToastOptions,
147
+ ToastPosition,
148
+ TooltipProps,
149
+ } from './props'
150
+
151
+ // Animation, theme, styling, and host services
152
+ export { useAnimation } from './anim'
153
+ export type { AnimatedValue } from './anim'
154
+ export {
155
+ useThemeScheme,
156
+ getThemeScheme,
157
+ setThemePreference,
158
+ getThemePreference,
159
+ themeSchemeClasses,
160
+ onThemeSchemeChange,
161
+ applyThemeClasses,
162
+ } from './theme/theme-scheme'
163
+
164
+ export { useColorScheme, getColorScheme } from './theme/colorScheme.web'
165
+ export type { ColorScheme } from './theme/colorScheme.web'
166
+ export { styled } from './styled'
167
+ export { openWindow } from './windows.web'
168
+
169
+ // Screens, visual controls, and icons
170
+ export { Screen } from './Screen'
171
+ export { Tabs } from './Tabs'
172
+ export type { TabSpec } from './Tabs'
173
+ export { Switch } from './Switch'
174
+ export { SafeArea } from './SafeArea'
175
+ export { KeyboardAvoiding } from './KeyboardAvoiding'
176
+ export { Drawer } from './Drawer'
177
+ export { useSafeAreaInsets } from './safeAreaInsets'
178
+ export type { SafeAreaInsets } from './safeAreaInsets'
179
+ export { useMeasure } from './useMeasure'
180
+ export type { MeasureBounds, MeasureResult, UseMeasureOptions } from './props'
181
+ export { ActivityIndicator } from './ActivityIndicator'
182
+ export { Meter } from './Meter'
183
+ export { Slider } from './Slider'
184
+ export { Icon } from './Icon'
185
+ export { Heading } from './Heading'
186
+ export { registerIcon, registerIcons } from './icons'
187
+ export type { IconGlyph } from './icons'
188
+ export type {
189
+ ActivityIndicatorProps,
190
+ HeadingProps,
191
+ IconProps,
192
+ MeterProps,
193
+ RefreshProps,
194
+ SearchInputProps,
195
+ SliderProps,
196
+ } from './props'
197
+
198
+ // Platform state and routing
199
+ export { isNative } from './platform.web'
200
+ export { registerStack, getStack, stackEntries } from './stacks.web'
201
+ export {
202
+ pushRoute,
203
+ popRoute,
204
+ routeStacks,
205
+ pushDeepLink,
206
+ routeFor,
207
+ currentRoute,
208
+ currentModalRoute,
209
+ canGoBack,
210
+ useCanGoBack,
211
+ useRoute,
212
+ useModalRoute,
213
+ redirect,
214
+ addBackInterceptor,
215
+ registerScreens,
216
+ registerRoutes,
217
+ addRoutes,
218
+ screenFor,
219
+ hrefFor,
220
+ layoutsForRoute,
221
+ } from './route.web'
222
+
223
+ export { useBackInterceptor } from './use-back'
224
+
225
+ export {
226
+ deriveRouteManifest,
227
+ defineRoutes,
228
+ mergeRouteManifests,
229
+ manifestToJson,
230
+ } from './route-table'
231
+
232
+ export type {
233
+ BeforeLoad,
234
+ BeforeLoadArgs,
235
+ LinkProps,
236
+ NavLinkProps,
237
+ Route,
238
+ RouteContext,
239
+ RouteHead,
240
+ RouteHeadExport,
241
+ RouteMeta,
242
+ RouteManifest,
243
+ RouteManifestJson,
244
+ RouteJson,
245
+ RouteDataMode,
246
+ RouteNameOfPath,
247
+ RouteParamsFromSpecs,
248
+ RoutePathParams,
249
+ RoutePresentationsFromSpecs,
250
+ RouteSpec,
251
+ RouteSpecSet,
252
+ ManifestRouteNames,
253
+ ManifestRouteParams,
254
+ ManifestRoutePresentations,
255
+ SpecRouteInfo,
256
+ ScreenTable,
257
+ ModalOpenResult,
258
+ OpenWindowOptions,
259
+ } from './props'
260
+
261
+ // Stores, sheets, and shared prop types
262
+ export { createStore } from './store'
263
+ export type { Store, ReadableStore } from './store'
264
+ export { useStore } from './use-store'
265
+ export { Sheet } from './Sheet'
266
+ export { openSheet, closeSheet } from './sheet-service.web'
267
+ export type { SheetProps, SheetOpenOptions, OpenSheet } from './props'
268
+ export type {
269
+ AbsoluteProps,
270
+ DrawerProps,
271
+ GridProps,
272
+ ImageProps,
273
+ KeyboardAvoidingProps,
274
+ LayoutChildProps,
275
+ PressableProps,
276
+ RichTextProps,
277
+ RichTextSpanProps,
278
+ RowProps,
279
+ ScreenProps,
280
+ SafeAreaProps,
281
+ ScrollBoxProps,
282
+ ScrollViewProps,
283
+ SpacerProps,
284
+ StackProps,
285
+ SwitchProps,
286
+ TabsProps,
287
+ TextAreaProps,
288
+ TextInputProps,
289
+ TextProps,
290
+ ViewProps,
291
+ } from './props'
package/src/index.web.ts CHANGED
@@ -1 +1 @@
1
- export * from './index.shared'
1
+ export * from './index.shared.web'
@@ -0,0 +1,82 @@
1
+ // @vitest-environment jsdom
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { act, createRoot } from 'octane';
4
+ import { Pressable } from './Pressable.web.tsrx';
5
+ import { TextInput } from './TextInput.web.tsrx';
6
+ import { TextArea } from './TextArea.web.tsrx';
7
+ import { SearchInput } from './SearchInput.web.tsrx';
8
+
9
+ describe('keyboard access', () => {
10
+ it('cancels a held long press when disabled before its timer fires', () => {
11
+ vi.useFakeTimers();
12
+ try {
13
+ const host = document.createElement('div');
14
+ const root = createRoot(host);
15
+ const hold = vi.fn();
16
+ act(() => root.render(<Pressable onLongPress={hold}>Hold</Pressable>));
17
+ act(() => host.firstElementChild!.dispatchEvent(new Event('pointerdown', { bubbles: true })));
18
+ act(() => root.render(<Pressable onLongPress={hold} disabled>Hold</Pressable>));
19
+ act(() => vi.advanceTimersByTime(600));
20
+ expect(hold).not.toHaveBeenCalled();
21
+ root.unmount();
22
+ } finally {
23
+ vi.useRealTimers();
24
+ }
25
+ });
26
+
27
+ it('makes actionable Pressables keyboard reachable and activates once per key', () => {
28
+ const host = document.createElement('div');
29
+ document.body.appendChild(host);
30
+ const root = createRoot(host);
31
+ const press = vi.fn();
32
+ act(() => root.render(<Pressable onPress={press}>Save</Pressable>));
33
+ const button = host.firstElementChild as HTMLElement;
34
+ expect(button.tabIndex).toBe(0);
35
+ act(() => {
36
+ button.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
37
+ button.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', repeat: true, bubbles: true }));
38
+ button.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', bubbles: true }));
39
+ });
40
+
41
+ expect(press).toHaveBeenCalledTimes(1);
42
+ act(() => {
43
+ button.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true }));
44
+ button.dispatchEvent(new KeyboardEvent('keyup', { key: ' ', bubbles: true }));
45
+ });
46
+
47
+ expect(press).toHaveBeenCalledTimes(2);
48
+ act(() => root.render(<Pressable onPress={press} disabled>Save</Pressable>));
49
+ expect(button.tabIndex).toBe(-1);
50
+ act(() => button.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })));
51
+ expect(press).toHaveBeenCalledTimes(2);
52
+ root.unmount();
53
+ host.remove();
54
+ });
55
+
56
+ for (const Component of [TextInput, TextArea, SearchInput]) {
57
+ it(`does not submit ${Component.name} while Enter confirms composition`, () => {
58
+ const host = document.createElement('div');
59
+ const root = createRoot(host);
60
+ const submit = vi.fn();
61
+ act(() => root.render(<Component onSubmit={submit} />));
62
+ const input = host.querySelector('input,textarea')!;
63
+ act(() => input.dispatchEvent(new KeyboardEvent('keydown', {
64
+ key: 'Enter', ctrlKey: true, isComposing: true, bubbles: true,
65
+ })));
66
+
67
+ expect(submit).not.toHaveBeenCalled();
68
+ // Some engines report composition-confirming Enter as keyCode 229.
69
+ act(() => input.dispatchEvent(new KeyboardEvent('keydown', {
70
+ key: 'Enter', ctrlKey: true, keyCode: 229, bubbles: true,
71
+ })));
72
+
73
+ expect(submit).not.toHaveBeenCalled();
74
+ act(() => input.dispatchEvent(new KeyboardEvent('keydown', {
75
+ key: 'Enter', ctrlKey: true, bubbles: true,
76
+ })));
77
+
78
+ expect(submit).toHaveBeenCalledTimes(1);
79
+ root.unmount();
80
+ });
81
+ }
82
+ });
@@ -37,6 +37,7 @@ function applyIcon(item: TabViewItem, name: string): void {
37
37
  item.iconSource = name;
38
38
  return;
39
39
  }
40
+
40
41
  const glyph = getIcon(name);
41
42
  if (!glyph) {
42
43
  warnIconOnce(name, `tab icon '${name}' isn't registered — call registerIcons() at boot.`);
@@ -0,0 +1,62 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+
3
+ vi.mock('@nativescript/core', () => ({
4
+ Application: {
5
+ android: {
6
+ foregroundActivity: {
7
+ getWindow: () => ({
8
+ getAttributes: () => ({ softInputMode: 0 }),
9
+ getDecorView: () => ({}),
10
+ }),
11
+ },
12
+ },
13
+ },
14
+ Utils: { layout: { toDeviceIndependentPixels: (px: number) => px / 2 } },
15
+ }))
16
+
17
+ import { bindBottomInsetToKeyboard } from './keyboard-inset.mobile'
18
+
19
+ describe('Android overlay keyboard inset', () => {
20
+ it('converts physical IME pixels to NativeScript transform dips', () => {
21
+ let listener: any
22
+ vi.stubGlobal('android', {
23
+ view: {
24
+ WindowManager: {
25
+ LayoutParams: { SOFT_INPUT_MASK_ADJUST: 240, SOFT_INPUT_ADJUST_RESIZE: 16 },
26
+ },
27
+ },
28
+ })
29
+
30
+ vi.stubGlobal('androidx', {
31
+ core: {
32
+ view: {
33
+ ViewCompat: {
34
+ OnApplyWindowInsetsListener: class {
35
+ onApplyWindowInsets: any
36
+ constructor(value: any) {
37
+ this.onApplyWindowInsets = value.onApplyWindowInsets
38
+ }
39
+ },
40
+ setOnApplyWindowInsetsListener: (_view: any, value: any) => {
41
+ listener = value
42
+ },
43
+ },
44
+ WindowInsetsCompat: { Type: { ime: () => 'ime', systemBars: () => 'bars' } },
45
+ },
46
+ },
47
+ })
48
+
49
+ try {
50
+ const host = { translateY: 0 }
51
+ const unbind = bindBottomInsetToKeyboard(host)
52
+ const insets = { getInsets: (type: string) => ({ bottom: type === 'ime' ? 600 : 100 }) }
53
+ expect(listener.onApplyWindowInsets({}, insets)).toBe(insets)
54
+ expect(host.translateY).toBe(-250)
55
+ unbind()
56
+ expect(host.translateY).toBe(0)
57
+ expect(listener).toBe(null)
58
+ } finally {
59
+ vi.unstubAllGlobals()
60
+ }
61
+ })
62
+ })
@@ -1,23 +1,25 @@
1
- import { Application } from '@nativescript/core';
1
+ import { Application, Utils } from '@nativescript/core'
2
2
 
3
3
  // One shared observer tracks the keyboard's current bottom inset — a sheet
4
4
  // opened while the keyboard is ALREADY up must lift immediately (a
5
5
  // WillChangeFrame observer only learns about changes after binding), and a
6
6
  // focused field keeps the inset live across sheet swaps.
7
- const bound = new Set<any>();
8
- let inset = 0;
9
- let wired = false;
7
+ const bound = new Set<any>()
8
+ let inset = 0
9
+ let wired = false
10
10
 
11
11
  const apply = () => {
12
12
  bound.forEach((host) => {
13
- host.translateY = -inset;
14
- });
15
- };
16
-
13
+ host.translateY = -inset
14
+ })
15
+ }
17
16
 
18
17
  const wireIos = () => {
19
- if (wired) { return; }
20
- wired = true;
18
+ if (wired) {
19
+ return
20
+ }
21
+
22
+ wired = true
21
23
  NSNotificationCenter.defaultCenter.addObserverForNameObjectQueueUsingBlock(
22
24
  UIKeyboardWillChangeFrameNotification,
23
25
  null,
@@ -25,14 +27,19 @@ const wireIos = () => {
25
27
  (note: any) => {
26
28
  // UIKeyboardFrameEndUserInfoKey arrives boxed as NSValue whose
27
29
  // `CGRectValue` marshals to a plain CGRect object (not a call).
28
- const raw = note.userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey);
29
- const boxed = raw?.CGRectValue;
30
- const frame = typeof boxed === 'function' ? raw.CGRectValue() : (boxed ?? raw);
31
- inset = Math.max(0, UIScreen.mainScreen.bounds.size.height - (frame?.origin?.y ?? UIScreen.mainScreen.bounds.size.height));
32
- apply();
30
+ const raw = note.userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)
31
+ const boxed = raw?.CGRectValue
32
+ const frame = typeof boxed === 'function' ? raw.CGRectValue() : (boxed ?? raw)
33
+ inset = Math.max(
34
+ 0,
35
+ UIScreen.mainScreen.bounds.size.height -
36
+ (frame?.origin?.y ?? UIScreen.mainScreen.bounds.size.height),
37
+ )
38
+
39
+ apply()
33
40
  },
34
- );
35
- };
41
+ )
42
+ }
36
43
 
37
44
  /** Lift a bottom-anchored overlay host above the software keyboard.
38
45
  * iOS: a shared UIKeyboardWillChangeFrame observer tracks the inset and
@@ -45,45 +52,58 @@ const wireIos = () => {
45
52
  * restores the transform — call it when the host detaches. */
46
53
  export function bindBottomInsetToKeyboard(host: any): () => void {
47
54
  if (Application.ios) {
48
- wireIos();
49
- bound.add(host);
50
- host.translateY = -inset;
55
+ wireIos()
56
+ bound.add(host)
57
+ host.translateY = -inset
51
58
  return () => {
52
- bound.delete(host);
53
- host.translateY = 0;
54
- };
59
+ bound.delete(host)
60
+ host.translateY = 0
61
+ }
55
62
  }
56
63
 
57
64
  if (Application.android) {
58
- const nativeWindow = Application.android.foregroundActivity?.window;
59
- if (!nativeWindow) { return () => {}; }
60
- const params = (globalThis as any).android?.view?.WindowManager?.LayoutParams;
61
- if (!params) { return () => {}; }
65
+ const nativeWindow = Application.android.foregroundActivity?.getWindow()
66
+ if (!nativeWindow) {
67
+ return () => {}
68
+ }
69
+
70
+ const params = (globalThis as any).android?.view?.WindowManager?.LayoutParams
71
+ if (!params) {
72
+ return () => {}
73
+ }
74
+
62
75
  // adjustResize resizes the RootLayout for us — an extra offset would
63
76
  // double-lift the host.
64
- if ((nativeWindow.attributes.softInputMode & params.SOFT_INPUT_MASK_ADJUST) === params.SOFT_INPUT_ADJUST_RESIZE) {
65
- return () => {};
77
+ if (
78
+ (nativeWindow.getAttributes().softInputMode & params.SOFT_INPUT_MASK_ADJUST) ===
79
+ params.SOFT_INPUT_ADJUST_RESIZE
80
+ ) {
81
+ return () => {}
66
82
  }
67
83
 
68
- const ViewCompat = (globalThis as any).androidx?.core?.view?.ViewCompat;
69
- const WindowInsetsCompat = (globalThis as any).androidx?.core?.view?.WindowInsetsCompat;
70
- if (!ViewCompat || !WindowInsetsCompat) { return () => {}; }
71
- const decorView = nativeWindow.decorView;
84
+ const ViewCompat = (globalThis as any).androidx?.core?.view?.ViewCompat
85
+ const WindowInsetsCompat = (globalThis as any).androidx?.core?.view?.WindowInsetsCompat
86
+ if (!ViewCompat || !WindowInsetsCompat) {
87
+ return () => {}
88
+ }
89
+
90
+ const decorView = nativeWindow.getDecorView()
72
91
  const listener = new ViewCompat.OnApplyWindowInsetsListener({
73
92
  onApplyWindowInsets: (v: any, insets: any) => {
74
- const ime = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;
75
- const nav = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom;
76
- host.translateY = -Math.max(0, ime - nav);
77
- return insets;
93
+ const ime = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
94
+ const nav = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom
95
+ // Insets are physical pixels; NativeScript transforms are dips.
96
+ host.translateY = -Utils.layout.toDeviceIndependentPixels(Math.max(0, ime - nav))
97
+ return insets
78
98
  },
79
- });
99
+ })
80
100
 
81
- ViewCompat.setOnApplyWindowInsetsListener(decorView, listener);
101
+ ViewCompat.setOnApplyWindowInsetsListener(decorView, listener)
82
102
  return () => {
83
- host.translateY = 0;
84
- ViewCompat.setOnApplyWindowInsetsListener(decorView, null);
85
- };
103
+ host.translateY = 0
104
+ ViewCompat.setOnApplyWindowInsetsListener(decorView, null)
105
+ }
86
106
  }
87
107
 
88
- return () => {};
108
+ return () => {}
89
109
  }
@@ -1,10 +1,6 @@
1
1
  /** @jsxImportSource @xplat/macos/renderer */
2
- import type { KeyboardAvoidingProps, SafeAreaProps } from './props'
2
+ import type { SafeAreaProps } from './props'
3
3
 
4
4
  export function SafeArea(props: SafeAreaProps) @{
5
5
  <flexboxlayout flexDirection="column" className={props.className} style={props.style}>{props.children}</flexboxlayout>
6
6
  }
7
-
8
- export function KeyboardAvoiding(props: KeyboardAvoidingProps) @{
9
- <flexboxlayout flexDirection="column" className={props.className} style={props.style}>{props.children}</flexboxlayout>
10
- }
@@ -5,6 +5,7 @@ import { cx } from './cx'
5
5
  export function Meter(props: MeterProps) @{
6
6
  const size = props.size ?? 24
7
7
  const strokeWidth = Math.max(0, Math.min(props.strokeWidth ?? 3, size))
8
+
8
9
  // Track ring via layer chrome; the progress arc itself needs a stroked
9
10
  // CAShapeLayer — not bridged yet, so the ring renders unfilled.
10
11
  <flexboxlayout
@@ -28,6 +29,7 @@ export function Meter(props: MeterProps) @{
28
29
 
29
30
  export function Heading(props: HeadingProps) @{
30
31
  const level = props.level ?? 2
32
+
31
33
  <label
32
34
  id={props.id}
33
35
  className={cx('vx-heading', `vx-h${level}`, props.className)}
@@ -0,0 +1,63 @@
1
+ // @vitest-environment jsdom
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { act, createRoot } from 'octane';
4
+ vi.mock('./theme/theme-scheme', () => ({ useThemeScheme: () => 'light' }));
5
+ import { Sheet } from './Sheet.web.tsrx';
6
+ import { Overlay } from './Overlay.web.tsrx';
7
+ import { isolateModalFocus } from './modal-focus.web';
8
+
9
+ describe('modal focus isolation', () => {
10
+ for (const [name, Component] of [['Sheet', Sheet], ['Overlay', Overlay]] as const) {
11
+ it(`${name} isolates background focus and restores its trigger on close`, () => {
12
+ const host = document.createElement('div');
13
+ document.body.appendChild(host);
14
+ const root = createRoot(host);
15
+ act(() => root.render(<><button id="trigger">Open</button><Component open={false} shadeCover><button id="inside">Close</button></Component></>));
16
+ const trigger = host.querySelector('#trigger') as HTMLElement;
17
+ trigger.focus();
18
+ act(() => root.render(<><button id="trigger">Open</button><Component open shadeCover><button id="inside">Close</button></Component></>));
19
+ expect(host.hasAttribute('inert')).toBe(true);
20
+ expect(document.activeElement?.id).toBe('inside');
21
+ act(() => root.render(<><button id="trigger">Open</button><Component open={false} shadeCover><button id="inside">Close</button></Component></>));
22
+ expect(host.hasAttribute('inert')).toBe(false);
23
+ expect(document.activeElement).toBe(trigger);
24
+ act(() => root.render(<><button id="trigger">Open</button><Component open shadeCover><button id="inside">Close</button></Component></>));
25
+ expect(host.hasAttribute('inert')).toBe(true);
26
+ expect(document.activeElement?.id).toBe('inside');
27
+ root.unmount();
28
+ host.remove();
29
+ }, 30000);
30
+ }
31
+
32
+ it('preserves nested isolation when the lower modal closes first', async () => {
33
+ const host = document.createElement('div');
34
+ host.innerHTML = '<button id="return">Return</button>';
35
+ const existing = document.createElement('div');
36
+ existing.setAttribute('inert', '');
37
+ document.body.append(host, existing);
38
+ const trigger = host.firstElementChild as HTMLElement;
39
+ trigger.focus();
40
+ const outer = document.createElement('div');
41
+ outer.innerHTML = '<button>Outer</button>';
42
+ document.body.append(outer);
43
+ const closeOuter = isolateModalFocus(outer, outer, () => {});
44
+ const inner = document.createElement('div');
45
+ inner.innerHTML = '<button>Inner</button>';
46
+ document.body.append(inner);
47
+ await Promise.resolve(); // outer modal's observer sees the new portal
48
+ expect(inner.hasAttribute('inert')).toBe(true);
49
+ const closeInner = isolateModalFocus(inner, inner, () => {});
50
+ expect(outer.hasAttribute('inert')).toBe(true);
51
+ closeOuter();
52
+ outer.remove();
53
+ expect(host.hasAttribute('inert')).toBe(true);
54
+ expect(document.activeElement).toBe(inner.firstElementChild);
55
+ closeInner();
56
+ inner.remove();
57
+ expect(document.activeElement).toBe(trigger);
58
+ expect(host.hasAttribute('inert')).toBe(false);
59
+ expect(existing.hasAttribute('inert')).toBe(true);
60
+ host.remove();
61
+ existing.remove();
62
+ }, 30000);
63
+ });