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.
Files changed (78) hide show
  1. package/dist/cjs/index.native.js.map +1 -1
  2. package/dist/cjs/layouts/Stack.cjs +1 -2
  3. package/dist/cjs/layouts/Stack.native.js +1 -2
  4. package/dist/cjs/layouts/Stack.native.js.map +1 -1
  5. package/dist/cjs/layouts/stack-utils/StackScreen.cjs +0 -3
  6. package/dist/cjs/layouts/stack-utils/StackScreen.native.js +0 -3
  7. package/dist/cjs/layouts/stack-utils/StackScreen.native.js.map +1 -1
  8. package/dist/cjs/layouts/stack-utils/__tests__/composition.test.cjs +0 -205
  9. package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js +0 -220
  10. package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -1
  11. package/dist/cjs/layouts/stack-utils/index.cjs +0 -2
  12. package/dist/cjs/layouts/stack-utils/index.native.js +0 -2
  13. package/dist/cjs/layouts/stack-utils/index.native.js.map +1 -1
  14. package/dist/esm/image/getImageData.mjs.map +1 -1
  15. package/dist/esm/image/getImageData.native.js.map +1 -1
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/index.mjs.map +1 -1
  18. package/dist/esm/index.native.js.map +1 -1
  19. package/dist/esm/layouts/Stack.mjs +2 -3
  20. package/dist/esm/layouts/Stack.mjs.map +1 -1
  21. package/dist/esm/layouts/Stack.native.js +2 -3
  22. package/dist/esm/layouts/Stack.native.js.map +1 -1
  23. package/dist/esm/layouts/stack-utils/StackScreen.mjs +0 -3
  24. package/dist/esm/layouts/stack-utils/StackScreen.mjs.map +1 -1
  25. package/dist/esm/layouts/stack-utils/StackScreen.native.js +0 -3
  26. package/dist/esm/layouts/stack-utils/StackScreen.native.js.map +1 -1
  27. package/dist/esm/layouts/stack-utils/__tests__/composition.test.mjs +0 -205
  28. package/dist/esm/layouts/stack-utils/__tests__/composition.test.mjs.map +1 -1
  29. package/dist/esm/layouts/stack-utils/__tests__/composition.test.native.js +0 -220
  30. package/dist/esm/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -1
  31. package/dist/esm/layouts/stack-utils/index.mjs +1 -2
  32. package/dist/esm/layouts/stack-utils/index.mjs.map +1 -1
  33. package/dist/esm/layouts/stack-utils/index.native.js +1 -2
  34. package/dist/esm/layouts/stack-utils/index.native.js.map +1 -1
  35. package/package.json +9 -10
  36. package/src/index.ts +0 -11
  37. package/src/layouts/Stack.tsx +0 -2
  38. package/src/layouts/stack-utils/README.md +0 -1
  39. package/src/layouts/stack-utils/StackScreen.tsx +0 -7
  40. package/src/layouts/stack-utils/__tests__/composition.test.tsx +0 -176
  41. package/src/layouts/stack-utils/index.tsx +0 -16
  42. package/types/image/getImageData.d.ts +1 -1
  43. package/types/image/getImageData.d.ts.map +1 -1
  44. package/types/index.d.ts +1 -1
  45. package/types/index.d.ts.map +1 -1
  46. package/types/layouts/Stack.d.ts +0 -11
  47. package/types/layouts/Stack.d.ts.map +1 -1
  48. package/types/layouts/stack-utils/StackScreen.d.ts.map +1 -1
  49. package/types/layouts/stack-utils/index.d.ts +1 -3
  50. package/types/layouts/stack-utils/index.d.ts.map +1 -1
  51. package/dist/cjs/layouts/stack-utils/StackToolbar.cjs +0 -419
  52. package/dist/cjs/layouts/stack-utils/StackToolbar.native.js +0 -453
  53. package/dist/cjs/layouts/stack-utils/StackToolbar.native.js.map +0 -1
  54. package/dist/cjs/layouts/stack-utils/StackToolbar.types.cjs +0 -18
  55. package/dist/cjs/layouts/stack-utils/StackToolbar.types.native.js +0 -21
  56. package/dist/cjs/layouts/stack-utils/StackToolbar.types.native.js.map +0 -1
  57. package/dist/cjs/layouts/stack-utils/__tests__/StackToolbar.runtime.test.cjs +0 -63
  58. package/dist/cjs/layouts/stack-utils/__tests__/StackToolbar.runtime.test.native.js +0 -73
  59. package/dist/cjs/layouts/stack-utils/__tests__/StackToolbar.runtime.test.native.js.map +0 -1
  60. package/dist/esm/layouts/stack-utils/StackToolbar.mjs +0 -384
  61. package/dist/esm/layouts/stack-utils/StackToolbar.mjs.map +0 -1
  62. package/dist/esm/layouts/stack-utils/StackToolbar.native.js +0 -416
  63. package/dist/esm/layouts/stack-utils/StackToolbar.native.js.map +0 -1
  64. package/dist/esm/layouts/stack-utils/StackToolbar.types.mjs +0 -2
  65. package/dist/esm/layouts/stack-utils/StackToolbar.types.mjs.map +0 -1
  66. package/dist/esm/layouts/stack-utils/StackToolbar.types.native.js +0 -2
  67. package/dist/esm/layouts/stack-utils/StackToolbar.types.native.js.map +0 -1
  68. package/dist/esm/layouts/stack-utils/__tests__/StackToolbar.runtime.test.mjs +0 -40
  69. package/dist/esm/layouts/stack-utils/__tests__/StackToolbar.runtime.test.mjs.map +0 -1
  70. package/dist/esm/layouts/stack-utils/__tests__/StackToolbar.runtime.test.native.js +0 -47
  71. package/dist/esm/layouts/stack-utils/__tests__/StackToolbar.runtime.test.native.js.map +0 -1
  72. package/src/layouts/stack-utils/StackToolbar.tsx +0 -550
  73. package/src/layouts/stack-utils/StackToolbar.types.ts +0 -98
  74. package/src/layouts/stack-utils/__tests__/StackToolbar.runtime.test.tsx +0 -46
  75. package/types/layouts/stack-utils/StackToolbar.d.ts +0 -26
  76. package/types/layouts/stack-utils/StackToolbar.d.ts.map +0 -1
  77. package/types/layouts/stack-utils/StackToolbar.types.d.ts +0 -82
  78. 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
- })