@sanity/ui 1.0.0-beta.30 → 1.0.0-beta.32

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 (28) hide show
  1. package/dist/sanity-ui.esm.js +163 -95
  2. package/dist/sanity-ui.esm.js.map +1 -1
  3. package/dist/sanity-ui.js +162 -94
  4. package/dist/sanity-ui.js.map +1 -1
  5. package/dist/types/src/index.d.ts +0 -6
  6. package/package.json +4 -4
  7. package/src/__workshop__/constants.ts +31 -22
  8. package/src/components/autocomplete/autocomplete.styles.tsx +1 -10
  9. package/src/components/autocomplete/autocomplete.tsx +13 -3
  10. package/src/components/menu/__workshop__/closableMenuButton.tsx +6 -2
  11. package/src/components/menu/__workshop__/constrainedInBoundary.tsx +5 -11
  12. package/src/components/menu/__workshop__/disableFocusOnClose.tsx +7 -2
  13. package/src/components/menu/__workshop__/groups.tsx +16 -3
  14. package/src/components/menu/__workshop__/menuButton.tsx +11 -1
  15. package/src/components/menu/__workshop__/menuGroupRight.tsx +8 -1
  16. package/src/components/menu/__workshop__/onCloseMenuButton.tsx +6 -2
  17. package/src/components/menu/__workshop__/selectedItem.tsx +16 -2
  18. package/src/components/menu/__workshop__/withoutArrow.tsx +12 -10
  19. package/src/primitives/card/styles.ts +3 -1
  20. package/src/primitives/popover/__workshop__/{RightAlignedStory.tsx → AlignedStory.tsx} +19 -7
  21. package/src/primitives/popover/__workshop__/PlainStory.tsx +24 -21
  22. package/src/primitives/popover/__workshop__/TestStory.tsx +2 -0
  23. package/src/primitives/popover/__workshop__/index.ts +3 -3
  24. package/src/primitives/popover/constants.ts +10 -0
  25. package/src/primitives/popover/floating-ui/size.ts +67 -0
  26. package/src/primitives/popover/popover.tsx +43 -50
  27. package/src/primitives/popover/popoverArrow.tsx +10 -9
  28. package/src/primitives/popover/popoverCard.tsx +39 -29
@@ -0,0 +1,67 @@
1
+ import {Middleware, detectOverflow} from '@floating-ui/react-dom'
2
+
3
+ export function size(scope: {
4
+ boundaryElement: HTMLElement | null
5
+ constrainSize: boolean
6
+ matchReferenceWidth?: boolean
7
+ padding?: number
8
+ setAvailableWidth: (v: number) => void
9
+ setAvailableHeight: (v: number) => void
10
+ setReferenceWidth: (v: number) => void
11
+ }): Middleware {
12
+ const {padding = 0} = scope
13
+
14
+ return {
15
+ name: '@sanity/ui/size',
16
+ async fn(args) {
17
+ const {placement, rects} = args
18
+ const {floating, reference} = rects
19
+
20
+ const overflow = await detectOverflow(args, {
21
+ altBoundary: true,
22
+ boundary: scope.boundaryElement || undefined,
23
+ elementContext: 'floating',
24
+ padding,
25
+ rootBoundary: 'viewport',
26
+ })
27
+
28
+ let maxWidth = Infinity
29
+ let maxHeight = Infinity
30
+
31
+ if (placement.includes('top')) {
32
+ maxWidth = floating.width - (overflow.left + overflow.right)
33
+ maxHeight = floating.height - overflow.top - padding
34
+ }
35
+
36
+ if (placement.includes('right')) {
37
+ maxWidth = floating.width - overflow.right - padding
38
+ maxHeight = floating.height - (overflow.top + overflow.bottom)
39
+ }
40
+
41
+ if (placement.includes('bottom')) {
42
+ maxWidth = floating.width - (overflow.left + overflow.right)
43
+ maxHeight = floating.height - overflow.bottom - padding
44
+ }
45
+
46
+ if (placement.includes('left')) {
47
+ maxWidth = floating.width - overflow.left - padding
48
+ maxHeight = floating.height - (overflow.top + overflow.bottom)
49
+ }
50
+
51
+ if (scope.constrainSize) {
52
+ scope.setAvailableWidth(maxWidth)
53
+ scope.setAvailableHeight(maxHeight)
54
+ }
55
+
56
+ if (scope.matchReferenceWidth) {
57
+ scope.setReferenceWidth(reference.width)
58
+ }
59
+
60
+ if (!floating.width || !floating.height) {
61
+ return {reset: {rects: true}}
62
+ }
63
+
64
+ return {}
65
+ },
66
+ }
67
+ }
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  Middleware,
3
+ RootBoundary,
3
4
  arrow,
