Skip to content

Commit

Permalink
Merge pull request #9 from Workfront/feature/custom-outside-click-pre…
Browse files Browse the repository at this point in the history
…dicate-wf

Feature/custom outside click predicate wf
  • Loading branch information
aramvr committed Mar 29, 2023
2 parents 4bfedb9 + c47fa35 commit de2c702
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from "react";
interface Props extends React.HTMLAttributes<HTMLDivElement> {
onClickOutside: () => void;
isOutsideClick?: (event: MouseEvent) => boolean;
}

export default class ClickOutsideContainer extends React.PureComponent<Props> {
Expand All @@ -17,6 +18,9 @@ export default class ClickOutsideContainer extends React.PureComponent<Props> {
}

private clickOutside = (event: MouseEvent) => {
if (this.props.isOutsideClick && !this.props.isOutsideClick(event)) {
return;
}
if (this.wrapperRef.current !== null && !this.wrapperRef.current.contains(event.target as Node | null)) {
let node = event.target as Element | null;
while (node !== null) {
Expand All @@ -31,7 +35,7 @@ export default class ClickOutsideContainer extends React.PureComponent<Props> {
};

public render(): React.ReactNode {
const { onClickOutside, ...rest } = this.props;
const { onClickOutside, isOutsideClick, ...rest } = this.props;
return (
<div {...rest} ref={this.wrapperRef}>
{this.props.children}
Expand Down
14 changes: 12 additions & 2 deletions packages/core/src/data-editor/data-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -525,8 +525,8 @@ export interface DataEditorProps extends Props {
* Determins which keybindings are enabled.
* @group Editing
* @defaultValue is
{
{
selectAll: true,
selectRow: true,
selectColumn: true,
Expand Down Expand Up @@ -608,6 +608,14 @@ export interface DataEditorProps extends Props {
readonly customRenderers?: readonly CustomRenderer<CustomCell<any>>[];

readonly scaleToRem?: boolean;

/**
* Custom predicate function to decide whether the click event occurred outside the grid
* Especially used when custom editor is opened with the portal and is outside the grid, but there is no possibility
* to add a class "click-outside-ignore"
* If this function is supplied and returns false, the click event is ignored
*/
readonly isOutsideClick?: (e: MouseEvent) => boolean;
}

type ScrollToFn = (
Expand Down Expand Up @@ -783,6 +791,7 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
headerHeight: headerHeightIn = 36,
groupHeaderHeight: groupHeaderHeightIn = headerHeightIn,
theme: themeIn,
isOutsideClick,
} = p;

const minColumnWidth = Math.max(minColumnWidthIn, 20);
Expand Down Expand Up @@ -3644,6 +3653,7 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
imageEditorOverride={imageEditorOverride}
onFinishEditing={onFinishEditing}
markdownDivCreateNode={markdownDivCreateNode}
isOutsideClick={isOutsideClick}
/>
)}
</DataEditorContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface DataGridOverlayEditorProps {
newValue: EditableGridCell,
prevValue: GridCell
) => boolean | ValidatedGridCell;
readonly isOutsideClick?: (e: MouseEvent) => boolean;
}

const DataGridOverlayEditor: React.FunctionComponent<DataGridOverlayEditorProps> = p => {
Expand All @@ -61,6 +62,7 @@ const DataGridOverlayEditor: React.FunctionComponent<DataGridOverlayEditorProps>
validateCell,
getCellRenderer,
provideEditor,
isOutsideClick,
} = p;

const [tempValue, setTempValueRaw] = React.useState<GridCell | undefined>(forceEditMode ? content : undefined);
Expand Down Expand Up @@ -206,7 +208,11 @@ const DataGridOverlayEditor: React.FunctionComponent<DataGridOverlayEditorProps>

return createPortal(
<ThemeContext.Provider value={theme}>
<ClickOutsideContainer style={makeCSSStyle(theme)} className={className} onClickOutside={onClickOutside}>
<ClickOutsideContainer
style={makeCSSStyle(theme)}
className={className}
onClickOutside={onClickOutside}
isOutsideClick={isOutsideClick}>
<DataGridOverlayEditorStyle
ref={ref}
id={id}
Expand Down
25 changes: 25 additions & 0 deletions packages/core/test/click-outside-container.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,29 @@ describe("click-outside-container", () => {
await userEvent.click(outsideElement);
expect(onClickOutside).toHaveBeenCalledTimes(1);
});

it(`Does not trigger onClose when clicking outside but 'isOutsideClick' returns false`, async () => {
const onClickOutside = jest.fn();
const isOutsideClick = jest.fn();

const result = render(
<main>
<div>
<p>I am outside</p>
</div>
<ClickOutsideContainer onClickOutside={onClickOutside} isOutsideClick={isOutsideClick} />
</main>
);

const outsideElement = await result.findByText("I am outside");

isOutsideClick.mockReturnValueOnce(true);

expect(onClickOutside).not.toHaveBeenCalled();
await userEvent.click(outsideElement);
expect(onClickOutside).toHaveBeenCalledTimes(1);
isOutsideClick.mockReturnValueOnce(false);
await userEvent.click(outsideElement);
expect(onClickOutside).toHaveBeenCalledTimes(1);
});
});

0 comments on commit de2c702

Please sign in to comment.