Skip to content

Commit eb97ed1

Browse files
committed
feat(toolbar): add onOutsideClick prop
Optional callback that fires when a click occurs outside the Toolbar. Useful for closing toolbars/menus on outside clicks. Adapted from upstream PR react95-io#391.
1 parent dc82574 commit eb97ed1

5 files changed

Lines changed: 72 additions & 8 deletions

File tree

dist/Toolbar/Toolbar.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
declare const Toolbar: React.ForwardRefExoticComponent<{
33
children?: React.ReactNode;
44
noPadding?: boolean | undefined;
5+
onOutsideClick?: (() => void) | undefined;
56
} & React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
67
export { Toolbar };
78
//# sourceMappingURL=Toolbar.d.ts.map

dist/Toolbar/Toolbar.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
44

55
var React = require('react');
66
var styled = require('styled-components');
7+
var useForkRef = require('../common/hooks/useForkRef.js');
78

89
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
910

@@ -16,8 +17,23 @@ const StyledToolbar = styled__default["default"].div`
1617
align-items: center;
1718
padding: ${(props) => props.$noPadding ? "0" : "4px"};
1819
`;
19-
const Toolbar = React.forwardRef(function Toolbar2({ children, noPadding = false, ...otherProps }, ref) {
20-
return React__default["default"].createElement(StyledToolbar, { "$noPadding": noPadding, ref, ...otherProps }, children);
20+
const Toolbar = React.forwardRef(function Toolbar2({ children, noPadding = false, onOutsideClick, ...otherProps }, ref) {
21+
const toolbarRef = React.useRef(null);
22+
const handleRef = useForkRef(ref, toolbarRef);
23+
React.useEffect(() => {
24+
if (!onOutsideClick) {
25+
return;
26+
}
27+
const handleOutsideClick = (e) => {
28+
var _a;
29+
if (!((_a = toolbarRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
30+
onOutsideClick();
31+
}
32+
};
33+
document.addEventListener("click", handleOutsideClick);
34+
return () => document.removeEventListener("click", handleOutsideClick);
35+
}, [onOutsideClick]);
36+
return React__default["default"].createElement(StyledToolbar, { "$noPadding": noPadding, ref: handleRef, ...otherProps }, children);
2137
});
2238
Toolbar.displayName = "Toolbar";
2339

dist/Toolbar/Toolbar.mjs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
1-
import React__default, { forwardRef } from 'react';
1+
import React__default, { forwardRef, useRef, useEffect } from 'react';
22
import styled from 'styled-components';
3+
import useForkRef from '../common/hooks/useForkRef.mjs';
34

45
const StyledToolbar = styled.div`
56
position: relative;
67
display: flex;
78
align-items: center;
89
padding: ${(props) => props.$noPadding ? "0" : "4px"};
910
`;
10-
const Toolbar = forwardRef(function Toolbar2({ children, noPadding = false, ...otherProps }, ref) {
11-
return React__default.createElement(StyledToolbar, { "$noPadding": noPadding, ref, ...otherProps }, children);
11+
const Toolbar = forwardRef(function Toolbar2({ children, noPadding = false, onOutsideClick, ...otherProps }, ref) {
12+
const toolbarRef = useRef(null);
13+
const handleRef = useForkRef(ref, toolbarRef);
14+
useEffect(() => {
15+
if (!onOutsideClick) {
16+
return;
17+
}
18+
const handleOutsideClick = (e) => {
19+
var _a;
20+
if (!((_a = toolbarRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
21+
onOutsideClick();
22+
}
23+
};
24+
document.addEventListener("click", handleOutsideClick);
25+
return () => document.removeEventListener("click", handleOutsideClick);
26+
}, [onOutsideClick]);
27+
return React__default.createElement(StyledToolbar, { "$noPadding": noPadding, ref: handleRef, ...otherProps }, children);
1228
});
1329
Toolbar.displayName = "Toolbar";
1430

src/Toolbar/Toolbar.spec.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,15 @@ describe('<Toolbar />', () => {
2626
expect(toolbar).toHaveStyleRule('padding', '0');
2727
});
2828
});
29+
30+
describe('prop: onOutsideClick', () => {
31+
it('should fire callback on outside click', () => {
32+
const mockCallBack = jest.fn();
33+
const { container } = render(<Toolbar onOutsideClick={mockCallBack} />);
34+
35+
container.click();
36+
37+
expect(mockCallBack).toHaveBeenCalled();
38+
});
39+
});
2940
});

src/Toolbar/Toolbar.tsx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import React, { forwardRef } from 'react';
1+
import React, { forwardRef, useEffect, useRef } from 'react';
22
import styled from 'styled-components';
3+
import useForkRef from '../common/hooks/useForkRef';
34

45
type ToolbarProps = {
56
children?: React.ReactNode;
67
noPadding?: boolean;
8+
onOutsideClick?: () => void;
79
} & React.HTMLAttributes<HTMLDivElement>;
810

911
type StyledToolbarProps = {
@@ -18,11 +20,29 @@ const StyledToolbar = styled.div<StyledToolbarProps>`
1820
`;
1921

2022
const Toolbar = forwardRef<HTMLDivElement, ToolbarProps>(function Toolbar(
21-
{ children, noPadding = false, ...otherProps },
23+
{ children, noPadding = false, onOutsideClick, ...otherProps },
2224
ref
2325
) {
26+
const toolbarRef = useRef<HTMLDivElement | null>(null);
27+
const handleRef = useForkRef(ref, toolbarRef);
28+
29+
useEffect(() => {
30+
if (!onOutsideClick) {
31+
return;
32+
}
33+
34+
const handleOutsideClick = (e: MouseEvent) => {
35+
if (!toolbarRef.current?.contains(e.target as Node)) {
36+
onOutsideClick();
37+
}
38+
};
39+
40+
document.addEventListener('click', handleOutsideClick);
41+
return () => document.removeEventListener('click', handleOutsideClick);
42+
}, [onOutsideClick]);
43+
2444
return (
25-
<StyledToolbar $noPadding={noPadding} ref={ref} {...otherProps}>
45+
<StyledToolbar $noPadding={noPadding} ref={handleRef} {...otherProps}>
2646
{children}
2747
</StyledToolbar>
2848
);

0 commit comments

Comments
 (0)