4
5
  autoUpdate,
5
6
  flip,
7
+ hide,
6
8
  offset,
7
9
  shift,
8
10
  useFloating,
9
- size as sizeMiddleware,
10
- RootBoundary,
11
11
  } from '@floating-ui/react-dom'
12
12
  import {
13
13
  cloneElement,
@@ -24,6 +24,8 @@ import {ThemeColorSchemeKey, useTheme} from '../../theme'
24
24
  import {BoxOverflow, CardTone, Placement, PopoverMargins} from '../../types'
25
25
  import {LayerProps, LayerProvider, Portal, useBoundaryElement} from '../../utils'
26
26
  import {ResponsiveRadiusProps, ResponsiveShadowProps, ResponsiveWidthProps} from '../types'
27
+ import {DEFAULT_POPOVER_DISTANCE, DEFAULT_POPOVER_PADDING} from './constants'
28
+ import {size} from './floating-ui/size'
27
29
  import {PopoverCard} from './popoverCard'
28
30
 
29
31
  /**
@@ -38,8 +40,6 @@ export interface PopoverProps
38
40
  * @beta
39
41
  */
40
42
  __unstable_margins?: PopoverMargins
41
- /** @deprecated Use `fallbackPlacements` instead. */
42
- allowedAutoPlacements?: Placement[]
43
43
  arrow?: boolean
44
44
  boundaryElement?: HTMLElement | null
45
45
  children?: React.ReactElement
@@ -56,36 +56,9 @@ export interface PopoverProps
56
56
  referenceElement?: HTMLElement | null
57
57
  matchReferenceWidth?: boolean
58
58
  scheme?: ThemeColorSchemeKey
59
- /** @deprecated No longer supported. */
60
- tether?: boolean
61
- /** @deprecated No longer supported. */
62
- tetherOffset?: number | ((...args: any[]) => number)
63
59
  tone?: CardTone
64
60
  }
65
61
 
66
- function size(scope: {
67
- boundaryElement: HTMLElement | null
68
- constrainSize: boolean
69
- matchReferenceWidth: boolean | undefined
70
- setAvailableWidth: (v: number) => void
71
- setAvailableHeight: (v: number) => void
72
- setReferenceWidth: (v: number) => void
73
- }) {
74
- return sizeMiddleware({
75
- apply(args) {
76
- if (scope.constrainSize) {
77
- scope.setAvailableWidth(args.availableWidth)
78
- scope.setAvailableHeight(args.availableHeight)
79
- }
80
-
81
- if (scope.matchReferenceWidth) {
82
- scope.setReferenceWidth(args.rects.reference.width)
83
- }
84
- },
85
- boundary: scope.boundaryElement || undefined,
86
- })
87
- }
88
-
89
62
  /** @public */
