@react-spectrum/overlays 4.1.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Popover.tsx CHANGED
@@ -10,13 +10,13 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import {AriaPopoverProps, DismissButton, usePopover} from '@react-aria/overlays';
13
+ import {AriaPopoverProps, DismissButton, PopoverAria, usePopover} from '@react-aria/overlays';
14
14
  import {classNames, useDOMRef, useStyleProps} from '@react-spectrum/utils';
15
15
  import {DOMRef, StyleProps} from '@react-types/shared';
16
16
  import {Overlay} from './Overlay';
17
17
  import {OverlayTriggerState} from '@react-stately/overlays';
18
18
  import overrideStyles from './overlays.css';
19
- import React, {forwardRef, ReactNode, RefObject, useRef, useState} from 'react';
19
+ import React, {forwardRef, MutableRefObject, ReactNode, RefObject, useRef, useState} from 'react';
20
20
  import styles from '@adobe/spectrum-css-temp/components/popover/vars.css';
21
21
  import {Underlay} from './Underlay';
22
22
  import {useLayoutEffect} from '@react-aria/utils';
@@ -28,7 +28,17 @@ interface PopoverProps extends Omit<AriaPopoverProps, 'popoverRef' | 'maxHeight'
28
28
  }
29
29
 
30
30
  interface PopoverWrapperProps extends PopoverProps {
31
- isOpen?: boolean
31
+ isOpen?: boolean,
32
+ wrapperRef: MutableRefObject<HTMLDivElement>
33
+ }
34
+
35
+ interface ArrowProps {
36
+ arrowProps: PopoverAria['arrowProps'],
37
+ isLandscape: boolean,
38
+ arrowRef?: RefObject<SVGSVGElement>,
39
+ primary: number,
40
+ secondary: number,
41
+ borderDiagonal: number
32
42
  }
33
43
 
