one 1.21.8 → 1.21.10
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/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/layouts/Stack.cjs +1 -2
- package/dist/cjs/layouts/Stack.native.js +1 -2
- package/dist/cjs/layouts/Stack.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackScreen.cjs +0 -3
- package/dist/cjs/layouts/stack-utils/StackScreen.native.js +0 -3
- package/dist/cjs/layouts/stack-utils/StackScreen.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/__tests__/composition.test.cjs +0 -205
- package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js +0 -220
- package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/index.cjs +0 -2
- package/dist/cjs/layouts/stack-utils/index.native.js +0 -2
- package/dist/cjs/layouts/stack-utils/index.native.js.map +1 -1
- package/dist/esm/image/getImageData.mjs.map +1 -1
- package/dist/esm/image/getImageData.native.js.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/layouts/Stack.mjs +2 -3
- package/dist/esm/layouts/Stack.mjs.map +1 -1
- package/dist/esm/layouts/Stack.native.js +2 -3
- package/dist/esm/layouts/Stack.native.js.map +1 -1
- package/dist/esm/layouts/stack-utils/StackScreen.mjs +0 -3
- package/dist/esm/layouts/stack-utils/StackScreen.mjs.map +1 -1
- package/dist/esm/layouts/stack-utils/StackScreen.native.js +0 -3
- package/dist/esm/layouts/stack-utils/StackScreen.native.js.map +1 -1
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.mjs +0 -205
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.mjs.map +1 -1
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.native.js +0 -220
- package/dist/esm/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -1
- package/dist/esm/layouts/stack-utils/index.mjs +1 -2
- package/dist/esm/layouts/stack-utils/index.mjs.map +1 -1
- package/dist/esm/layouts/stack-utils/index.native.js +1 -2
- package/dist/esm/layouts/stack-utils/index.native.js.map +1 -1
- package/package.json +9 -10
- package/src/index.ts +0 -11
- package/src/layouts/Stack.tsx +0 -2
- package/src/layouts/stack-utils/README.md +0 -1
- package/src/layouts/stack-utils/StackScreen.tsx +0 -7
- package/src/layouts/stack-utils/__tests__/composition.test.tsx +0 -176
- package/src/layouts/stack-utils/index.tsx +0 -16
- package/types/image/getImageData.d.ts +1 -1
- package/types/image/getImageData.d.ts.map +1 -1
- package/types/index.d.ts +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/layouts/Stack.d.ts +0 -11
- package/types/layouts/Stack.d.ts.map +1 -1
- package/types/layouts/stack-utils/StackScreen.d.ts.map +1 -1
- package/types/layouts/stack-utils/index.d.ts +1 -3
- package/types/layouts/stack-utils/index.d.ts.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackToolbar.cjs +0 -419
- package/dist/cjs/layouts/stack-utils/StackToolbar.native.js +0 -453
- package/dist/cjs/layouts/stack-utils/StackToolbar.native.js.map +0 -1
- package/dist/cjs/layouts/stack-utils/StackToolbar.types.cjs +0 -18
- package/dist/cjs/layouts/stack-utils/StackToolbar.types.native.js +0 -21
- package/dist/cjs/layouts/stack-utils/StackToolbar.types.native.js.map +0 -1
- package/dist/cjs/layouts/stack-utils/__tests__/StackToolbar.runtime.test.cjs +0 -63
- package/dist/cjs/layouts/stack-utils/__tests__/StackToolbar.runtime.test.native.js +0 -73
- package/dist/cjs/layouts/stack-utils/__tests__/StackToolbar.runtime.test.native.js.map +0 -1
- package/dist/esm/layouts/stack-utils/StackToolbar.mjs +0 -384
- package/dist/esm/layouts/stack-utils/StackToolbar.mjs.map +0 -1
- package/dist/esm/layouts/stack-utils/StackToolbar.native.js +0 -416
- package/dist/esm/layouts/stack-utils/StackToolbar.native.js.map +0 -1
- package/dist/esm/layouts/stack-utils/StackToolbar.types.mjs +0 -2
- package/dist/esm/layouts/stack-utils/StackToolbar.types.mjs.map +0 -1
- package/dist/esm/layouts/stack-utils/StackToolbar.types.native.js +0 -2
- package/dist/esm/layouts/stack-utils/StackToolbar.types.native.js.map +0 -1
- package/dist/esm/layouts/stack-utils/__tests__/StackToolbar.runtime.test.mjs +0 -40
- package/dist/esm/layouts/stack-utils/__tests__/StackToolbar.runtime.test.mjs.map +0 -1
- package/dist/esm/layouts/stack-utils/__tests__/StackToolbar.runtime.test.native.js +0 -47
- package/dist/esm/layouts/stack-utils/__tests__/StackToolbar.runtime.test.native.js.map +0 -1
- package/src/layouts/stack-utils/StackToolbar.tsx +0 -550
- package/src/layouts/stack-utils/StackToolbar.types.ts +0 -98
- package/src/layouts/stack-utils/__tests__/StackToolbar.runtime.test.tsx +0 -46
- package/types/layouts/stack-utils/StackToolbar.d.ts +0 -26
- package/types/layouts/stack-utils/StackToolbar.d.ts.map +0 -1
- package/types/layouts/stack-utils/StackToolbar.types.d.ts +0 -82
- package/types/layouts/stack-utils/StackToolbar.types.d.ts.map +0 -1
|
@@ -1,550 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
NativeStackHeaderItem,
|
|
5
|
-
NativeStackHeaderItemButton,
|
|
6
|
-
NativeStackHeaderItemMenu,
|
|
7
|
-
NativeStackHeaderItemMenuAction,
|
|
8
|
-
NativeStackHeaderItemMenuSubmenu,
|
|
9
|
-
NativeStackNavigationOptions,
|
|
10
|
-
} from '@react-navigation/native-stack'
|
|
11
|
-
import { MenuAction, ToolbarHost, ToolbarItem } from '@vxrn/native'
|
|
12
|
-
import {
|
|
13
|
-
Children,
|
|
14
|
-
createContext,
|
|
15
|
-
Fragment,
|
|
16
|
-
useContext,
|
|
17
|
-
useId,
|
|
18
|
-
useMemo,
|
|
19
|
-
type ReactNode,
|
|
20
|
-
} from 'react'
|
|
21
|
-
import { Platform, StyleSheet, type ImageSourcePropType } from 'react-native'
|
|
22
|
-
|
|
23
|
-
import type {
|
|
24
|
-
StackToolbarBadgeProps,
|
|
25
|
-
StackToolbarButtonProps,
|
|
26
|
-
StackToolbarIconProps,
|
|
27
|
-
StackToolbarItemProps,
|
|
28
|
-
StackToolbarLabelProps,
|
|
29
|
-
StackToolbarMenuActionProps,
|
|
30
|
-
StackToolbarMenuProps,
|
|
31
|
-
StackToolbarPlacement,
|
|
32
|
-
StackToolbarProps,
|
|
33
|
-
StackToolbarSearchBarSlotProps,
|
|
34
|
-
StackToolbarSpacerProps,
|
|
35
|
-
StackToolbarViewProps,
|
|
36
|
-
} from './StackToolbar.types'
|
|
37
|
-
import { useIsomorphicLayoutEffect } from '@vxrn/use-isomorphic-layout-effect'
|
|
38
|
-
import { useNavigation } from '../../router/useNavigation'
|
|
39
|
-
import { isChildOfType } from '../../utils/children'
|
|
40
|
-
|
|
41
|
-
const StackToolbarPlacementContext = createContext<StackToolbarPlacement | null>(null)
|
|
42
|
-
|
|
43
|
-
export function StackToolbarLabel(_props: StackToolbarLabelProps) {
|
|
44
|
-
return null
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function StackToolbarIcon(_props: StackToolbarIconProps) {
|
|
48
|
-
return null
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function StackToolbarBadge(_props: StackToolbarBadgeProps) {
|
|
52
|
-
return null
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
type ToolbarContent = {
|
|
56
|
-
label: string
|
|
57
|
-
icon?: StackToolbarIconProps
|
|
58
|
-
badge?: StackToolbarBadgeProps
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function getToolbarContent(
|
|
62
|
-
children: ReactNode,
|
|
63
|
-
icon?: string | ImageSourcePropType,
|
|
64
|
-
iconRenderingMode?: 'template' | 'original'
|
|
65
|
-
): ToolbarContent {
|
|
66
|
-
let label = ''
|
|
67
|
-
let iconProps: StackToolbarIconProps | undefined =
|
|
68
|
-
typeof icon === 'string'
|
|
69
|
-
? { sf: icon }
|
|
70
|
-
: icon
|
|
71
|
-
? { src: icon, renderingMode: iconRenderingMode }
|
|
72
|
-
: undefined
|
|
73
|
-
let badge: StackToolbarBadgeProps | undefined
|
|
74
|
-
|
|
75
|
-
Children.forEach(children, (child) => {
|
|
76
|
-
if (typeof child === 'string' || typeof child === 'number') {
|
|
77
|
-
label += String(child)
|
|
78
|
-
} else if (isChildOfType(child, StackToolbarLabel)) {
|
|
79
|
-
label = child.props.children ?? ''
|
|
80
|
-
} else if (isChildOfType(child, StackToolbarIcon)) {
|
|
81
|
-
iconProps = child.props
|
|
82
|
-
} else if (isChildOfType(child, StackToolbarBadge)) {
|
|
83
|
-
badge = child.props
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
return { label, icon: iconProps, badge }
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function getHeaderIcon(
|
|
91
|
-
content: ToolbarContent,
|
|
92
|
-
tintColor?: StackToolbarItemProps['tintColor']
|
|
93
|
-
) {
|
|
94
|
-
if (content.icon?.sf) {
|
|
95
|
-
return { type: 'sfSymbol' as const, name: content.icon.sf }
|
|
96
|
-
}
|
|
97
|
-
if (content.icon?.src) {
|
|
98
|
-
return {
|
|
99
|
-
type: 'image' as const,
|
|
100
|
-
source: content.icon.src,
|
|
101
|
-
tinted:
|
|
102
|
-
(content.icon.renderingMode ?? (tintColor ? 'template' : 'original')) ===
|
|
103
|
-
'template',
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if (content.icon?.xcasset) {
|
|
107
|
-
return {
|
|
108
|
-
type: 'image' as const,
|
|
109
|
-
source: { uri: content.icon.xcasset },
|
|
110
|
-
tinted:
|
|
111
|
-
(content.icon.renderingMode ?? (tintColor ? 'template' : 'original')) ===
|
|
112
|
-
'template',
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return undefined
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function getHeaderItemSharedProps(
|
|
119
|
-
props: StackToolbarButtonProps | StackToolbarMenuProps,
|
|
120
|
-
content: ToolbarContent
|
|
121
|
-
) {
|
|
122
|
-
const labelStyle = StyleSheet.flatten(props.style)
|
|
123
|
-
const badgeStyle = StyleSheet.flatten(content.badge?.style)
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
label: content.label,
|
|
127
|
-
labelStyle,
|
|
128
|
-
icon: getHeaderIcon(content, props.tintColor),
|
|
129
|
-
variant: props.variant,
|
|
130
|
-
tintColor: props.tintColor,
|
|
131
|
-
disabled: props.disabled,
|
|
132
|
-
hidesSharedBackground: props.hidesSharedBackground,
|
|
133
|
-
sharesBackground: !props.separateBackground,
|
|
134
|
-
accessibilityLabel: props.accessibilityLabel ?? content.label,
|
|
135
|
-
accessibilityHint: props.accessibilityHint,
|
|
136
|
-
badge: content.badge
|
|
137
|
-
? {
|
|
138
|
-
value: content.badge.children ?? '',
|
|
139
|
-
style: badgeStyle,
|
|
140
|
-
}
|
|
141
|
-
: undefined,
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function getMenuItems(children: ReactNode): NativeStackHeaderItemMenu['menu']['items'] {
|
|
146
|
-
return Children.toArray(children)
|
|
147
|
-
.map(
|
|
148
|
-
(
|
|
149
|
-
child
|
|
150
|
-
): NativeStackHeaderItemMenuAction | NativeStackHeaderItemMenuSubmenu | null => {
|
|
151
|
-
if (isChildOfType(child, StackToolbarMenuAction)) {
|
|
152
|
-
const content = getToolbarContent(
|
|
153
|
-
child.props.children,
|
|
154
|
-
child.props.icon,
|
|
155
|
-
child.props.iconRenderingMode
|
|
156
|
-
)
|
|
157
|
-
return {
|
|
158
|
-
type: 'action',
|
|
159
|
-
label: content.label,
|
|
160
|
-
description: child.props.subtitle,
|
|
161
|
-
icon: getHeaderIcon(content, child.props.tintColor),
|
|
162
|
-
onPress: child.props.onPress ?? (() => {}),
|
|
163
|
-
state: child.props.isOn ? 'on' : 'off',
|
|
164
|
-
disabled: child.props.disabled,
|
|
165
|
-
destructive: child.props.destructive,
|
|
166
|
-
hidden: child.props.hidden,
|
|
167
|
-
keepsMenuPresented: child.props.unstable_keepPresented,
|
|
168
|
-
discoverabilityLabel: child.props.discoverabilityLabel,
|
|
169
|
-
} as NativeStackHeaderItemMenuAction
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (isChildOfType(child, StackToolbarMenu)) {
|
|
173
|
-
const content = getToolbarContent(
|
|
174
|
-
child.props.children,
|
|
175
|
-
child.props.icon,
|
|
176
|
-
child.props.iconRenderingMode
|
|
177
|
-
)
|
|
178
|
-
return {
|
|
179
|
-
type: 'submenu',
|
|
180
|
-
label: content.label || child.props.title || '',
|
|
181
|
-
icon: getHeaderIcon(content, child.props.tintColor),
|
|
182
|
-
inline: child.props.inline,
|
|
183
|
-
layout: child.props.palette ? 'palette' : 'default',
|
|
184
|
-
destructive: child.props.destructive,
|
|
185
|
-
multiselectable: child.props.singleSelection === false,
|
|
186
|
-
items: getMenuItems(child.props.children),
|
|
187
|
-
} as NativeStackHeaderItemMenuSubmenu
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return null
|
|
191
|
-
}
|
|
192
|
-
)
|
|
193
|
-
.filter(
|
|
194
|
-
(
|
|
195
|
-
item
|
|
196
|
-
): item is NativeStackHeaderItemMenuAction | NativeStackHeaderItemMenuSubmenu =>
|
|
197
|
-
Boolean(item)
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function convertToolbarChildToHeaderItem(child: ReactNode): NativeStackHeaderItem | null {
|
|
202
|
-
if (isChildOfType(child, StackToolbarButton)) {
|
|
203
|
-
if (child.props.hidden) return null
|
|
204
|
-
const content = getToolbarContent(
|
|
205
|
-
child.props.children,
|
|
206
|
-
child.props.icon,
|
|
207
|
-
child.props.iconRenderingMode
|
|
208
|
-
)
|
|
209
|
-
return {
|
|
210
|
-
...getHeaderItemSharedProps(child.props, content),
|
|
211
|
-
type: 'button',
|
|
212
|
-
onPress: child.props.onPress ?? (() => {}),
|
|
213
|
-
selected: child.props.selected,
|
|
214
|
-
} as NativeStackHeaderItemButton
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (isChildOfType(child, StackToolbarMenu)) {
|
|
218
|
-
if (child.props.hidden) return null
|
|
219
|
-
const content = getToolbarContent(
|
|
220
|
-
child.props.children,
|
|
221
|
-
child.props.icon,
|
|
222
|
-
child.props.iconRenderingMode
|
|
223
|
-
)
|
|
224
|
-
const contentWithTitle = {
|
|
225
|
-
...content,
|
|
226
|
-
label: content.label || child.props.title || '',
|
|
227
|
-
}
|
|
228
|
-
return {
|
|
229
|
-
...getHeaderItemSharedProps(child.props, contentWithTitle),
|
|
230
|
-
type: 'menu',
|
|
231
|
-
menu: {
|
|
232
|
-
title: child.props.title,
|
|
233
|
-
multiselectable: child.props.singleSelection === false,
|
|
234
|
-
layout: child.props.palette ? 'palette' : 'default',
|
|
235
|
-
items: getMenuItems(child.props.children),
|
|
236
|
-
},
|
|
237
|
-
} as NativeStackHeaderItemMenu
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (isChildOfType(child, StackToolbarSpacer)) {
|
|
241
|
-
if (child.props.hidden) return null
|
|
242
|
-
if (child.props.width === undefined) {
|
|
243
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
244
|
-
console.warn('Stack.Toolbar.Spacer requires a width in header placements.')
|
|
245
|
-
}
|
|
246
|
-
return null
|
|
247
|
-
}
|
|
248
|
-
return { type: 'spacing', spacing: child.props.width }
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (isChildOfType(child, StackToolbarView)) {
|
|
252
|
-
if (child.props.hidden) return null
|
|
253
|
-
return {
|
|
254
|
-
type: 'custom',
|
|
255
|
-
element: <Fragment>{child.props.children}</Fragment>,
|
|
256
|
-
hidesSharedBackground: child.props.hidesSharedBackground,
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return null
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
export function appendStackToolbarPropsToOptions(
|
|
264
|
-
options: NativeStackNavigationOptions,
|
|
265
|
-
props: StackToolbarProps
|
|
266
|
-
): NativeStackNavigationOptions {
|
|
267
|
-
if (Platform.OS !== 'ios') return options
|
|
268
|
-
|
|
269
|
-
const placement = props.placement ?? 'bottom'
|
|
270
|
-
if (placement === 'bottom') {
|
|
271
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
272
|
-
console.warn(
|
|
273
|
-
'Stack.Toolbar with bottom placement must be rendered in a page component, not inside Stack.Screen.'
|
|
274
|
-
)
|
|
275
|
-
}
|
|
276
|
-
return options
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (placement !== 'left' && placement !== 'right') {
|
|
280
|
-
throw new Error(
|
|
281
|
-
`Invalid placement "${placement}" for Stack.Toolbar. Expected "left", "right", or "bottom".`
|
|
282
|
-
)
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (props.asChild) {
|
|
286
|
-
return placement === 'left'
|
|
287
|
-
? { ...options, headerShown: true, headerLeft: () => props.children }
|
|
288
|
-
: { ...options, headerShown: true, headerRight: () => props.children }
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const allChildren = Children.toArray(props.children)
|
|
292
|
-
const items = allChildren
|
|
293
|
-
.map(convertToolbarChildToHeaderItem)
|
|
294
|
-
.filter((item): item is NativeStackHeaderItem => Boolean(item))
|
|
295
|
-
|
|
296
|
-
if (process.env.NODE_ENV !== 'production' && items.length !== allChildren.length) {
|
|
297
|
-
const invalidChildren = allChildren.filter(
|
|
298
|
-
(child) =>
|
|
299
|
-
!isChildOfType(child, StackToolbarButton) &&
|
|
300
|
-
!isChildOfType(child, StackToolbarMenu) &&
|
|
301
|
-
!isChildOfType(child, StackToolbarSpacer) &&
|
|
302
|
-
!isChildOfType(child, StackToolbarView)
|
|
303
|
-
)
|
|
304
|
-
if (invalidChildren.length) {
|
|
305
|
-
console.warn(
|
|
306
|
-
`Stack.Toolbar with placement="${placement}" only accepts Stack.Toolbar.Button, Menu, Spacer, and View children.`
|
|
307
|
-
)
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const getItems = () => items
|
|
312
|
-
return placement === 'left'
|
|
313
|
-
? { ...options, headerShown: true, unstable_headerLeftItems: getItems }
|
|
314
|
-
: { ...options, headerShown: true, unstable_headerRightItems: getItems }
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function StackToolbarComponent(props: StackToolbarProps) {
|
|
318
|
-
const parentPlacement = useContext(StackToolbarPlacementContext)
|
|
319
|
-
const navigation = useNavigation()
|
|
320
|
-
const placement = props.placement ?? 'bottom'
|
|
321
|
-
const options = useMemo(
|
|
322
|
-
() => (placement === 'bottom' ? {} : appendStackToolbarPropsToOptions({}, props)),
|
|
323
|
-
[placement, props.asChild, props.children]
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
if (parentPlacement) {
|
|
327
|
-
throw new Error('Stack.Toolbar cannot be nested inside another Stack.Toolbar.')
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
useIsomorphicLayoutEffect(() => {
|
|
331
|
-
if (Platform.OS !== 'ios' || placement === 'bottom') return
|
|
332
|
-
|
|
333
|
-
navigation.setOptions(options)
|
|
334
|
-
}, [navigation, options, placement])
|
|
335
|
-
|
|
336
|
-
if (Platform.OS !== 'ios' || placement !== 'bottom') return null
|
|
337
|
-
|
|
338
|
-
return (
|
|
339
|
-
<StackToolbarPlacementContext.Provider value="bottom">
|
|
340
|
-
<ToolbarHost>{props.children}</ToolbarHost>
|
|
341
|
-
</StackToolbarPlacementContext.Provider>
|
|
342
|
-
)
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
export function StackToolbarButton(props: StackToolbarButtonProps) {
|
|
346
|
-
const placement = useContext(StackToolbarPlacementContext)
|
|
347
|
-
const identifier = useId()
|
|
348
|
-
if (Platform.OS !== 'ios') return null
|
|
349
|
-
if (!placement)
|
|
350
|
-
throw new Error('Stack.Toolbar.Button must be used inside Stack.Toolbar.')
|
|
351
|
-
|
|
352
|
-
const content = getToolbarContent(props.children, props.icon, props.iconRenderingMode)
|
|
353
|
-
const badgeStyle = StyleSheet.flatten(content.badge?.style)
|
|
354
|
-
return (
|
|
355
|
-
<ToolbarItem
|
|
356
|
-
identifier={identifier}
|
|
357
|
-
title={content.label}
|
|
358
|
-
systemImageName={content.icon?.sf}
|
|
359
|
-
xcassetName={content.icon?.xcasset}
|
|
360
|
-
image={props.image ?? content.icon?.src}
|
|
361
|
-
imageRenderingMode={
|
|
362
|
-
content.icon?.renderingMode ??
|
|
363
|
-
props.iconRenderingMode ??
|
|
364
|
-
(props.tintColor ? 'template' : 'original')
|
|
365
|
-
}
|
|
366
|
-
tintColor={props.tintColor}
|
|
367
|
-
hidesSharedBackground={props.hidesSharedBackground}
|
|
368
|
-
sharesBackground={!props.separateBackground}
|
|
369
|
-
barButtonItemStyle={props.variant === 'done' ? 'prominent' : props.variant}
|
|
370
|
-
hidden={props.hidden}
|
|
371
|
-
selected={props.selected}
|
|
372
|
-
badgeConfiguration={
|
|
373
|
-
content.badge
|
|
374
|
-
? {
|
|
375
|
-
value: content.badge.children,
|
|
376
|
-
backgroundColor: badgeStyle?.backgroundColor,
|
|
377
|
-
color: badgeStyle?.color,
|
|
378
|
-
fontFamily: badgeStyle?.fontFamily,
|
|
379
|
-
fontSize: badgeStyle?.fontSize,
|
|
380
|
-
fontWeight: badgeStyle?.fontWeight,
|
|
381
|
-
}
|
|
382
|
-
: undefined
|
|
383
|
-
}
|
|
384
|
-
titleStyle={StyleSheet.flatten(props.style)}
|
|
385
|
-
accessibilityLabel={props.accessibilityLabel ?? content.label}
|
|
386
|
-
accessibilityHint={props.accessibilityHint}
|
|
387
|
-
disabled={props.disabled}
|
|
388
|
-
onSelected={props.onPress}
|
|
389
|
-
/>
|
|
390
|
-
)
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
export function StackToolbarMenu(props: StackToolbarMenuProps) {
|
|
394
|
-
const placement = useContext(StackToolbarPlacementContext)
|
|
395
|
-
const identifier = useId()
|
|
396
|
-
if (Platform.OS !== 'ios') return null
|
|
397
|
-
if (!placement) throw new Error('Stack.Toolbar.Menu must be used inside Stack.Toolbar.')
|
|
398
|
-
|
|
399
|
-
const content = getToolbarContent(props.children, props.icon, props.iconRenderingMode)
|
|
400
|
-
const actions = Children.toArray(props.children).filter(
|
|
401
|
-
(child) =>
|
|
402
|
-
isChildOfType(child, StackToolbarMenu) ||
|
|
403
|
-
isChildOfType(child, StackToolbarMenuAction)
|
|
404
|
-
)
|
|
405
|
-
return (
|
|
406
|
-
<MenuAction
|
|
407
|
-
identifier={identifier}
|
|
408
|
-
title={props.title ?? ''}
|
|
409
|
-
label={content.label || props.title}
|
|
410
|
-
icon={content.icon?.sf}
|
|
411
|
-
xcassetName={content.icon?.xcasset}
|
|
412
|
-
image={props.image ?? content.icon?.src}
|
|
413
|
-
imageRenderingMode={
|
|
414
|
-
content.icon?.renderingMode ??
|
|
415
|
-
props.iconRenderingMode ??
|
|
416
|
-
(props.tintColor ? 'template' : 'original')
|
|
417
|
-
}
|
|
418
|
-
disabled={props.disabled}
|
|
419
|
-
destructive={props.destructive}
|
|
420
|
-
hidden={props.hidden}
|
|
421
|
-
accessibilityLabel={props.accessibilityLabel ?? (content.label || props.title)}
|
|
422
|
-
accessibilityHint={props.accessibilityHint}
|
|
423
|
-
displayInline={props.inline}
|
|
424
|
-
displayAsPalette={props.palette}
|
|
425
|
-
singleSelection={props.singleSelection}
|
|
426
|
-
preferredElementSize={props.elementSize}
|
|
427
|
-
tintColor={props.tintColor}
|
|
428
|
-
barButtonItemStyle={props.variant === 'done' ? 'prominent' : props.variant}
|
|
429
|
-
sharesBackground={!props.separateBackground}
|
|
430
|
-
hidesSharedBackground={props.hidesSharedBackground}
|
|
431
|
-
titleStyle={StyleSheet.flatten(props.style)}
|
|
432
|
-
>
|
|
433
|
-
{actions}
|
|
434
|
-
</MenuAction>
|
|
435
|
-
)
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
export function StackToolbarMenuAction(props: StackToolbarMenuActionProps) {
|
|
439
|
-
const placement = useContext(StackToolbarPlacementContext)
|
|
440
|
-
const identifier = useId()
|
|
441
|
-
if (Platform.OS !== 'ios') return null
|
|
442
|
-
if (!placement)
|
|
443
|
-
throw new Error('Stack.Toolbar.MenuAction must be used inside Stack.Toolbar.Menu.')
|
|
444
|
-
|
|
445
|
-
const content = getToolbarContent(props.children, props.icon, props.iconRenderingMode)
|
|
446
|
-
return (
|
|
447
|
-
<MenuAction
|
|
448
|
-
identifier={identifier}
|
|
449
|
-
title={content.label}
|
|
450
|
-
icon={content.icon?.sf}
|
|
451
|
-
xcassetName={content.icon?.xcasset}
|
|
452
|
-
image={props.image ?? content.icon?.src}
|
|
453
|
-
imageRenderingMode={
|
|
454
|
-
content.icon?.renderingMode ??
|
|
455
|
-
props.iconRenderingMode ??
|
|
456
|
-
(props.tintColor ? 'template' : 'original')
|
|
457
|
-
}
|
|
458
|
-
disabled={props.disabled}
|
|
459
|
-
destructive={props.destructive}
|
|
460
|
-
discoverabilityLabel={props.discoverabilityLabel}
|
|
461
|
-
subtitle={props.subtitle}
|
|
462
|
-
accessibilityLabel={props.accessibilityLabel ?? content.label}
|
|
463
|
-
accessibilityHint={props.accessibilityHint}
|
|
464
|
-
isOn={props.isOn}
|
|
465
|
-
keepPresented={props.unstable_keepPresented}
|
|
466
|
-
hidden={props.hidden}
|
|
467
|
-
onSelected={props.onPress}
|
|
468
|
-
/>
|
|
469
|
-
)
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
export function StackToolbarSpacer(props: StackToolbarSpacerProps) {
|
|
473
|
-
const placement = useContext(StackToolbarPlacementContext)
|
|
474
|
-
const identifier = useId()
|
|
475
|
-
if (Platform.OS !== 'ios') return null
|
|
476
|
-
if (!placement)
|
|
477
|
-
throw new Error('Stack.Toolbar.Spacer must be used inside Stack.Toolbar.')
|
|
478
|
-
|
|
479
|
-
return (
|
|
480
|
-
<ToolbarItem
|
|
481
|
-
identifier={identifier}
|
|
482
|
-
type={props.width === undefined ? 'fluidSpacer' : 'fixedSpacer'}
|
|
483
|
-
width={props.width}
|
|
484
|
-
hidden={props.hidden}
|
|
485
|
-
sharesBackground={props.sharesBackground}
|
|
486
|
-
/>
|
|
487
|
-
)
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
export function StackToolbarSearchBarSlot(props: StackToolbarSearchBarSlotProps) {
|
|
491
|
-
const placement = useContext(StackToolbarPlacementContext)
|
|
492
|
-
const identifier = useId()
|
|
493
|
-
if (Platform.OS !== 'ios') return null
|
|
494
|
-
if (!placement)
|
|
495
|
-
throw new Error('Stack.Toolbar.SearchBarSlot must be used inside Stack.Toolbar.')
|
|
496
|
-
|
|
497
|
-
return (
|
|
498
|
-
<ToolbarItem
|
|
499
|
-
identifier={identifier}
|
|
500
|
-
type="searchBar"
|
|
501
|
-
hidden={props.hidden}
|
|
502
|
-
hidesSharedBackground={props.hidesSharedBackground}
|
|
503
|
-
sharesBackground={!props.separateBackground}
|
|
504
|
-
/>
|
|
505
|
-
)
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
export function StackToolbarView(props: StackToolbarViewProps) {
|
|
509
|
-
const placement = useContext(StackToolbarPlacementContext)
|
|
510
|
-
const identifier = useId()
|
|
511
|
-
if (Platform.OS !== 'ios') return null
|
|
512
|
-
if (!placement) throw new Error('Stack.Toolbar.View must be used inside Stack.Toolbar.')
|
|
513
|
-
if (props.hidden) return null
|
|
514
|
-
|
|
515
|
-
return (
|
|
516
|
-
<ToolbarItem
|
|
517
|
-
identifier={identifier}
|
|
518
|
-
hidesSharedBackground={props.hidesSharedBackground}
|
|
519
|
-
sharesBackground={!props.separateBackground}
|
|
520
|
-
>
|
|
521
|
-
{props.children}
|
|
522
|
-
</ToolbarItem>
|
|
523
|
-
)
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
export const StackToolbar = Object.assign(StackToolbarComponent, {
|
|
527
|
-
Button: StackToolbarButton,
|
|
528
|
-
Menu: StackToolbarMenu,
|
|
529
|
-
MenuAction: StackToolbarMenuAction,
|
|
530
|
-
Spacer: StackToolbarSpacer,
|
|
531
|
-
SearchBarSlot: StackToolbarSearchBarSlot,
|
|
532
|
-
View: StackToolbarView,
|
|
533
|
-
Label: StackToolbarLabel,
|
|
534
|
-
Icon: StackToolbarIcon,
|
|
535
|
-
Badge: StackToolbarBadge,
|
|
536
|
-
})
|
|
537
|
-
|
|
538
|
-
export type {
|
|
539
|
-
StackToolbarBadgeProps,
|
|
540
|
-
StackToolbarButtonProps,
|
|
541
|
-
StackToolbarIconProps,
|
|
542
|
-
StackToolbarLabelProps,
|
|
543
|
-
StackToolbarMenuActionProps,
|
|
544
|
-
StackToolbarMenuProps,
|
|
545
|
-
StackToolbarPlacement,
|
|
546
|
-
StackToolbarProps,
|
|
547
|
-
StackToolbarSearchBarSlotProps,
|
|
548
|
-
StackToolbarSpacerProps,
|
|
549
|
-
StackToolbarViewProps,
|
|
550
|
-
} from './StackToolbar.types'
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react'
|
|
2
|
-
import type { ColorValue, ImageSourcePropType, StyleProp, TextStyle } from 'react-native'
|
|
3
|
-
|
|
4
|
-
export type StackToolbarPlacement = 'left' | 'right' | 'bottom'
|
|
5
|
-
|
|
6
|
-
export interface StackToolbarProps {
|
|
7
|
-
children?: ReactNode
|
|
8
|
-
placement?: StackToolbarPlacement
|
|
9
|
-
asChild?: boolean
|
|
10
|
-
/** Android-only. One's Android toolbar host is not implemented yet. */
|
|
11
|
-
disableImePadding?: boolean
|
|
12
|
-
/** Android-only. One's Android toolbar host is not implemented yet. */
|
|
13
|
-
tintColor?: ColorValue
|
|
14
|
-
/** Android-only. One's Android toolbar host is not implemented yet. */
|
|
15
|
-
backgroundColor?: ColorValue
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface StackToolbarIconProps {
|
|
19
|
-
src?: ImageSourcePropType
|
|
20
|
-
sf?: string
|
|
21
|
-
xcasset?: string
|
|
22
|
-
renderingMode?: 'template' | 'original'
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface StackToolbarLabelProps {
|
|
26
|
-
children?: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface StackToolbarBadgeProps {
|
|
30
|
-
children?: string
|
|
31
|
-
style?: StyleProp<
|
|
32
|
-
Pick<
|
|
33
|
-
TextStyle,
|
|
34
|
-
'fontFamily' | 'fontSize' | 'fontWeight' | 'color' | 'backgroundColor'
|
|
35
|
-
>
|
|
36
|
-
>
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface StackToolbarItemProps {
|
|
40
|
-
children?: ReactNode
|
|
41
|
-
icon?: string | ImageSourcePropType
|
|
42
|
-
iconRenderingMode?: 'template' | 'original'
|
|
43
|
-
tintColor?: ColorValue
|
|
44
|
-
hidden?: boolean
|
|
45
|
-
disabled?: boolean
|
|
46
|
-
accessibilityLabel?: string
|
|
47
|
-
accessibilityHint?: string
|
|
48
|
-
hidesSharedBackground?: boolean
|
|
49
|
-
separateBackground?: boolean
|
|
50
|
-
style?: StyleProp<TextStyle>
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface StackToolbarButtonProps extends StackToolbarItemProps {
|
|
54
|
-
image?: ImageSourcePropType
|
|
55
|
-
onPress?: () => void
|
|
56
|
-
selected?: boolean
|
|
57
|
-
variant?: 'plain' | 'done' | 'prominent'
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface StackToolbarMenuProps extends StackToolbarItemProps {
|
|
61
|
-
image?: ImageSourcePropType
|
|
62
|
-
destructive?: boolean
|
|
63
|
-
title?: string
|
|
64
|
-
inline?: boolean
|
|
65
|
-
palette?: boolean
|
|
66
|
-
singleSelection?: boolean
|
|
67
|
-
elementSize?: 'auto' | 'small' | 'medium' | 'large'
|
|
68
|
-
variant?: 'plain' | 'done' | 'prominent'
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface StackToolbarMenuActionProps extends StackToolbarItemProps {
|
|
72
|
-
image?: ImageSourcePropType
|
|
73
|
-
destructive?: boolean
|
|
74
|
-
discoverabilityLabel?: string
|
|
75
|
-
subtitle?: string
|
|
76
|
-
isOn?: boolean
|
|
77
|
-
onPress?: () => void
|
|
78
|
-
unstable_keepPresented?: boolean
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface StackToolbarSpacerProps {
|
|
82
|
-
width?: number
|
|
83
|
-
hidden?: boolean
|
|
84
|
-
sharesBackground?: boolean
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface StackToolbarSearchBarSlotProps {
|
|
88
|
-
hidden?: boolean
|
|
89
|
-
hidesSharedBackground?: boolean
|
|
90
|
-
separateBackground?: boolean
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export interface StackToolbarViewProps {
|
|
94
|
-
children?: ReactNode
|
|
95
|
-
hidden?: boolean
|
|
96
|
-
hidesSharedBackground?: boolean
|
|
97
|
-
separateBackground?: boolean
|
|
98
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import TestRenderer, { act } from 'react-test-renderer'
|
|
3
|
-
import { Platform } from 'react-native'
|
|
4
|
-
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
-
|
|
6
|
-
const setOptions = vi.fn()
|
|
7
|
-
|
|
8
|
-
vi.mock('../../../router/useNavigation', () => ({
|
|
9
|
-
useNavigation: () => ({ setOptions }),
|
|
10
|
-
}))
|
|
11
|
-
|
|
12
|
-
import { StackToolbar } from '../StackToolbar'
|
|
13
|
-
|
|
14
|
-
describe('StackToolbar runtime options', () => {
|
|
15
|
-
const originalOS = Platform.OS
|
|
16
|
-
|
|
17
|
-
afterEach(() => {
|
|
18
|
-
;(Platform as any).OS = originalOS
|
|
19
|
-
setOptions.mockClear()
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
it('does not write undefined header overrides when the toolbar unmounts', () => {
|
|
23
|
-
;(Platform as any).OS = 'ios'
|
|
24
|
-
let renderer: TestRenderer.ReactTestRenderer
|
|
25
|
-
|
|
26
|
-
act(() => {
|
|
27
|
-
renderer = TestRenderer.create(
|
|
28
|
-
<StackToolbar placement="right">
|
|
29
|
-
<StackToolbar.Button icon="bell" />
|
|
30
|
-
</StackToolbar>
|
|
31
|
-
)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
expect(setOptions).toHaveBeenCalledTimes(1)
|
|
35
|
-
expect(setOptions).toHaveBeenLastCalledWith(
|
|
36
|
-
expect.objectContaining({
|
|
37
|
-
headerShown: true,
|
|
38
|
-
unstable_headerRightItems: expect.any(Function),
|
|
39
|
-
})
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
act(() => renderer!.unmount())
|
|
43
|
-
|
|
44
|
-
expect(setOptions).toHaveBeenCalledTimes(1)
|
|
45
|
-
})
|
|
46
|
-
})
|