90
63
  export const Popover = memo(
91
64
  forwardRef(function Popover(
@@ -98,7 +71,6 @@ export const Popover = memo(
98
71
 
99
72
  const {
100
73
  __unstable_margins: margins,
101
- allowedAutoPlacements,
102
74
  arrow: arrowProp = true,
103
75
  boundaryElement = boundaryElementContext.element,
104
76
  children: childProp,
@@ -108,7 +80,7 @@ export const Popover = memo(
108
80
  fallbackPlacements,
109
81
  matchReferenceWidth: matchReferenceWidthProp,
110
82
  open,
111
- overflow = props.constrainSize ? 'auto' : undefined,
83
+ overflow = props.constrainSize ? 'auto' : 'hidden',
112
84
  padding: paddingProp,
113
85
  placement: placementProp = 'bottom',
114
86
  portal,
@@ -117,10 +89,8 @@ export const Popover = memo(
117
89
  referenceElement,
118
90
  scheme,
119
91
  shadow: shadowProp = 3,
120
- tether,
121
- tetherOffset,
122
92
  tone = 'inherit',
123
- width: widthProp = undefined,
93
+ width: widthProp = 'auto',
124
94
  zOffset: zOffsetProp = theme.sanity.layer?.popover.zOffset,
125
95
  ...restProps
126
96
  } = props
@@ -146,43 +116,63 @@ export const Popover = memo(
146
116
  flip({
147
117
  boundary: boundaryElement || undefined,
148
118
  fallbackPlacements,
149
- padding: 8,
119
+ padding: DEFAULT_POPOVER_PADDING,
150
120
  rootBoundary,
151
121
  })
152
122
  )
153
123
  }
154
124
 
155
125
  // Track sizes
126
+ if (constrainSize || matchReferenceWidthProp) {
127
+ ret.push(
128
+ size({
129
+ boundaryElement,
130
+ constrainSize,
131
+ matchReferenceWidth: matchReferenceWidthProp,
132
+ padding: DEFAULT_POPOVER_PADDING,
133
+ setAvailableHeight,
134
+ setAvailableWidth,
135
+ setReferenceWidth,
136
+ })
137
+ )
138
+ }
139
+
140
+ // Define distance between reference and floating element
156
141
  ret.push(
157
- size({
158
- boundaryElement,
159
- constrainSize,
160
- matchReferenceWidth: matchReferenceWidthProp,
161
- setAvailableHeight,
162
- setAvailableWidth,
163
- setReferenceWidth,
142
+ offset({
143
+ mainAxis: arrowProp ? DEFAULT_POPOVER_DISTANCE : 0,
164
144
  })
165
145
  )
166
146
 
167
- // Define distance between reference and floating element
168
- ret.push(offset({mainAxis: arrowProp ? 4 : 0}))
169
-
170
147
  // Shift the popover so its sits with the boundary eleement
171
148
  if (preventOverflow) {
172
149
  ret.push(
173
150
  shift({
174
151
  boundary: boundaryElement || undefined,
175
152
  rootBoundary,
176
- padding: 8,
153
+ padding: DEFAULT_POPOVER_PADDING,
177
154
  })
178
155
  )
179
156
  }
180
157
 
181
158
  // Place arrow
182
159
  if (arrowProp) {
183
- ret.push(arrow({element: arrowRef, padding: 4}))
160
+ ret.push(
161
+ arrow({
162
+ element: arrowRef,
163
+ padding: DEFAULT_POPOVER_PADDING,
164
+ })
165
+ )
184
166
  }
185
167
 
168
+ ret.push(
169
+ hide({
170
+ boundary: boundaryElement || undefined,
171
+ padding: DEFAULT_POPOVER_PADDING,
172
+ strategy: 'referenceHidden',
173
+ })
174
+ )
175
+
186
176
  return ret
187
177
  }, [
188
178
  arrowProp,
@@ -199,6 +189,8 @@ export const Popover = memo(
199
189
  whileElementsMounted: autoUpdate,
200
190
  })
201
191
 
192
+ const referenceHidden = middlewareData.hide?.referenceHidden
193
+
202
194
  const arrowX = middlewareData.arrow?.x
203
195
  const arrowY = middlewareData.arrow?.y
204
196
 
@@ -254,7 +246,8 @@ export const Popover = memo(
254
246
  arrowY={arrowY}
255
247
  availableWidth={constrainSize ? availableWidth : undefined}
256
248
  availableHeight={constrainSize ? availableHeight : undefined}
257
- boundaryWidth={boundarySize?.width}
249
+ boundaryWidth={preventOverflow ? boundarySize?.width : undefined}
250
+ hidden={referenceHidden}
258
251
  overflow={overflow}
259
252
  padding={padding}
260
253
  placement={placement}
@@ -1,11 +1,12 @@
1
1
  import {forwardRef} from 'react'
2
2
  import styled from 'styled-components'
3
+ import {DEFAULT_POPOVER_ARROW_HEIGHT, DEFAULT_POPOVER_ARROW_WIDTH} from './constants'
3
4
 
4
5
  const Root = styled.div`
5
6
  position: absolute;
6
7
  pointer-events: none;
7
- width: 27px;
8
- height: 27px;
8
+ width: ${DEFAULT_POPOVER_ARROW_WIDTH}px;
9
+ height: ${DEFAULT_POPOVER_ARROW_WIDTH}px;
9
10
  fill: none;
10
11
 
11
12
  :empty + & {
@@ -14,15 +15,15 @@ const Root = styled.div`
14
15
 
15
16
  & > svg {
16
17
  display: block;
17
- transform-origin: 13.5px 13.5px;
18
+ transform-origin: ${DEFAULT_POPOVER_ARROW_WIDTH / 2}px ${DEFAULT_POPOVER_ARROW_WIDTH / 2}px;
18
19
  }
19
20
 
20
21
  [data-placement^='top'] > & {
21
- bottom: -27px;
22
+ bottom: -${DEFAULT_POPOVER_ARROW_WIDTH}px;
22
23
  }
23
24
 
24
25
  [data-placement^='right'] > & {
25
- left: -27px;
26
+ left: -${DEFAULT_POPOVER_ARROW_WIDTH}px;
26
27
 
27
28
  & > svg {
28
29
  transform: rotate(90deg);
@@ -30,7 +31,7 @@ const Root = styled.div`
30
31
  }
31
32
 
32
33
  [data-placement^='left'] > & {
33
- right: -27px;
34
+ right: -${DEFAULT_POPOVER_ARROW_WIDTH}px;
34
35
 
35
36
  & > svg {
36
37
  transform: rotate(-90deg);
@@ -38,7 +39,7 @@ const Root = styled.div`
38
39
  }
39
40
 
40
41
  [data-placement^='bottom'] > & {
41
- top: -27px;
42
+ top: -${DEFAULT_POPOVER_ARROW_WIDTH}px;
42
43
 
43
44
  & > svg {
44
45
  transform: rotate(180deg);
@@ -61,8 +62,8 @@ export const PopoverArrow = forwardRef(function PopoverArrow(
61
62
  return (
62
63
  <Root data-ui="Popover__arrow" {...props} ref={ref}>
63
64
  <svg
64
- width="27"
65
- height="11"
65
+ width={DEFAULT_POPOVER_ARROW_WIDTH}
66
+ height={DEFAULT_POPOVER_ARROW_HEIGHT}
66
67
  viewBox="0 0 27 11"
67
68
  fill="none"
68
69
  xmlns="http://www.w3.org/2000/svg"
@@ -2,18 +2,35 @@ import {Strategy} from '@floating-ui/react-dom'
2
2
  import React, {CSSProperties, forwardRef, memo, useMemo} from 'react'
3
3
  import styled, {CSSObject} from 'styled-components'
4
4
  import {FLOATING_STATIC_SIDES} from '../../constants'
5
+ import {ThemeProps} from '../../styles'
5
6
  import {ThemeColorSchemeKey} from '../../theme'
6
7
  import {BoxOverflow, CardTone, Placement, PopoverMargins} from '../../types'
7
8
  import {useLayer} from '../../utils'
8
- import {Box} from '../box'
9
9
  import {Card} from '../card'
10
+ import {Container} from '../container'
11
+ import {
12
+ DEFAULT_POPOVER_ARROW_WIDTH,
13
+ DEFAULT_POPOVER_MARGINS,
14
+ DEFAULT_POPOVER_PADDING,
15
+ } from './constants'
10
16
  import {PopoverArrow} from './popoverArrow'
11
17
 
12
- function popoverCardStyle(props: {$boundaryWidth?: number}): CSSObject {
18
+ function popoverCardStyle(props: {$boundaryWidth?: number} & ThemeProps): CSSObject {
13
19
  const {$boundaryWidth} = props
14
20
 
15
21
  return {
16
- maxWidth: $boundaryWidth ? `${$boundaryWidth - 16}px` : 'calc(100% - 16px)',
22
+ '&:not([hidden])': {
23
+ display: 'flex',
24
+ },
25
+
26
+ flexDirection: 'column',
27
+
28
+ width: 'max-content',
29
+ minWidth: 'min-content',
30
+ maxWidth:
31
+ typeof $boundaryWidth === 'number'
32
+ ? `${$boundaryWidth - DEFAULT_POPOVER_PADDING * 2}px`
33
+ : undefined,
17
34
  }
18
35
  }
19
36
 
@@ -25,9 +42,7 @@ const Root = memo(styled(Card)(popoverCardStyle))
25
42
  export const PopoverCard = memo(
26
43
  forwardRef(function PopoverCard(
27
44
  props: {
28
- /**
29
- * @beta
30
- */
45
+ /** @beta*/
31
46
  __unstable_margins?: PopoverMargins
32
47
  arrow: boolean
33
48
  arrowRef: React.Ref<HTMLDivElement>
@@ -69,8 +84,9 @@ export const PopoverCard = memo(
69
84
  scheme,
70
85
  shadow,
71
86
  strategy,
87
+ style,
72
88
  tone,
73
- width,
89
+ width = 'auto',
74
90
  x: xProp,
75
91
  y: yProp,
76
92
  ...restProps
@@ -78,20 +94,20 @@ export const PopoverCard = memo(
78
94
 
79
95
  const {zIndex} = useLayer()
80
96
 
81
- // top right bottom left
82
- const margins: PopoverMargins = useMemo(() => marginsProp || [0, 0, 0, 0], [marginsProp])
97
+ // Get margins: [top, right, bottom, left]
98
+ const margins: PopoverMargins = useMemo(
99
+ () => marginsProp || DEFAULT_POPOVER_MARGINS,
100
+ [marginsProp]
101
+ )
83
102
 
84
- // translate according to margins
103
+ // Translate according to margins
85
104
  const referenceWidth = referenceWidthProp
86
105
  ? referenceWidthProp - margins[1] - margins[3]
87
106
  : undefined
107
+
88
108
  const x = (xProp ?? 0) + margins[3]
89
109
  const y = (yProp ?? 0) + margins[0]
90
110
 
91
- const maxWidth = availableWidth
92
- ? Math.min(availableWidth - 8, referenceWidth || Infinity)
93
- : undefined
94
-
95
111
  const rootStyle: CSSProperties = useMemo(
96
112
  () => ({
97
113
  position: strategy,
@@ -99,17 +115,11 @@ export const PopoverCard = memo(
99
115
  left: x,
100
116
  zIndex,
101
117
  width: referenceWidth,
102
- maxWidth: referenceWidth ? undefined : maxWidth,
103
- }),
104
- [referenceWidth, maxWidth, strategy, x, y, zIndex]
105
- )
106
-
107
- const wrapperStyle: CSSProperties = useMemo(
108
- () => ({
109
- minHeight: 25,
110
- maxHeight: availableHeight ? availableHeight - 8 : undefined,
118
+ maxWidth: availableWidth,
119
+ maxHeight: availableHeight,
120
+ ...style,
111
121
  }),
112
- [availableHeight]
122
+ [availableHeight, availableWidth, referenceWidth, strategy, style, x, y, zIndex]
113
123
  )
114
124
 
115
125
  const staticSide = placement && FLOATING_STATIC_SIDES[placement.split('-')[0]]
@@ -122,7 +132,7 @@ export const PopoverCard = memo(
122
132
  bottom: undefined,
123
133
  }
124
134
 
125
- if (staticSide) style[staticSide] = -27
135
+ if (staticSide) style[staticSide] = 0 - DEFAULT_POPOVER_ARROW_WIDTH
126
136
 
127
137
  return style
128
138
  }, [arrowX, arrowY, staticSide])
@@ -139,17 +149,17 @@ export const PopoverCard = memo(
139
149
  shadow={shadow}
140
150
  style={rootStyle}
141
151
  tone={tone}
142
- $width={width}
143
152
  >
144
- <Box
153
+ <Container
145
154
  data-ui="Popover__wrapper"
155
+ flex={1}
146
156
  overflow={overflow}
147
157
  padding={padding}
148
158
  sizing="border"
149
- style={wrapperStyle}
159
+ width={width}
150
160
  >
151
161
  {children}
152
- </Box>
162
+ </Container>
153
163
 
154
164
  {arrow && <PopoverArrow ref={arrowRef} style={arrowStyle} />}
155
165
  </Root>