@octane-xplat/ui 0.7.3 → 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.
- package/README.md +4 -3
- package/dist/native/Button.tsrx.js +1 -1
- package/dist/native/KeyboardAvoiding.mobile.tsrx.js +2 -2
- package/dist/native/Markdown.tsrx.js +233 -0
- package/dist/native/Overlay.tsrx.js +15 -26
- package/dist/native/PinInput.tsrx.js +25 -7
- package/dist/native/Popover.tsrx.js +17 -18
- package/dist/native/Pressable.tsrx.js +4 -1
- package/dist/native/SearchInput.tsrx.js +6 -3
- package/dist/native/Sheet.tsrx.js +22 -37
- package/dist/native/TextArea.tsrx.js +6 -3
- package/dist/native/TextInput.tsrx.js +6 -3
- package/dist/native/VirtualList.tsrx.js +305 -121
- package/dist/native/index.shared.js +7 -5
- package/dist/native/keyboard-inset.mobile.js +5 -5
- package/dist/native/navigation-request.js +26 -0
- package/dist/native/octane-client-build.json +1 -1
- package/dist/native/overlay-lifetime.mobile.js +65 -0
- package/dist/native/pan.tsrx.js +16 -2
- package/dist/native/route-table.js +90 -10
- package/dist/native/route.js +26 -16
- package/dist/native/shared.js +7 -5
- package/dist/native/sheet-service.js +1 -1
- package/dist/native/svg.mobile.js +1 -1
- package/dist/native/text-focus.js +10 -0
- package/dist/native/text-write.js +18 -11
- package/dist/native/toast-anchor.tsrx.js +1 -1
- package/dist/native/ui.js +7 -6
- package/dist/native/vendor/ui-svg/index.android.js +2 -2
- package/dist/native/vendor/ui-svg/index.ios.js +2 -2
- package/dist/native/vendor/ui-svg/{index.common.js → src/index.common.js} +1 -1
- package/dist/native/virtual-list-cell-pool.js +63 -0
- package/dist/web/Button.web.tsrx.js +1 -1
- package/dist/web/KeyboardAvoiding.web.tsrx.js +78 -0
- package/dist/web/Markdown.tsrx.js +98 -0
- package/dist/web/Overlay.web.tsrx.js +81 -32
- package/dist/web/PinInput.web.tsrx.js +24 -10
- package/dist/web/Pressable.web.tsrx.js +169 -53
- package/dist/web/SearchInput.web.tsrx.js +2 -2
- package/dist/web/Sheet.web.tsrx.js +20 -7
- package/dist/web/TextArea.web.tsrx.js +22 -17
- package/dist/web/TextInput.web.tsrx.js +2 -2
- package/dist/web/VirtualList.web.tsrx.js +220 -109
- package/dist/web/WebView.web.tsrx.js +3 -3
- package/dist/web/{index.shared.js → index.shared.web.js} +7 -5
- package/dist/web/modal-focus.web.js +95 -0
- package/dist/web/navigation-request.js +26 -0
- package/dist/web/octane-client-build.json +1 -1
- package/dist/web/pan.web.tsrx.js +27 -10
- package/dist/web/route-table.js +90 -10
- package/dist/web/route.web.js +88 -22
- package/dist/web/sheet-service.web.js +8 -0
- package/dist/web/theme/colorScheme.web.js +31 -4
- package/dist/web/ui.js +8 -6
- package/dist/web/virtual-list-cell-pool.js +63 -0
- package/package.json +21 -19
- package/platforms/android/native-api-usage.json +7 -7
- package/src/CommandPalette.tsrx +1 -0
- package/src/Grid.tsrx +2 -0
- package/src/Icon.macos.tsrx +1 -0
- package/src/KeyboardAvoiding.macos.tsrx +7 -1
- package/src/KeyboardAvoiding.mobile.tsrx +2 -2
- package/src/KeyboardAvoiding.tsrx +15 -0
- package/src/KeyboardAvoiding.web.tsrx +15 -0
- package/src/Markdown.tsrx +121 -0
- package/src/Meter.tsrx +1 -0
- package/src/Overlay.tsrx +15 -30
- package/src/Overlay.web.tsrx +12 -3
- package/src/PinInput.macos.tsrx +20 -6
- package/src/PinInput.mobile.test.ts +107 -0
- package/src/PinInput.tsrx +20 -6
- package/src/PinInput.web.test.tsrx +42 -0
- package/src/PinInput.web.tsrx +20 -6
- package/src/Popover.tsrx +17 -17
- package/src/Pressable.tsrx +1 -1
- package/src/Pressable.web.test.tsrx +36 -0
- package/src/Pressable.web.tsrx +37 -6
- package/src/RouteHost.macos.tsrx +1 -0
- package/src/SearchInput.tsrx +4 -3
- package/src/SearchInput.web.tsrx +1 -1
- package/src/Sheet.tsrx +20 -41
- package/src/Sheet.web.tsrx +9 -1
- package/src/Text.tsrx +2 -0
- package/src/TextArea.tsrx +6 -5
- package/src/TextArea.web.test.tsrx +39 -0
- package/src/TextArea.web.tsrx +7 -5
- package/src/TextInput.tsrx +6 -6
- package/src/TextInput.web.tsrx +1 -1
- package/src/VirtualList.macos.tsrx +93 -6
- package/src/VirtualList.mobile.test.tsrx +232 -0
- package/src/VirtualList.tsrx +285 -81
- package/src/VirtualList.web.tsrx +131 -25
- package/src/WebView.tsrx +1 -0
- package/src/WebView.web.tsrx +3 -0
- package/src/android/BottomNavigationView.android.tsrx +1 -0
- package/src/android/MaterialDialog.android.tsrx +1 -0
- package/src/anim.macos.tsrx +1 -0
- package/src/apply-native-modifiers.native.ts +4 -1
- package/src/child-array.ts +12 -7
- package/src/colorScheme.macos.ts +1 -0
- package/src/controls.macos.tsrx +4 -1
- package/src/data-driver.mobile.test.ts +120 -0
- package/src/data-lifecycle.mobile.test.ts +251 -0
- package/src/escape-props.ts +2 -0
- package/src/grid-auto-placement.ts +54 -12
- package/src/grid-placement.ts +1 -1
- package/src/hosted-unsupported.macos.tsrx +1 -0
- package/src/index.macos.ts +23 -3
- package/src/index.mobile.ts +0 -1
- package/src/index.shared.ts +22 -1
- package/src/index.shared.web.ts +291 -0
- package/src/index.web.ts +1 -1
- package/src/input-readiness.web.test.tsrx +82 -0
- package/src/ios/UITabBar.ios.tsrx +1 -0
- package/src/keyboard-inset.mobile.test.ts +62 -0
- package/src/keyboard-inset.mobile.ts +63 -43
- package/src/layout-shells.macos.tsrx +1 -5
- package/src/macos-extras.macos.tsrx +2 -0
- package/src/modal-focus.web.test.tsrx +63 -0
- package/src/modal-focus.web.ts +162 -0
- package/src/navigation-request.ts +37 -0
- package/src/overlay-lifecycle.mobile.test.ts +316 -0
- package/src/overlay-lifetime.mobile.ts +107 -0
- package/src/pan.mobile.test.tsrx +116 -0
- package/src/pan.tsrx +20 -2
- package/src/pan.web.tsrx +35 -7
- package/src/platformProps.ts +1 -0
- package/src/popover.mobile.test.ts +9 -1
- package/src/pressable-accessibility.mobile.test.ts +30 -0
- package/src/props.ts +163 -3
- package/src/refresh.ts +6 -1
- package/src/refresh.web.test.ts +77 -77
- package/src/route-android.test.ts +162 -0
- package/src/route-history.web.test.ts +80 -0
- package/src/route-navigation.web.test.ts +173 -0
- package/src/route-table.test.ts +188 -9
- package/src/route-table.ts +138 -10
- package/src/route.macos.ts +56 -13
- package/src/route.ts +54 -24
- package/src/route.web.ts +141 -24
- package/src/sheet-detents.ts +5 -3
- package/src/sheet-service.macos.ts +5 -1
- package/src/sheet-service.web.ts +8 -0
- package/src/sheet-snap.test.ts +23 -23
- package/src/sheet-snap.ts +6 -1
- package/src/svg.mobile.ts +9 -3
- package/src/tap-to-blur.ios.ts +48 -32
- package/src/tap-to-blur.mobile.ts +23 -15
- package/src/text-focus.ts +12 -0
- package/src/text-input.mobile.test.ts +89 -0
- package/src/text-write.ts +21 -11
- package/src/theme/colorScheme.linux.ts +2 -4
- package/src/theme/colorScheme.web.ts +51 -4
- package/src/theme/theme-scheme.macos.ts +8 -2
- package/src/theme/tokens.css +1736 -1730
- package/src/translate.macos.ts +4 -1
- package/src/virtual-list-cell-pool.test.ts +53 -0
- package/src/virtual-list-cell-pool.ts +81 -0
- package/src/virtual-list-layout.test.ts +11 -8
- package/src/virtual-list-layout.ts +4 -8
- package/src/windows.linux.ts +7 -2
- package/src/windows.macos.ts +1 -0
- package/types/generated/.tsrx-typegen-manifest.json +13 -3
- package/types/generated/KeyboardAvoiding.d.ts +3 -0
- package/types/generated/KeyboardAvoiding.web.d.ts +2 -0
- package/types/generated/Markdown.d.ts +59 -0
- package/types/generated/TextArea.d.ts +2 -2
- package/types/generated/TextArea.web.d.ts +1 -1
- package/types/generated/TextInput.d.ts +2 -3
- package/types/generated/VirtualList.d.ts +3 -3
- package/types/generated/index.mobile.d.ts +0 -1
- package/types/generated/index.shared.d.ts +6 -3
- package/types/generated/index.shared.web.d.ts +114 -0
- package/types/generated/index.web.d.ts +1 -1
- package/types/generated/modal-focus.web.d.ts +3 -0
- package/types/generated/navigation-request.d.ts +10 -0
- package/types/generated/overlay-lifetime.mobile.d.ts +10 -0
- package/types/generated/props.d.ts +111 -3
- package/types/generated/route-table.d.ts +14 -3
- package/types/generated/svg.mobile.d.ts +2 -2
- package/types/generated/text-focus.d.ts +3 -0
- package/types/generated/text-write.d.ts +3 -1
- package/types/generated/theme/colorScheme.web.d.ts +5 -0
- package/types/generated/virtual-list-cell-pool.d.ts +18 -0
- package/types/index.macos.d.ts +15 -3
- /package/src/vendor/ui-svg/{index.android.ts → src/index.android.ts} +0 -0
- /package/src/vendor/ui-svg/{index.common.ts → src/index.common.ts} +0 -0
- /package/src/vendor/ui-svg/{index.ios.ts → src/index.ios.ts} +0 -0
- /package/src/vendor/ui-svg/{index.ts → src/index.ts} +0 -0
- /package/src/vendor/ui-svg/{typings → src/typings}/SVGKit.d.ts +0 -0
- /package/src/vendor/ui-svg/{typings → src/typings}/android.d.ts +0 -0
- /package/src/vendor/ui-svg/{typings → src/typings}/ios.d.ts +0 -0
- /package/types/generated/vendor/ui-svg/{index.common.d.ts → src/index.common.d.ts} +0 -0
- /package/types/generated/vendor/ui-svg/{index.d.ts → src/index.d.ts} +0 -0
- /package/types/generated/vendor/ui-svg/{index.ios.d.ts → src/index.ios.d.ts} +0 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Profile,
|
|
3
|
+
SuspenseProfile,
|
|
4
|
+
NestedProfile,
|
|
5
|
+
Retained,
|
|
6
|
+
Reader,
|
|
7
|
+
sharedSelection$,
|
|
8
|
+
sharedCalls,
|
|
9
|
+
} from '../tests/data-lifecycle.fixture.mobile.tsrx'
|
|
10
|
+
|
|
11
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
12
|
+
import {
|
|
13
|
+
createObjectContainer,
|
|
14
|
+
createObjectDriver,
|
|
15
|
+
createUniversalRoot,
|
|
16
|
+
flushUniversalSync,
|
|
17
|
+
} from 'octane/universal/native'
|
|
18
|
+
|
|
19
|
+
import { type QueryContext } from 'octane/signals'
|
|
20
|
+
|
|
21
|
+
type Request = {
|
|
22
|
+
id: string
|
|
23
|
+
signal: AbortSignal
|
|
24
|
+
resolve: (value: string) => void
|
|
25
|
+
reject: (error: Error) => void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function requests() {
|
|
29
|
+
const calls: Request[] = []
|
|
30
|
+
const load = (id: string, { signal }: QueryContext<string>) =>
|
|
31
|
+
new Promise<string>((resolve, reject) => {
|
|
32
|
+
calls.push({ id, signal, resolve, reject })
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
return { calls, load }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const roots: ReturnType<typeof createUniversalRoot>[] = []
|
|
39
|
+
function mount(Component: any, props: any) {
|
|
40
|
+
const container = createObjectContainer('nativescript')
|
|
41
|
+
const root = createUniversalRoot(container, createObjectDriver('nativescript'))
|
|
42
|
+
roots.push(root)
|
|
43
|
+
root.render(Component, props)
|
|
44
|
+
return {
|
|
45
|
+
root,
|
|
46
|
+
container,
|
|
47
|
+
text: () =>
|
|
48
|
+
container.children
|
|
49
|
+
.filter((node: any) => node.type === 'label')
|
|
50
|
+
.map((node: any) => node.props.text),
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function settle() {
|
|
55
|
+
for (let i = 0; i < 12; i++) {
|
|
56
|
+
await Promise.resolve()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
flushUniversalSync(() => {})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
for (const root of roots.splice(0)) {
|
|
64
|
+
root.unmount()
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
describe('compiler-owned query lifecycle on universal roots', () => {
|
|
69
|
+
it('suspends on first data, catches a query error, and retries the boundary', async () => {
|
|
70
|
+
const { calls, load } = requests()
|
|
71
|
+
const view = mount(SuspenseProfile, { load })
|
|
72
|
+
expect(view.text()).toEqual(['pending'])
|
|
73
|
+
calls[0].reject(new Error('offline'))
|
|
74
|
+
await settle()
|
|
75
|
+
expect(view.container.children[0].props.text).toBe('offline')
|
|
76
|
+
flushUniversalSync(() => view.container.dispatchEvent(view.container.children[0], 'tap', {}))
|
|
77
|
+
await settle()
|
|
78
|
+
expect(view.text()).toEqual(['pending'])
|
|
79
|
+
expect(calls).toHaveLength(2)
|
|
80
|
+
calls[1].resolve('recovered')
|
|
81
|
+
await settle()
|
|
82
|
+
expect(view.text()).toEqual(['recovered'])
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('shares the declaring component query with a child reader', async () => {
|
|
86
|
+
const { calls, load } = requests()
|
|
87
|
+
const view = mount(NestedProfile, { load })
|
|
88
|
+
expect(calls).toHaveLength(1)
|
|
89
|
+
calls[0].resolve('nested result')
|
|
90
|
+
await settle()
|
|
91
|
+
expect(view.text()).toEqual(['ready', 'nested result'])
|
|
92
|
+
view.root.unmount()
|
|
93
|
+
expect(view.container.children).toEqual([])
|
|
94
|
+
const pendingView = mount(NestedProfile, { load })
|
|
95
|
+
expect(calls).toHaveLength(2)
|
|
96
|
+
pendingView.root.unmount()
|
|
97
|
+
expect(calls[1].signal.aborted).toBe(true)
|
|
98
|
+
calls[1].resolve('after child reader unmounted')
|
|
99
|
+
await settle()
|
|
100
|
+
expect(pendingView.container.children).toEqual([])
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('isolates stacked instances, retires requests, and ignores late responses', async () => {
|
|
104
|
+
const { calls, load } = requests()
|
|
105
|
+
const first = mount(Profile, { id: 'first', load })
|
|
106
|
+
const second = mount(Profile, { id: 'second', load })
|
|
107
|
+
expect(calls.map((call) => call.id)).toEqual(['first', 'second'])
|
|
108
|
+
calls[0].resolve('one')
|
|
109
|
+
calls[1].resolve('two')
|
|
110
|
+
await settle()
|
|
111
|
+
expect(first.text()).toEqual(['first:ready:one:false'])
|
|
112
|
+
expect(second.text()).toEqual(['second:ready:two:false'])
|
|
113
|
+
second.root.render(Profile, { id: 'second', nextId: 'third', load })
|
|
114
|
+
flushUniversalSync(() =>
|
|
115
|
+
second.container.dispatchEvent(second.container.children[4], 'tap', {}),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
await settle()
|
|
119
|
+
expect(calls.map((call) => call.id)).toEqual(['first', 'second', 'third'])
|
|
120
|
+
second.root.render(Profile, { id: 'second', nextId: 'fourth', load })
|
|
121
|
+
flushUniversalSync(() =>
|
|
122
|
+
second.container.dispatchEvent(second.container.children[4], 'tap', {}),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
await settle()
|
|
126
|
+
expect(calls[2].signal.aborted).toBe(true)
|
|
127
|
+
calls[3].resolve('four')
|
|
128
|
+
await settle()
|
|
129
|
+
calls[2].resolve('late third')
|
|
130
|
+
await settle()
|
|
131
|
+
expect(second.text()).toEqual(['fourth:ready:four:false'])
|
|
132
|
+
expect(first.text()).toEqual(['first:ready:one:false'])
|
|
133
|
+
second.root.render(Profile, { id: 'second', nextId: 'fifth', load })
|
|
134
|
+
flushUniversalSync(() =>
|
|
135
|
+
second.container.dispatchEvent(second.container.children[4], 'tap', {}),
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
await settle()
|
|
139
|
+
second.root.unmount()
|
|
140
|
+
expect(calls[4].signal.aborted).toBe(true)
|
|
141
|
+
calls[4].resolve('after unmount')
|
|
142
|
+
await settle()
|
|
143
|
+
expect(second.container.children).toEqual([])
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('reports pending, error, retry, refetch, and reset separately', async () => {
|
|
147
|
+
const { calls, load } = requests()
|
|
148
|
+
const view = mount(Profile, { id: 'a', load })
|
|
149
|
+
expect(view.text()).toEqual(['a:pending:none:false'])
|
|
150
|
+
calls[0].reject(new Error('offline'))
|
|
151
|
+
await settle()
|
|
152
|
+
expect(view.text()).toEqual(['a:error:none:false'])
|
|
153
|
+
flushUniversalSync(() => view.container.dispatchEvent(view.container.children[1], 'tap', {}))
|
|
154
|
+
await settle()
|
|
155
|
+
expect(view.text()).toEqual(['a:pending:none:false'])
|
|
156
|
+
calls[1].resolve('one')
|
|
157
|
+
await settle()
|
|
158
|
+
flushUniversalSync(() => view.container.dispatchEvent(view.container.children[2], 'tap', {}))
|
|
159
|
+
await settle()
|
|
160
|
+
expect(view.text()).toEqual(['a:ready:one:true'])
|
|
161
|
+
calls[2].resolve('two')
|
|
162
|
+
await settle()
|
|
163
|
+
flushUniversalSync(() => view.container.dispatchEvent(view.container.children[3], 'tap', {}))
|
|
164
|
+
await settle()
|
|
165
|
+
expect(view.text()).toEqual(['a:pending:two:false'])
|
|
166
|
+
calls[3].resolve('three')
|
|
167
|
+
await settle()
|
|
168
|
+
expect(view.text()).toEqual(['a:ready:three:false'])
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('updates a module signal across roots and disconnects unmounted readers', async () => {
|
|
172
|
+
const selection$ = sharedSelection$
|
|
173
|
+
const calls = sharedCalls
|
|
174
|
+
selection$.set('a')
|
|
175
|
+
let renders = 0
|
|
176
|
+
const props = {
|
|
177
|
+
onRender: () => {
|
|
178
|
+
renders++
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const page = mount(Reader, props)
|
|
183
|
+
const sheet = mount(Reader, props)
|
|
184
|
+
const modal = mount(Reader, props)
|
|
185
|
+
expect(calls).toHaveLength(1)
|
|
186
|
+
calls[0].resolve('one')
|
|
187
|
+
await settle()
|
|
188
|
+
for (const view of [page, sheet, modal]) {
|
|
189
|
+
expect(view.text()).toEqual(['a:ready:one'])
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
flushUniversalSync(() => selection$.set('b'))
|
|
193
|
+
await settle()
|
|
194
|
+
expect(calls).toHaveLength(2)
|
|
195
|
+
calls[1].resolve('two')
|
|
196
|
+
await settle()
|
|
197
|
+
for (const view of [page, sheet, modal]) {
|
|
198
|
+
expect(view.text()).toEqual(['b:ready:two'])
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
for (const view of [page, sheet, modal]) {
|
|
202
|
+
view.root.unmount()
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const before = renders
|
|
206
|
+
flushUniversalSync(() => selection$.set(''))
|
|
207
|
+
await settle()
|
|
208
|
+
expect(renders).toBe(before)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('delivers a tap that re-suspends, hides retained hosts, and reports handler errors', async () => {
|
|
212
|
+
let resolve!: (value: string) => void
|
|
213
|
+
const pending = new Promise<string>((done) => {
|
|
214
|
+
resolve = done
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
const error = new Error('handler failure')
|
|
218
|
+
const fail = vi.fn(() => {
|
|
219
|
+
throw error
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
const uncaught = vi.fn()
|
|
223
|
+
const container = createObjectContainer('nativescript')
|
|
224
|
+
const root = createUniversalRoot(container, createObjectDriver('nativescript'), {
|
|
225
|
+
onUncaughtError: uncaught,
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
roots.push(root)
|
|
229
|
+
root.render(Retained, { pending, fail })
|
|
230
|
+
const body = container.children[0]
|
|
231
|
+
expect(body.props.text).toBe('ready')
|
|
232
|
+
flushUniversalSync(() => container.dispatchEvent(body, 'tap', {}))
|
|
233
|
+
await settle()
|
|
234
|
+
expect(container.children[0]).toBe(body)
|
|
235
|
+
expect(body.visible).toBe(false)
|
|
236
|
+
expect(container.children[1]).toMatchObject({ props: { text: 'pending' }, visible: true })
|
|
237
|
+
expect(container.commits.flatMap((batch: any) => batch.commands ?? batch)).toEqual(
|
|
238
|
+
expect.arrayContaining([expect.objectContaining({ op: 'visibility', state: 'hidden' })]),
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
resolve('resolved')
|
|
242
|
+
await settle()
|
|
243
|
+
expect(container.children[0]).toBe(body)
|
|
244
|
+
expect(body.visible).toBe(true)
|
|
245
|
+
expect(body.props.text).toBe('resolved')
|
|
246
|
+
container.dispatchEvent(container.children[1], 'tap', {})
|
|
247
|
+
await settle()
|
|
248
|
+
expect(fail).toHaveBeenCalledOnce()
|
|
249
|
+
expect(uncaught).toHaveBeenCalledWith(error)
|
|
250
|
+
})
|
|
251
|
+
})
|
package/src/escape-props.ts
CHANGED
|
@@ -19,12 +19,14 @@ export function applyEscapeProps(
|
|
|
19
19
|
if (!view) {
|
|
20
20
|
return
|
|
21
21
|
}
|
|
22
|
+
|
|
22
23
|
rememberGridChildPlacement(view, props)
|
|
23
24
|
|
|
24
25
|
const bag = isIOS ? props.ios : isAndroid ? props.android : undefined
|
|
25
26
|
if (bag) {
|
|
26
27
|
Object.assign(view, bag)
|
|
27
28
|
}
|
|
29
|
+
|
|
28
30
|
applyNativeModifiers(view, props.modifiers)
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -12,7 +12,10 @@ export interface GridAutoPlacement {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function gridIndex(value: unknown): number | null {
|
|
15
|
-
if (value == null || value === '')
|
|
15
|
+
if (value == null || value === '') {
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
|
|
16
19
|
const index = Number(value)
|
|
17
20
|
return Number.isInteger(index) && index >= 0 ? index : null
|
|
18
21
|
}
|
|
@@ -38,6 +41,7 @@ export function autoPlaceGridChildren(
|
|
|
38
41
|
rowSpan: gridSpan(item.rowSpan),
|
|
39
42
|
colSpan: gridSpan(item.colSpan),
|
|
40
43
|
}))
|
|
44
|
+
|
|
41
45
|
const columnCount = Math.max(
|
|
42
46
|
1,
|
|
43
47
|
trackCount(columnTracks),
|
|
@@ -46,18 +50,25 @@ export function autoPlaceGridChildren(
|
|
|
46
50
|
.map((placement) => placement.col! + placement.colSpan),
|
|
47
51
|
...placements.map((placement) => placement.colSpan),
|
|
48
52
|
)
|
|
53
|
+
|
|
49
54
|
const occupied = new Set<string>()
|
|
50
55
|
const isFree = (row: number, col: number, rowSpan: number, colSpan: number) => {
|
|
51
56
|
for (let y = row; y < row + rowSpan; y++) {
|
|
52
57
|
for (let x = col; x < col + colSpan; x++) {
|
|
53
|
-
if (occupied.has(`${y},${x}`))
|
|
58
|
+
if (occupied.has(`${y},${x}`)) {
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
54
61
|
}
|
|
55
62
|
}
|
|
63
|
+
|
|
56
64
|
return true
|
|
57
65
|
}
|
|
66
|
+
|
|
58
67
|
const occupy = (row: number, col: number, rowSpan: number, colSpan: number) => {
|
|
59
68
|
for (let y = row; y < row + rowSpan; y++) {
|
|
60
|
-
for (let x = col; x < col + colSpan; x++)
|
|
69
|
+
for (let x = col; x < col + colSpan; x++) {
|
|
70
|
+
occupied.add(`${y},${x}`)
|
|
71
|
+
}
|
|
61
72
|
}
|
|
62
73
|
}
|
|
63
74
|
|
|
@@ -69,17 +80,29 @@ export function autoPlaceGridChildren(
|
|
|
69
80
|
}
|
|
70
81
|
|
|
71
82
|
for (const placement of placements) {
|
|
72
|
-
if (placement.row == null || placement.col != null)
|
|
83
|
+
if (placement.row == null || placement.col != null) {
|
|
84
|
+
continue
|
|
85
|
+
}
|
|
86
|
+
|
|
73
87
|
let col = 0
|
|
74
|
-
while (!isFree(placement.row, col, placement.rowSpan, placement.colSpan))
|
|
88
|
+
while (!isFree(placement.row, col, placement.rowSpan, placement.colSpan)) {
|
|
89
|
+
col++
|
|
90
|
+
}
|
|
91
|
+
|
|
75
92
|
placement.col = col
|
|
76
93
|
occupy(placement.row, col, placement.rowSpan, placement.colSpan)
|
|
77
94
|
}
|
|
78
95
|
|
|
79
96
|
for (const placement of placements) {
|
|
80
|
-
if (placement.col == null || placement.row != null)
|
|
97
|
+
if (placement.col == null || placement.row != null) {
|
|
98
|
+
continue
|
|
99
|
+
}
|
|
100
|
+
|
|
81
101
|
let row = 0
|
|
82
|
-
while (!isFree(row, placement.col, placement.rowSpan, placement.colSpan))
|
|
102
|
+
while (!isFree(row, placement.col, placement.rowSpan, placement.colSpan)) {
|
|
103
|
+
row++
|
|
104
|
+
}
|
|
105
|
+
|
|
83
106
|
placement.row = row
|
|
84
107
|
occupy(row, placement.col, placement.rowSpan, placement.colSpan)
|
|
85
108
|
}
|
|
@@ -87,16 +110,24 @@ export function autoPlaceGridChildren(
|
|
|
87
110
|
let cursorRow = 0
|
|
88
111
|
let cursorCol = 0
|
|
89
112
|
for (const placement of placements) {
|
|
90
|
-
if (placement.row != null && placement.col != null)
|
|
113
|
+
if (placement.row != null && placement.col != null) {
|
|
114
|
+
continue
|
|
115
|
+
}
|
|
116
|
+
|
|
91
117
|
while (true) {
|
|
92
118
|
if (cursorCol + placement.colSpan > columnCount) {
|
|
93
119
|
cursorRow++
|
|
94
120
|
cursorCol = 0
|
|
95
121
|
continue
|
|
96
122
|
}
|
|
97
|
-
|
|
123
|
+
|
|
124
|
+
if (isFree(cursorRow, cursorCol, placement.rowSpan, placement.colSpan)) {
|
|
125
|
+
break
|
|
126
|
+
}
|
|
127
|
+
|
|
98
128
|
cursorCol++
|
|
99
129
|
}
|
|
130
|
+
|
|
100
131
|
placement.row = cursorRow
|
|
101
132
|
placement.col = cursorCol
|
|
102
133
|
occupy(cursorRow, cursorCol, placement.rowSpan, placement.colSpan)
|
|
@@ -109,13 +140,24 @@ export function autoPlaceGridChildren(
|
|
|
109
140
|
|
|
110
141
|
return {
|
|
111
142
|
cells: placements.map(({ row, col }) => ({ row: row!, col: col! })),
|
|
112
|
-
rowCount: Math.max(
|
|
143
|
+
rowCount: Math.max(
|
|
144
|
+
trackCount(rowTracks),
|
|
145
|
+
...placements.map((item) => item.row! + item.rowSpan),
|
|
146
|
+
),
|
|
113
147
|
columnCount: Math.max(columnCount, ...placements.map((item) => item.col! + item.colSpan)),
|
|
114
148
|
}
|
|
115
149
|
}
|
|
116
150
|
|
|
117
151
|
export function ensureGridTracks(spec: string | undefined, requiredCount: number): string {
|
|
118
|
-
const tracks =
|
|
119
|
-
|
|
152
|
+
const tracks =
|
|
153
|
+
spec
|
|
154
|
+
?.split(',')
|
|
155
|
+
.map((track) => track.trim())
|
|
156
|
+
.filter(Boolean) ?? []
|
|
157
|
+
|
|
158
|
+
while (tracks.length < requiredCount) {
|
|
159
|
+
tracks.push('auto')
|
|
160
|
+
}
|
|
161
|
+
|
|
120
162
|
return tracks.join(',')
|
|
121
163
|
}
|
package/src/grid-placement.ts
CHANGED
|
@@ -25,5 +25,5 @@ export function rememberGridChildPlacement(view: unknown, props: GridChildPlacem
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function gridChildPlacement(view: unknown): GridChildPlacement {
|
|
28
|
-
return typeof view === 'object' && view !== null ? placements.get(view) ?? {} : {}
|
|
28
|
+
return typeof view === 'object' && view !== null ? (placements.get(view) ?? {}) : {}
|
|
29
29
|
}
|
|
@@ -4,6 +4,7 @@ import type { CameraViewProps, WebViewProps } from './props'
|
|
|
4
4
|
export function WebView(_props: WebViewProps) @{
|
|
5
5
|
<label className="vx-unsupported">WebView is unsupported by the AppKit host</label>
|
|
6
6
|
}
|
|
7
|
+
|
|
7
8
|
export function CameraView(_props: CameraViewProps) @{
|
|
8
9
|
<label className="vx-unsupported">Camera capture is unsupported by the AppKit host</label>
|
|
9
10
|
}
|
package/src/index.macos.ts
CHANGED
|
@@ -8,7 +8,15 @@ export type { PanEvent, SwipeEvent, SetTranslate } from './props'
|
|
|
8
8
|
export { setTranslate } from './translate.macos'
|
|
9
9
|
export { Text, RichText, RichTextSpan } from './Text.macos.tsrx'
|
|
10
10
|
export { Pressable } from './Pressable.macos.tsrx'
|
|
11
|
-
export {
|
|
11
|
+
export {
|
|
12
|
+
Button,
|
|
13
|
+
Checkbox,
|
|
14
|
+
Switch,
|
|
15
|
+
Slider,
|
|
16
|
+
SegmentedControl,
|
|
17
|
+
SearchInput,
|
|
18
|
+
ActivityIndicator,
|
|
19
|
+
} from './controls.macos.tsrx'
|
|
12
20
|
|
|
13
21
|
export { Collapsible } from './Collapsible.macos.tsrx'
|
|
14
22
|
export { Accordion } from './Accordion.macos.tsrx'
|
|
@@ -50,6 +58,7 @@ export { Drawer } from './Drawer.macos.tsrx'
|
|
|
50
58
|
|
|
51
59
|
export { Hoverable } from './Hoverable.tsrx'
|
|
52
60
|
export { Tooltip } from './Tooltip.tsrx'
|
|
61
|
+
export { Markdown, MarkdownScreen } from './Markdown.tsrx'
|
|
53
62
|
export { Link } from './Link.macos.tsrx'
|
|
54
63
|
export { NavLink } from './NavLink.macos.tsrx'
|
|
55
64
|
export { TextInput, TextArea } from './text-controls.macos.tsrx'
|
|
@@ -60,14 +69,25 @@ export { WebView, CameraView } from './hosted-unsupported.macos.tsrx'
|
|
|
60
69
|
export { Overlay, Popover, Sheet } from './surfaces.macos.tsrx'
|
|
61
70
|
export { showToast } from './toast-anchor.macos.tsrx'
|
|
62
71
|
export { useAnimation } from './anim.macos.tsrx'
|
|
63
|
-
export {
|
|
72
|
+
export {
|
|
73
|
+
useThemeScheme,
|
|
74
|
+
getThemeScheme,
|
|
75
|
+
setThemePreference,
|
|
76
|
+
getThemePreference,
|
|
77
|
+
themeSchemeClasses,
|
|
78
|
+
onThemeSchemeChange,
|
|
79
|
+
applyThemeClasses,
|
|
80
|
+
} from './theme/theme-scheme'
|
|
81
|
+
|
|
64
82
|
export { useColorScheme, getColorScheme } from './colorScheme.macos'
|
|
65
83
|
export { styled } from './styled.macos.tsrx'
|
|
66
84
|
export { openWindow } from './windows.macos'
|
|
67
85
|
export { Screen } from './Screen.macos.tsrx'
|
|
68
86
|
export { Tabs } from './Tabs.macos.tsrx'
|
|
69
87
|
export type { TabSpec } from './props'
|
|
70
|
-
export { SafeArea
|
|
88
|
+
export { SafeArea } from './layout-shells.macos.tsrx'
|
|
89
|
+
export { KeyboardAvoiding } from './KeyboardAvoiding.macos.tsrx'
|
|
90
|
+
export type { KeyboardAvoidingProps } from './props'
|
|
71
91
|
export { useSafeAreaInsets } from './safeAreaInsets.macos.tsrx'
|
|
72
92
|
export { useMeasure } from './useMeasure.macos.tsrx'
|
|
73
93
|
export { Meter, Heading } from './macos-extras.macos.tsrx'
|
package/src/index.mobile.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from './index.shared'
|
|
2
2
|
export { KeyboardAvoiding } from './KeyboardAvoiding.mobile.tsrx'
|
|
3
|
-
export type { KeyboardAvoidingProps } from './props'
|
|
4
3
|
|
|
5
4
|
// Keep native status-bar icon appearance synced with the effective theme scheme.
|
|
6
5
|
import './theme/status-bar-scheme.mobile'
|
package/src/index.shared.ts
CHANGED
|
@@ -9,6 +9,8 @@ export type { PanEvent, SwipeEvent, SetTranslate } from './props'
|
|
|
9
9
|
export { setTranslate } from './translate'
|
|
10
10
|
export { Spacer } from './Spacer'
|
|
11
11
|
export { Text } from './Text'
|
|
12
|
+
export { Markdown, MarkdownScreen } from './Markdown'
|
|
13
|
+
export type { MdDoc, MdNode, MdInline } from './Markdown'
|
|
12
14
|
export { RichText, RichTextSpan } from './RichText'
|
|
13
15
|
export { Pressable } from './Pressable'
|
|
14
16
|
export { Button } from './Button'
|
|
@@ -169,6 +171,7 @@ export { Tabs } from './Tabs'
|
|
|
169
171
|
export type { TabSpec } from './Tabs'
|
|
170
172
|
export { Switch } from './Switch'
|
|
171
173
|
export { SafeArea } from './SafeArea'
|
|
174
|
+
export { KeyboardAvoiding } from './KeyboardAvoiding'
|
|
172
175
|
export { Drawer } from './Drawer'
|
|
173
176
|
export { useSafeAreaInsets } from './safeAreaInsets'
|
|
174
177
|
export type { SafeAreaInsets } from './safeAreaInsets'
|
|
@@ -218,7 +221,13 @@ export {
|
|
|
218
221
|
|
|
219
222
|
export { useBackInterceptor } from './use-back'
|
|
220
223
|
|
|
221
|
-
export {
|
|
224
|
+
export {
|
|
225
|
+
deriveRouteManifest,
|
|
226
|
+
defineRoutes,
|
|
227
|
+
mergeRouteManifests,
|
|
228
|
+
manifestToJson,
|
|
229
|
+
} from './route-table'
|
|
230
|
+
|
|
222
231
|
export type {
|
|
223
232
|
BeforeLoad,
|
|
224
233
|
BeforeLoadArgs,
|
|
@@ -230,8 +239,19 @@ export type {
|
|
|
230
239
|
RouteHeadExport,
|
|
231
240
|
RouteMeta,
|
|
232
241
|
RouteManifest,
|
|
242
|
+
RouteManifestJson,
|
|
243
|
+
RouteJson,
|
|
244
|
+
RouteDataMode,
|
|
245
|
+
RouteNameOfPath,
|
|
246
|
+
RouteParamsFromSpecs,
|
|
247
|
+
RoutePathParams,
|
|
248
|
+
RoutePresentationsFromSpecs,
|
|
233
249
|
RouteSpec,
|
|
234
250
|
RouteSpecSet,
|
|
251
|
+
ManifestRouteNames,
|
|
252
|
+
ManifestRouteParams,
|
|
253
|
+
ManifestRoutePresentations,
|
|
254
|
+
SpecRouteInfo,
|
|
235
255
|
ScreenTable,
|
|
236
256
|
ModalOpenResult,
|
|
237
257
|
OpenWindowOptions,
|
|
@@ -249,6 +269,7 @@ export type {
|
|
|
249
269
|
DrawerProps,
|
|
250
270
|
GridProps,
|
|
251
271
|
ImageProps,
|
|
272
|
+
KeyboardAvoidingProps,
|
|
252
273
|
LayoutChildProps,
|
|
253
274
|
PressableProps,
|
|
254
275
|
RichTextProps,
|