34
44
  /**
@@ -52,10 +62,11 @@ function Popover(props: PopoverProps, ref: DOMRef<HTMLDivElement>) {
52
62
  ...otherProps
53
63
  } = props;
54
64
  let domRef = useDOMRef(ref);
65
+ let wrapperRef = useRef<HTMLDivElement>(null);
55
66
 
56
67
  return (
57
- <Overlay {...otherProps} isOpen={state.isOpen}>
58
- <PopoverWrapper ref={domRef} {...props}>
68
+ <Overlay {...otherProps} isOpen={state.isOpen} nodeRef={wrapperRef}>
69
+ <PopoverWrapper ref={domRef} {...props} wrapperRef={wrapperRef}>
59
70
  {children}
60
71
  </PopoverWrapper>
61
72
  </Overlay>
@@ -68,18 +79,27 @@ const PopoverWrapper = forwardRef((props: PopoverWrapperProps, ref: RefObject<HT
68
79
  isOpen,
69
80
  hideArrow,
70
81
  isNonModal,
71
- state
82
+ state,
83
+ wrapperRef
72
84
  } = props;
73
85
  let {styleProps} = useStyleProps(props);
74
86
 
87
+ let {size, borderWidth, arrowRef} = useArrowSize();
88
+ const borderRadius = usePopoverBorderRadius(ref);
89
+ let borderDiagonal = borderWidth * Math.SQRT2;
90
+ let primary = size + borderDiagonal;
91
+ let secondary = primary * 2;
75
92
  let {popoverProps, arrowProps, underlayProps, placement} = usePopover({
76
93
  ...props,
77
94
  popoverRef: ref,
78
- maxHeight: null
95
+ maxHeight: null,
96
+ arrowSize: hideArrow ? 0 : secondary,
97
+ arrowBoundaryOffset: borderRadius
79
98
  }, state);
80
99
 
100
+ // Attach Transition's nodeRef to outermost wrapper for node.reflow: https://github.com/reactjs/react-transition-group/blob/c89f807067b32eea6f68fd6c622190d88ced82e2/src/Transition.js#L231
81
101
  return (
82
- <>
102
+ <div ref={wrapperRef}>
83
103
  {!isNonModal && <Underlay isTransparent {...underlayProps} isOpen={isOpen} /> }
84
104
  <div
85
105
  {...styleProps}
@@ -111,54 +131,68 @@ const PopoverWrapper = forwardRef((props: PopoverWrapperProps, ref: RefObject<HT
111
131
  {!isNonModal && <DismissButton onDismiss={state.close} />}
112
132
  {children}
113
133
  {hideArrow ? null : (
114
- <Arrow arrowProps={arrowProps} direction={arrowPlacement[placement]} />
134
+ <Arrow
135
+ arrowProps={arrowProps}
136
+ isLandscape={arrowPlacement[placement] === 'bottom'}
137
+ arrowRef={arrowRef}
138
+ primary={primary}
139
+ secondary={secondary}
140
+ borderDiagonal={borderDiagonal} />
115
141
  )}
116
142
  <DismissButton onDismiss={state.close} />
117
143
  </div>
118
- </>
144
+ </div>
119
145
  );
120
146
  });
121
147
 
122
- let ROOT_2 = Math.sqrt(2);
148
+ function usePopoverBorderRadius(popoverRef: RefObject<HTMLDivElement>) {
149
+ let [borderRadius, setBorderRadius] = useState(0);
150
+ useLayoutEffect(() => {
151
+ if (popoverRef.current) {
152
+ let spectrumBorderRadius = window.getComputedStyle(popoverRef.current).borderRadius;
153
+ if (spectrumBorderRadius !== '') {
154
+ setBorderRadius(parseInt(spectrumBorderRadius, 10));
155
+ }
156
+ }
157
+ }, [popoverRef]);
158
+ return borderRadius;
159
+ }
123
160
 
124
- function Arrow(props) {
161
+ function useArrowSize() {
125
162
  let [size, setSize] = useState(20);
126
163
  let [borderWidth, setBorderWidth] = useState(1);
127
- let ref = useRef();
164
+ let arrowRef = useRef<SVGSVGElement>(null);
128
165
  // get the css value for the tip size and divide it by 2 for this arrow implementation
129
166
  useLayoutEffect(() => {
130
- if (ref.current) {
131
- let spectrumTipWidth = window.getComputedStyle(ref.current)
167
+ if (arrowRef.current) {
168
+ let spectrumTipWidth = window.getComputedStyle(arrowRef.current)
132
169
  .getPropertyValue('--spectrum-popover-tip-size');
133
170
  if (spectrumTipWidth !== '') {
134
171
  setSize(parseInt(spectrumTipWidth, 10) / 2);
135
172
  }
136
173
 
137
- let spectrumBorderWidth = window.getComputedStyle(ref.current)
174
+ let spectrumBorderWidth = window.getComputedStyle(arrowRef.current)
138
175
  .getPropertyValue('--spectrum-popover-tip-borderWidth');
139
176
  if (spectrumBorderWidth !== '') {
140
177
  setBorderWidth(parseInt(spectrumBorderWidth, 10));
141
178
  }
142
179
  }
143
- }, [ref]);
144
-
145
- let landscape = props.direction === 'top' || props.direction === 'bottom';
146
- let mirror = props.direction === 'left' || props.direction === 'top';
180
+ }, []);
181
+ return {size, borderWidth, arrowRef};
182
+ }
147
183
 
148
- let borderDiagonal = borderWidth * ROOT_2;
184
+ function Arrow(props: ArrowProps) {
185
+ let {primary, secondary, isLandscape, arrowProps, borderDiagonal, arrowRef} = props;
149
186
  let halfBorderDiagonal = borderDiagonal / 2;
150
187
 
151
- let secondary = 2 * size + 2 * borderDiagonal;
152
- let primary = size + borderDiagonal;
153
-
154
- let primaryStart = mirror ? primary : 0;
155
- let primaryEnd = mirror ? halfBorderDiagonal : primary - halfBorderDiagonal;
188
+ let primaryStart = 0;
189
+ let primaryEnd = primary - halfBorderDiagonal;
156
190
 
157
191
  let secondaryStart = halfBorderDiagonal;
158
192
  let secondaryMiddle = secondary / 2;
159
193
  let secondaryEnd = secondary - halfBorderDiagonal;
160
194
 
161
- let pathData = landscape ? [
195
+ let pathData = isLandscape ? [
162
196
  'M', secondaryStart, primaryStart,
163
197
  'L', secondaryMiddle, primaryEnd,
164
198
  'L', secondaryEnd, primaryStart
@@ -167,17 +201,15 @@ function Arrow(props) {
167
201
  'L', primaryEnd, secondaryMiddle,
168
202
  'L', primaryStart, secondaryEnd
169
203
  ];
170
- let arrowProps = props.arrowProps;
171
204
 
172
- /* use ceil because the svg needs to always accomodate the path inside it */
205
+ /* use ceil because the svg needs to always accommodate the path inside it */
173
206
  return (
174
207
  <svg
175
208
  xmlns="http://www.w3.org/svg/2000"
176
- width={Math.ceil(landscape ? secondary : primary)}
177
- height={Math.ceil(landscape ? primary : secondary)}
178
- style={props.style}
209
+ width={Math.ceil(isLandscape ? secondary : primary)}
210
+ height={Math.ceil(isLandscape ? primary : secondary)}
179
211
  className={classNames(styles, 'spectrum-Popover-tip')}
180
- ref={ref}
212
+ ref={arrowRef}
181
213
  {...arrowProps}>
182
214
  <path className={classNames(styles, 'spectrum-Popover-tip-triangle')} d={pathData.join(' ')} />
183
215
  </svg>
package/src/Tray.tsx CHANGED
@@ -17,28 +17,30 @@ import {Overlay} from './Overlay';
17
17
  import {OverlayProps} from '@react-types/overlays';
18
18
  import {OverlayTriggerState} from '@react-stately/overlays';
19
19
  import overrideStyles from './overlays.css';
20
- import React, {forwardRef, ReactNode, RefObject} from 'react';
20
+ import React, {forwardRef, MutableRefObject, ReactNode, RefObject, useRef} from 'react';
21
21
  import trayStyles from '@adobe/spectrum-css-temp/components/tray/vars.css';
22
22
  import {Underlay} from './Underlay';
23
23
  import {useViewportSize} from '@react-aria/utils';
24
24
 
25
- interface TrayProps extends AriaModalOverlayProps, StyleProps, OverlayProps {
25
+ interface TrayProps extends AriaModalOverlayProps, StyleProps, Omit<OverlayProps, 'nodeRef'> {
26
26
  children: ReactNode,
27
27
  state: OverlayTriggerState,
28
28
  isFixedHeight?: boolean
29
29
  }
30
30
 
31
31
  interface TrayWrapperProps extends TrayProps {
32
- isOpen?: boolean
32
+ isOpen?: boolean,
33
+ wrapperRef: MutableRefObject<HTMLDivElement>
33
34
  }
34
35
 
35
36
  function Tray(props: TrayProps, ref: DOMRef<HTMLDivElement>) {
36
37
  let {children, state, ...otherProps} = props;
37
38
  let domRef = useDOMRef(ref);
39
+ let wrapperRef = useRef<HTMLDivElement>(null);
38
40
 
39
41
  return (
40
- <Overlay {...otherProps} isOpen={state.isOpen}>
41
- <TrayWrapper {...props} ref={domRef}>
42
+ <Overlay {...otherProps} isOpen={state.isOpen} nodeRef={wrapperRef}>
43
+ <TrayWrapper {...props} wrapperRef={wrapperRef} ref={domRef}>
42
44
  {children}
43
45
  </TrayWrapper>
44
46
  </Overlay>
@@ -50,7 +52,8 @@ let TrayWrapper = forwardRef(function (props: TrayWrapperProps, ref: RefObject<H
50
52
  children,
51
53
  isOpen,
52
54
  isFixedHeight,
53
- state
55
+ state,
56
+ wrapperRef
54
57
  } = props;
55
58
  let {styleProps} = useStyleProps(props);
56
59
 
@@ -91,8 +94,9 @@ let TrayWrapper = forwardRef(function (props: TrayWrapperProps, ref: RefObject<H
91
94
  styleProps.className
92
95
  );
93
96
 
97
+ // Attach Transition's nodeRef to outer most wrapper for node.reflow: https://github.com/reactjs/react-transition-group/blob/c89f807067b32eea6f68fd6c622190d88ced82e2/src/Transition.js#L231
94
98
  return (
95
- <>
99
+ <div ref={wrapperRef}>
96
100
  <Underlay {...underlayProps} isOpen={isOpen} />
97
101
  <div className={wrapperClassName} style={wrapperStyle}>
98
102
  <div
@@ -106,7 +110,7 @@ let TrayWrapper = forwardRef(function (props: TrayWrapperProps, ref: RefObject<H
106
110
  <DismissButton onDismiss={state.close} />
107
111
  </div>
108
112
  </div>
109
- </>
113
+ </div>
110
114
  );
111
115
  });
112
116