@sanity/ui 4.0.0-static.33 → 4.0.0-static.35

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 (32) hide show
  1. package/dist/index.d.ts +6 -20
  2. package/dist/index.js +284 -230
  3. package/dist/index.js.map +1 -1
  4. package/package.json +1 -1
  5. package/src/core/components/dialog/Dialog.tsx +16 -7
  6. package/src/core/components/dialog/DialogCard.tsx +4 -4
  7. package/src/core/components/dialog/DialogProvider.tsx +1 -1
  8. package/src/core/components/menu/Menu.test.tsx +6 -6
  9. package/src/core/components/menu/Menu.tsx +2 -2
  10. package/src/core/components/toast/Toast.test.tsx +6 -6
  11. package/src/core/components/toast/ToastProvider.tsx +2 -2
  12. package/src/core/components/tree/Tree.tsx +2 -2
  13. package/src/core/components/tree/TreeItem.tsx +4 -4
  14. package/src/core/helpers/props.ts +0 -9
  15. package/src/core/hooks/useResponsiveProp.ts +4 -17
  16. package/src/core/index.ts +4 -5
  17. package/src/core/primitives/avatar/Avatar.tsx +2 -2
  18. package/src/core/primitives/card/CardProvider.tsx +2 -11
  19. package/src/core/primitives/card/useCard.ts +8 -3
  20. package/src/core/primitives/layer/Layer.test.tsx +6 -6
  21. package/src/core/primitives/layer/LayerProvider.tsx +3 -3
  22. package/src/core/primitives/popover/Popover.tsx +22 -17
  23. package/src/core/primitives/textInput/TextInput.tsx +73 -53
  24. package/src/core/primitives/tooltip/Tooltip.tsx +30 -20
  25. package/src/core/primitives/tooltip/tooltipDelayGroup/TooltipDelayGroupProvider.tsx +1 -3
  26. package/src/core/utils/boundaryElement/BoundaryElementContext.ts +2 -5
  27. package/src/core/utils/boundaryElement/BoundaryElementProvider.tsx +2 -4
  28. package/src/core/utils/boundaryElement/types.ts +1 -4
  29. package/src/core/utils/boundaryElement/useBoundaryElement.ts +6 -18
  30. package/src/core/utils/portal/Portal.tsx +6 -3
  31. package/src/core/utils/portal/usePortal.ts +9 -2
  32. package/src/core/utils/boundaryElement/BoundaryElement.test.tsx +0 -102
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/ui",
3
- "version": "4.0.0-static.33",
3
+ "version": "4.0.0-static.35",
4
4
  "keywords": [
5
5
  "react",
6
6
  "ui",
@@ -5,17 +5,25 @@ import {
5
5
  type ResponsiveProp,
6
6
  } from '@sanity/ui/css'
7
7
  import type {CardTone, ColorScheme, Radius} from '@sanity/ui/theme'
8
- import {type FocusEvent, type ForwardedRef, type ReactNode, useCallback, useRef} from 'react'
8
+ import {
9
+ type FocusEvent,
10
+ type ForwardedRef,
11
+ type ReactNode,
12
+ use,
13
+ useCallback,
14
+ useMemo,
15
+ useRef,
16
+ } from 'react'
9
17
 
10
18
  import {Z_OFFSETS} from '../../constants'
11
19
  import {isHTMLElement} from '../../helpers/element'
12
20
  import {focusFirstDescendant, focusLastDescendant} from '../../helpers/focus'
21
+ import {_getResponsiveProp} from '../../helpers/props'
13
22
  import {usePrefersReducedMotion} from '../../hooks/usePrefersReducedMotion'
14
- import {useResponsiveProp} from '../../hooks/useResponsiveProp'
15
23
  import {Container} from '../../primitives/container/Container'
16
24
  import {Layer, type LayerOwnProps, type LayerProps} from '../../primitives/layer/Layer'
17
25
  import type {ComponentType, Props} from '../../types'
18
- import {useBoundaryElement} from '../../utils/boundaryElement/useBoundaryElement'
26
+ import {BoundaryElementContext} from '../../utils/boundaryElement/BoundaryElementContext'
19
27
  import {Portal} from '../../utils/portal/Portal'
20
28
  import {usePortal} from '../../utils/portal/usePortal'
21
29
  import {DialogCard} from './DialogCard'
@@ -108,10 +116,11 @@ export function Dialog<E extends DialogElementType = typeof DEFAULT_DIALOG_ELEME
108
116
  const animate = prefersReducedMotion ? false : _animate
109
117
  const portal = usePortal()
110
118
  const portalElement = portalProp ? portal.elements?.[portalProp] || null : portal.element
111
- const boundaryElement = useBoundaryElement().element
112
- const cardRadius = useResponsiveProp(cardRadiusProp)
113
- const position = useResponsiveProp(positionProp)
114
- const zOffset = useResponsiveProp(zOffsetProp)
119
+ const boundaryElement = use(BoundaryElementContext)
120
+ const cardRadius = useMemo(() => _getResponsiveProp(cardRadiusProp), [cardRadiusProp])
121
+ const position = useMemo(() => _getResponsiveProp(positionProp), [positionProp])
122
+ const zOffset = useMemo(() => _getResponsiveProp(zOffsetProp), [zOffsetProp])
123
+
115
124
  const preDivRef = useRef<HTMLDivElement | null>(null)
116
125
  const postDivRef = useRef<HTMLDivElement | null>(null)
117
126
  const cardRef = useRef<HTMLDivElement | null>(null)
@@ -11,6 +11,7 @@ import {
11
11
  import {
12
12
  type ForwardedRef,
13
13
  type ReactNode,
14
+ use,
14
15
  useCallback,
15
16
  useEffect,
16
17
  useImperativeHandle,
@@ -28,7 +29,7 @@ import {Flex} from '../../primitives/flex/Flex'
28
29
  import {useLayer} from '../../primitives/layer/useLayer'
29
30
  import {Text} from '../../primitives/text/Text'
30
31
  import type {Props} from '../../types'
31
- import {useBoundaryElement} from '../../utils/boundaryElement/useBoundaryElement'
32
+ import {BoundaryElementContext} from '../../utils/boundaryElement/BoundaryElementContext'
32
33
  import {usePortal} from '../../utils/portal/usePortal'
33
34
  import {isTargetWithinScope} from './isTargetWithinScope'
34
35
 
@@ -87,11 +88,10 @@ export function DialogCard<E extends DialogCardElementType = typeof DEFAULT_DIAL
87
88
 
88
89
  const portal = usePortal()
89
90
  const portalElement = portalProp ? portal.elements?.[portalProp] || null : portal.element
90
- const boundaryElement = useBoundaryElement().element
91
+ const boundaryElement = use(BoundaryElementContext)
91
92
  const ref = useRef<HTMLDivElement | null>(null)
92
93
  const contentRef = useRef<HTMLDivElement | null>(null)
93
- const layer = useLayer()
94
- const {isTopLayer} = layer
94
+ const {isTopLayer} = useLayer()
95
95
  const labelId = `${id}_label`
96
96
  const showCloseButton = Boolean(onClose) && hideCloseButton === false
97
97
  const showHeader = Boolean(header) || showCloseButton
@@ -30,5 +30,5 @@ export function DialogProvider(props: DialogProviderProps): React.JSX.Element {
30
30
  [position, zOffset],
31
31
  )
32
32
 
33
- return <DialogContext.Provider value={contextValue}>{children}</DialogContext.Provider>
33
+ return <DialogContext value={contextValue}>{children}</DialogContext>
34
34
  }
@@ -45,9 +45,9 @@ describe('components/menu', () => {
45
45
  )
46
46
 
47
47
  return (
48
- <MenuContext.Provider value={value}>
48
+ <MenuContext value={value}>
49
49
  <Debug />
50
- </MenuContext.Provider>
50
+ </MenuContext>
51
51
  )
52
52
  }
53
53
 
@@ -77,12 +77,12 @@ describe('components/menu', () => {
77
77
 
78
78
  function Root() {
79
79
  return (
80
- <MenuContext.Provider
80
+ <MenuContext
81
81
  // @ts-expect-error - we want to test the error case
82
82
  value={undefined}
83
83
  >
84
84
  <Debug />
85
- </MenuContext.Provider>
85
+ </MenuContext>
86
86
  )
87
87
  }
88
88
 
@@ -108,12 +108,12 @@ describe('components/menu', () => {
108
108
  // NOTE: we’re testing this because the context value may be a function in the future
109
109
 
110
110
  return (
111
- <MenuContext.Provider
111
+ <MenuContext
112
112
  // @ts-expect-error - we want to test the error case
113
113
  value={() => ({version: 1})}
114
114
  >
115
115
  <Debug />
116
- </MenuContext.Provider>
116
+ </MenuContext>
117
117
  )
118
118
  }
119
119
 
@@ -153,7 +153,7 @@ export function Menu<E extends MenuElementType = typeof DEFAULT_MENU_ELEMENT>(
153
153
  )
154
154
 
155
155
  return (
156
- <MenuContext.Provider value={value}>
156
+ <MenuContext value={value}>
157
157
  <Box
158
158
  data-ui="Menu"
159
159
  {...rest}
@@ -169,6 +169,6 @@ export function Menu<E extends MenuElementType = typeof DEFAULT_MENU_ELEMENT>(
169
169
  >
170
170
  <Stack gap={gap}>{children}</Stack>
171
171
  </Box>
172
- </MenuContext.Provider>
172
+ </MenuContext>
173
173
  )
174
174
  }
@@ -26,9 +26,9 @@ describe('components/toast', () => {
26
26
  }
27
27
 
28
28
  return (
29
- <ToastContext.Provider value={value}>
29
+ <ToastContext value={value}>
30
30
  <Debug />
31
- </ToastContext.Provider>
31
+ </ToastContext>
32
32
  )
33
33
  }
34
34
 
@@ -53,12 +53,12 @@ describe('components/toast', () => {
53
53
 
54
54
  function Root() {
55
55
  return (
56
- <ToastContext.Provider
56
+ <ToastContext
57
57
  // @ts-expect-error - we want to test the error case
58
58
  value={undefined}
59
59
  >
60
60
  <Debug />
61
- </ToastContext.Provider>
61
+ </ToastContext>
62
62
  )
63
63
  }
64
64
 
@@ -84,12 +84,12 @@ describe('components/toast', () => {
84
84
  // NOTE: we’re testing this because the context value may be a function in the future
85
85
 
86
86
  return (
87
- <ToastContext.Provider
87
+ <ToastContext
88
88
  // @ts-expect-error - we want to test the error case
89
89
  value={() => ({version: 1})}
90
90
  >
91
91
  <Debug />
92
- </ToastContext.Provider>
92
+ </ToastContext>
93
93
  )
94
94
  }
95
95
 
@@ -86,7 +86,7 @@ export function ToastProvider(props: ToastProviderProps): React.JSX.Element {
86
86
  }, [])
87
87
 
88
88
  return (
89
- <ToastContext.Provider value={value}>
89
+ <ToastContext value={value}>
90
90
  {children}
91
91
  {mounted && (
92
92
  <LayerProvider zOffset={zOffset}>
@@ -107,6 +107,6 @@ export function ToastProvider(props: ToastProviderProps): React.JSX.Element {
107
107
  </ToastLayer>
108
108
  </LayerProvider>
109
109
  )}
110
- </ToastContext.Provider>
110
+ </ToastContext>
111
111
  )
112
112
  }
@@ -231,7 +231,7 @@ export function Tree<E extends TreeElementType = typeof DEFAULT_TREE_ELEMENT>(
231
231
  }, [children])
232
232
 
233
233
  return (
234
- <TreeContext.Provider value={contextValue}>
234
+ <TreeContext value={contextValue}>
235
235
  <Stack
236
236
  as="ul"
237
237
  data-ui="Tree"
@@ -244,6 +244,6 @@ export function Tree<E extends TreeElementType = typeof DEFAULT_TREE_ELEMENT>(
244
244
  >
245
245
  {children}
246
246
  </Stack>
247
- </TreeContext.Provider>
247
+ </TreeContext>
248
248
  )
249
249
  }
@@ -195,9 +195,9 @@ export function TreeItem<E extends TreeItemElementType = typeof DEFAULT_TREE_ITE
195
195
  {content}
196
196
  </Selectable>
197
197
 
198
- <TreeContext.Provider value={contextValue}>
198
+ <TreeContext value={contextValue}>
199
199
  {children && <TreeGroup hidden={!expanded}>{children}</TreeGroup>}
200
- </TreeContext.Provider>
200
+ </TreeContext>
201
201
  </Box>
202
202
  )
203
203
  }
@@ -232,9 +232,9 @@ export function TreeItem<E extends TreeItemElementType = typeof DEFAULT_TREE_ITE
232
232
  {content}
233
233
  </Selectable>
234
234
 
235
- <TreeContext.Provider value={contextValue}>
235
+ <TreeContext value={contextValue}>
236
236
  {children && <TreeGroup expanded={expanded}>{children}</TreeGroup>}
237
- </TreeContext.Provider>
237
+ </TreeContext>
238
238
  </Box>
239
239
  )
240
240
  }
@@ -4,15 +4,6 @@ import {EMPTY_ARRAY} from '../constants'
4
4
  import {isArray} from '../lib/isArray'
5
5
  import {isRecord} from '../lib/isRecord'
6
6
 
7
- /**
8
- * @internal
9
- */
10
- export function _getArrayProp<T>(val: T | T[] | undefined, defaultVal?: T[]): T[] {
11
- if (val === undefined) return defaultVal || EMPTY_ARRAY
12
-
13
- return Array.isArray(val) ? val : [val]
14
- }
15
-
16
7
  /**
17
8
  * @internal
18
9
  */
@@ -1,28 +1,15 @@
1
1
  import type {Breakpoint, ResponsiveProp} from '@sanity/ui/css'
2
- import {useState} from 'react'
2
+ import {useMemo} from 'react'
3
3
 
4
4
  import {_getResponsiveProp} from '../helpers/props'
5
5
 
6
6
  /**
7
- * This API might change. DO NOT USE IN PRODUCTION.
8
- * @beta
7
+ * @internal
8
+ * @deprecated use `_getResponsiveProp` directly instead, if necessary
9
9
  */
10
10
  export function useResponsiveProp<T>(
11
11
  val: ResponsiveProp<T> | undefined,
12
12
  defaultVal?: Partial<Record<Breakpoint, T>>,
13
13
  ): Partial<Record<Breakpoint, T>> {
14
- const [[cachedVal, cachedHash], setCache] = useState<[Partial<Record<Breakpoint, T>>, string]>(
15
- () => [_getResponsiveProp(val, defaultVal), JSON.stringify(val ?? defaultVal)],
16
- )
17
-
18
- const hash = JSON.stringify(val ?? defaultVal)
19
-
20
- if (hash !== cachedHash) {
21
- // If the cached hash has changed, update the cache right away.
22
- // Calling setState during render is fine in this case, and preferred over a useEffect loop
23
- // https://19.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes
24
- setCache([_getResponsiveProp(val, defaultVal), hash])
25
- }
26
-
27
- return cachedVal
14
+ return useMemo(() => _getResponsiveProp(val, defaultVal), [defaultVal, val])
28
15
  }
package/src/core/index.ts CHANGED
@@ -42,7 +42,6 @@ export * from './hooks/useMatchMedia'
42
42
  export * from './hooks/useMediaIndex/useMediaIndex'
43
43
  export * from './hooks/usePrefersDark'
44
44
  export * from './hooks/usePrefersReducedMotion'
45
- export * from './hooks/useResponsiveProp'
46
45
 
47
46
  // observers
48
47
  export * from './observers/elementSize'
@@ -61,7 +60,7 @@ export * from './primitives/button/types'
61
60
  export * from './primitives/card/Card'
62
61
  export * from './primitives/card/CardProvider'
63
62
  export * from './primitives/card/types'
64
- export * from './primitives/card/useCard'
63
+ export {useCard} from './primitives/card/useCard'
65
64
  export * from './primitives/checkbox/Checkbox'
66
65
  export * from './primitives/code/Code'
67
66
  export * from './primitives/container/Container'
@@ -97,18 +96,18 @@ export * from './primitives/tooltip/Tooltip'
97
96
  export * from './primitives/tooltip/tooltipDelayGroup/TooltipDelayGroupContext'
98
97
  export * from './primitives/tooltip/tooltipDelayGroup/TooltipDelayGroupProvider'
99
98
  export * from './primitives/tooltip/tooltipDelayGroup/types'
100
- export * from './primitives/tooltip/tooltipDelayGroup/useTooltipDelayGroup'
99
+ export {useTooltipDelayGroup} from './primitives/tooltip/tooltipDelayGroup/useTooltipDelayGroup'
101
100
 
102
101
  // utils
103
102
  export * from './utils/boundaryElement/BoundaryElementProvider'
104
103
  export * from './utils/boundaryElement/types'
105
- export * from './utils/boundaryElement/useBoundaryElement'
104
+ export {useBoundaryElement} from './utils/boundaryElement/useBoundaryElement'
106
105
  export * from './utils/elementQuery/ElementQuery'
107
106
  export * from './utils/ErrorBoundary'
108
107
  export * from './utils/portal/Portal'
109
108
  export * from './utils/portal/PortalProvider'
110
109
  export * from './utils/portal/types'
111
- export * from './utils/portal/usePortal'
110
+ export {usePortal} from './utils/portal/usePortal'
112
111
 
113
112
  // root
114
113
  export * from './Root'
@@ -9,7 +9,7 @@ import {
9
9
  import type {AvatarColor, AvatarSize, FontLabelSize} from '@sanity/ui/theme'
10
10
  import {useCallback, useEffect, useMemo, useState} from 'react'
11
11
 
12
- import {useResponsiveProp} from '../../hooks/useResponsiveProp'
12
+ import {_getResponsiveProp} from '../../helpers/props'
13
13
  import type {ComponentType, Props} from '../../types'
14
14
  import {Box} from '../box/Box'
15
15
  import {Label} from '../label/Label'
@@ -61,7 +61,7 @@ export function Avatar<E extends AvatarElementType = typeof DEFAULT_AVATAR_ELEME
61
61
  ...rest
62
62
  } = props as AvatarProps<typeof DEFAULT_AVATAR_ELEMENT>
63
63
 
64
- const size = useResponsiveProp(sizeProp)
64
+ const size = useMemo(() => _getResponsiveProp(sizeProp), [sizeProp])
65
65
 
66
66
  const [arrowPosition, setArrowPosition] = useState<AvatarPosition | undefined>(
67
67
  animateArrowFrom || arrowPositionProp || 'inside',
@@ -1,5 +1,5 @@
1
1
  import type {CardTone, ColorScheme} from '@sanity/ui/theme'
2
- import {type ReactNode, useMemo} from 'react'
2
+ import {type ReactNode} from 'react'
3
3
 
4
4
  import {CardContext} from './CardContext'
5
5
  import type {_CardCompatProviderComponent} from './types'
@@ -14,14 +14,5 @@ export function CardProvider(props: {
14
14
  }): React.JSX.Element {
15
15
  const {children, tone, scheme, unstable_CompatProvider} = props
16
16
 
17
- return (
18
- <CardContext.Provider
19
- value={useMemo(
20
- () => ({tone, scheme, unstable_CompatProvider}),
21
- [tone, scheme, unstable_CompatProvider],
22
- )}
23
- >
24
- {children}
25
- </CardContext.Provider>
26
- )
17
+ return <CardContext value={{tone, scheme, unstable_CompatProvider}}>{children}</CardContext>
27
18
  }
@@ -7,9 +7,14 @@ import type {CardContextValue} from './types'
7
7
  export function useCard(): CardContextValue {
8
8
  const card = use(CardContext)
9
9
 
10
- if (!card) {
11
- throw new Error('useCard(): missing context value')
12
- }
10
+ assertCardContext(card)
13
11
 
14
12
  return card
15
13
  }
14
+
15
+ /** @internal */
16
+ export function assertCardContext(card: CardContextValue | null): asserts card is CardContextValue {
17
+ if (!card) {
18
+ throw new Error('useCard(): missing context value', {cause: card})
19
+ }
20
+ }
@@ -30,9 +30,9 @@ describe('primitives/layer', () => {
30
30
  }
31
31
 
32
32
  return (
33
- <LayerContext.Provider value={value}>
33
+ <LayerContext value={value}>
34
34
  <Debug />
35
- </LayerContext.Provider>
35
+ </LayerContext>
36
36
  )
37
37
  }
38
38
 
@@ -60,12 +60,12 @@ describe('primitives/layer', () => {
60
60
 
61
61
  function Root() {
62
62
  return (
63
- <LayerContext.Provider
63
+ <LayerContext
64
64
  // @ts-expect-error - we want to test the error case
65
65
  value={undefined}
66
66
  >
67
67
  <Debug />
68
- </LayerContext.Provider>
68
+ </LayerContext>
69
69
  )
70
70
  }
71
71
 
@@ -91,12 +91,12 @@ describe('primitives/layer', () => {
91
91
  // NOTE: we’re testing this because the context value may be a function in the future
92
92
 
93
93
  return (
94
- <LayerContext.Provider
94
+ <LayerContext
95
95
  // @ts-expect-error - we want to test the error case
96
96
  value={() => ({version: 1})}
97
97
  >
98
98
  <Debug />
99
- </LayerContext.Provider>
99
+ </LayerContext>
100
100
  )
101
101
  }
102
102
 
@@ -1,8 +1,8 @@
1
1
  import type {Breakpoint, ResponsiveProp} from '@sanity/ui/css'
2
2
  import {type ReactNode, use, useCallback, useEffect, useMemo, useState} from 'react'
3
3
 
4
+ import {_getResponsiveProp} from '../../helpers/props'
4
5
  import {useMediaIndex} from '../../hooks/useMediaIndex/useMediaIndex'
5
- import {useResponsiveProp} from '../../hooks/useResponsiveProp'
6
6
  import {getLayerContext} from './getLayerContext'
7
7
  import {LayerContext} from './LayerContext'
8
8
  import type {LayerContextValue} from './types'
@@ -27,7 +27,7 @@ export function LayerProvider(props: LayerProviderProps): React.JSX.Element {
27
27
  const level = parentLevel + 1
28
28
 
29
29
  // Get z-index offset
30
- const zOffset = useResponsiveProp(zOffsetProp)
30
+ const zOffset = useMemo(() => _getResponsiveProp(zOffsetProp), [zOffsetProp])
31
31
 
32
32
  // Get responsive z-index value
33
33
  const maxMediaIndex = Object.values(zOffset).length - 1
@@ -102,5 +102,5 @@ export function LayerProvider(props: LayerProviderProps): React.JSX.Element {
102
102
  [isTopLayer, level, registerChild, size, zIndex],
103
103
  )
104
104
 
105
- return <LayerContext.Provider value={value}>{children}</LayerContext.Provider>
105
+ return <LayerContext value={value}>{children}</LayerContext>
106
106
  }
@@ -18,6 +18,7 @@ import {
18
18
  type ReactElement,
19
19
  type ReactNode,
20
20
  type Ref,
21
+ use,
21
22
  useCallback,
22
23
  useImperativeHandle,
23
24
  useMemo,
@@ -25,15 +26,16 @@ import {
25
26
  } from 'react'
26
27
 
27
28
  import {Z_OFFSETS} from '../../constants'
29
+ import {_getResponsiveProp} from '../../helpers/props'
28
30
  import {usePrefersReducedMotion} from '../../hooks/usePrefersReducedMotion'
29
- import {useResponsiveProp} from '../../hooks/useResponsiveProp'
30
31
  import {origin} from '../../middleware/origin'
31
32
  import type {ComponentType, Placement, Props} from '../../types'
32
- import {useBoundaryElement} from '../../utils/boundaryElement/useBoundaryElement'
33
+ import {BoundaryElementContext} from '../../utils/boundaryElement/BoundaryElementContext'
33
34
  import {getElementRef} from '../../utils/getElementRef'
34
35
  import {Portal} from '../../utils/portal/Portal'
36
+ import {CardContext} from '../card/CardContext'
35
37
  import {CardProvider} from '../card/CardProvider'
36
- import {useCard} from '../card/useCard'
38
+ import {assertCardContext} from '../card/useCard'
37
39
  import {type LayerOwnProps} from '../layer/Layer'
38
40
  import {useLayer} from '../layer/useLayer'
39
41
  import {
@@ -153,8 +155,6 @@ function ViewportOverlay() {
153
155
  export function Popover<E extends PopoverElementType = typeof DEFAULT_POPOVER_ELEMENT>(
154
156
  props: PopoverProps<E>,
155
157
  ): React.JSX.Element {
156
- const boundaryElementContext = useBoundaryElement()
157
-
158
158
  const {
159
159
  __unstable_margins: margins = DEFAULT_POPOVER_MARGINS,
160
160
  animate: _animate = false,
@@ -191,14 +191,12 @@ export function Popover<E extends PopoverElementType = typeof DEFAULT_POPOVER_EL
191
191
  } = props as PopoverProps<typeof DEFAULT_POPOVER_ELEMENT>
192
192
  const fallbackPlacements =
193
193
  _fallbackPlacements ?? DEFAULT_FALLBACK_PLACEMENTS[props.placement ?? 'bottom']
194
- const floatingBoundary = _floatingBoundary ?? boundaryElementContext.element
195
- const referenceBoundary = _referenceBoundary ?? boundaryElementContext.element
196
-
197
- const card = useCard()
194
+ const floatingBoundary = _floatingBoundary ?? use(BoundaryElementContext)
195
+ const referenceBoundary = _referenceBoundary ?? use(BoundaryElementContext)
198
196
 
199
197
  const prefersReducedMotion = usePrefersReducedMotion()
200
198
  const animate = prefersReducedMotion ? false : _animate
201
- const zOffset = useResponsiveProp(zOffsetProp)
199
+ const zOffset = useMemo(() => _getResponsiveProp(zOffsetProp), [zOffsetProp])
202
200
  const ref = useRef<HTMLDivElement | null>(null)
203
201
  const arrowRef = useRef<HTMLDivElement | null>(null)
204
202
  const rootBoundary: RootBoundary = 'viewport'
@@ -309,17 +307,24 @@ export function Popover<E extends PopoverElementType = typeof DEFAULT_POPOVER_EL
309
307
  </>
310
308
  )
311
309
 
312
- const children =
313
- open &&
314
- (portal ? (
310
+ let children = open ? node : null
311
+
312
+ if (open && portal) {
313
+ let resolvedTone = tone as Exclude<typeof tone, 'inherit'>
314
+ if (tone === 'inherit') {
315
+ const card = use(CardContext)
316
+ assertCardContext(card)
317
+ resolvedTone = card.tone
318
+ }
319
+
320
+ children = (
315
321
  <Portal __unstable_name={typeof portal === 'string' ? portal : undefined}>
316
- <CardProvider tone={tone === 'inherit' ? card.tone : tone} scheme={scheme ?? 'light'}>
322
+ <CardProvider tone={resolvedTone} scheme={scheme ?? 'light'}>
317
323
  {node}
318
324
  </CardProvider>
319
325
  </Portal>
320
- ) : (
321
- node
322
- ))
326
+ )
327
+ }
323
328
 
324
329
  return (
325
330
  <>