Skip to content

Commit ef3cce8

Browse files
authored
fix(Popover): use Bootstrap default offsets (react-bootstrap#5663)
* fix(Popover): use Bootstrap default offsets * Add comment about useOverlayOffset Add offset constant into popover Move overlay types into another types.tsx to prevent circular dependency warning
1 parent d707ca3 commit ef3cce8

File tree

7 files changed

+111
-34
lines changed

7 files changed

+111
-34
lines changed

src/Overlay.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,10 @@ import BaseOverlay, {
66
} from 'react-overlays/Overlay';
77
import safeFindDOMNode from 'react-overlays/safeFindDOMNode';
88
import { componentOrElement, elementType } from 'prop-types-extra';
9-
import usePopperMarginModifiers from './usePopperMarginModifiers';
9+
import useOverlayOffset from './useOverlayOffset';
1010
import Fade from './Fade';
1111
import { TransitionType } from './helpers';
12-
13-
export type Placement = import('react-overlays/usePopper').Placement;
14-
15-
export type ArrowProps = {
16-
ref: React.RefCallback<HTMLElement>;
17-
style: React.CSSProperties;
18-
};
12+
import { ArrowProps, Placement } from './types';
1913

2014
export interface OverlayInjectedProps {
2115
ref: React.RefCallback<HTMLElement>;
@@ -166,7 +160,7 @@ function Overlay({
166160
...outerProps
167161
}: OverlayProps) {
168162
const popperRef = useRef({});
169-
const [ref, marginModifiers] = usePopperMarginModifiers();
163+
const [ref, modifiers] = useOverlayOffset();
170164

171165
const actualTransition = transition === true ? Fade : transition || null;
172166

@@ -176,7 +170,7 @@ function Overlay({
176170
ref={ref}
177171
popperConfig={{
178172
...popperConfig,
179-
modifiers: marginModifiers.concat(popperConfig.modifiers || []),
173+
modifiers: modifiers.concat(popperConfig.modifiers || []),
180174
}}
181175
transition={actualTransition as any}
182176
>

src/Popover.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import isRequiredForA11y from 'prop-types-extra/lib/isRequiredForA11y';
55
import { useBootstrapPrefix } from './ThemeProvider';
66
import PopoverTitle from './PopoverTitle';
77
import PopoverBody from './PopoverBody';
8-
import { ArrowProps, Placement } from './Overlay';
8+
import { ArrowProps, Placement } from './types';
99
import { BsPrefixProps } from './helpers';
1010

1111
export interface PopoverProps
@@ -136,4 +136,8 @@ Popover.defaultProps = defaultProps;
136136
export default Object.assign(Popover, {
137137
Title: PopoverTitle,
138138
Body: PopoverBody,
139+
140+
// Default popover offset.
141+
// https://github.com/twbs/bootstrap/blob/5c32767e0e0dbac2d934bcdee03719a65d3f1187/js/src/popover.js#L28
142+
POPPER_OFFSET: [0, 8] as const,
139143
});

src/Tooltip.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import React from 'react';
33
import PropTypes from 'prop-types';
44
import isRequiredForA11y from 'prop-types-extra/lib/isRequiredForA11y';
55
import { useBootstrapPrefix } from './ThemeProvider';
6-
7-
import { ArrowProps, Placement } from './Overlay';
6+
import { ArrowProps, Placement } from './types';
87
import { BsPrefixProps } from './helpers';
98

109
export interface TooltipProps

src/types.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,10 @@ export type Color =
3030
| 'light'
3131
| 'white'
3232
| 'muted';
33+
34+
export type Placement = import('react-overlays/usePopper').Placement;
35+
36+
export type ArrowProps = {
37+
ref: React.RefCallback<HTMLElement>;
38+
style: React.CSSProperties;
39+
};

src/useOverlayOffset.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useMemo, useRef } from 'react';
2+
import hasClass from 'dom-helpers/hasClass';
3+
import { Options } from 'react-overlays/usePopper';
4+
import { useBootstrapPrefix } from './ThemeProvider';
5+
import Popover from './Popover';
6+
7+
// This is meant for internal use.
8+
// This applies a custom offset to the overlay if it's a popover.
9+
export default function useOverlayOffset(): [
10+
React.RefObject<HTMLElement>,
11+
Options['modifiers'],
12+
] {
13+
const overlayRef = useRef<HTMLDivElement | null>(null);
14+
const popoverClass = useBootstrapPrefix(undefined, 'popover');
15+
16+
const offset = useMemo(
17+
() => ({
18+
name: 'offset',
19+
options: {
20+
offset: () => {
21+
if (
22+
overlayRef.current &&
23+
hasClass(overlayRef.current, popoverClass)
24+
) {
25+
return Popover.POPPER_OFFSET;
26+
}
27+
return [0, 0];
28+
},
29+
},
30+
}),
31+
[popoverClass],
32+
);
33+
34+
return [overlayRef, [offset]];
35+
}

test/useOverlayOffsetSpec.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React, { useImperativeHandle } from 'react';
2+
import { mount } from 'enzyme';
3+
4+
import Popover from '../src/Popover';
5+
import Tooltip from '../src/Tooltip';
6+
import useOverlayOffset from '../src/useOverlayOffset';
7+
8+
describe('useOverlayOffset', () => {
9+
const Wrapper = React.forwardRef((props, outerRef) => {
10+
const [ref, modifiers] = useOverlayOffset();
11+
12+
useImperativeHandle(outerRef, () => ({
13+
modifiers,
14+
}));
15+
16+
return React.cloneElement(props.children, {
17+
ref,
18+
});
19+
});
20+
21+
it('should have offset of [0, 8] for Popovers', () => {
22+
const ref = React.createRef();
23+
24+
mount(
25+
<Wrapper ref={ref}>
26+
<Popover id="test-popover" />
27+
</Wrapper>,
28+
);
29+
30+
const offset = ref.current.modifiers[0].options.offset();
31+
expect(offset).to.eql([0, 8]);
32+
});
33+
34+
it('should have offset of [0, 0] for Tooltips', () => {
35+
const ref = React.createRef();
36+
37+
mount(
38+
<Wrapper ref={ref}>
39+
<Tooltip id="test-tooltip" />
40+
</Wrapper>,
41+
);
42+
43+
const offset = ref.current.modifiers[0].options.offset();
44+
expect(offset).to.eql([0, 0]);
45+
});
46+
47+
it('should have offset of [0, 0] for any overlay', () => {
48+
const ref = React.createRef();
49+
50+
mount(
51+
<Wrapper ref={ref}>
52+
<div>test</div>
53+
</Wrapper>,
54+
);
55+
56+
const offset = ref.current.modifiers[0].options.offset();
57+
expect(offset).to.eql([0, 0]);
58+
});
59+
});

test/usePopperMarginModifiersSpec.js

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)