From e0a8f2e067f8dc871980e6ccbd7aa7e739f1a052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Curcio?= Date: Wed, 25 Jul 2018 17:33:29 -0300 Subject: [PATCH] [next] ClickOutside Component (#1757) * working on the tests Merge branch 'next' of github.com:coralproject/talk into clickoutside * 'next' of github.com:coralproject/talk: (36 commits) [next] Implement AriaInfo (#1756) e render props for TrapFocus (#1755) [ToggleShow] Fix typo and better description (#1753) Fix wrong hour pluralization Implement button active state Styling fixes Fix Playground Commit snapshots Harmonize typography Fix Flex margin bug and add examples Update package-lock.json Use explicit export Implement ButtonIcon component Remove wrong ref prop Implement new button api Read env in watchers.ts updated tests Update ToggleShow.spec.tsx ToggleShow Component Fix CI thanks to wyatt ... docz added Added simulant Added simulant unnused Merge branch 'clickoutside' of github.com:coralproject/talk into clickoutside * 'clickoutside' of github.com:coralproject/talk: (40 commits) Added simulant Added simulant docz added [next] Implement AriaInfo (#1756) e render props for TrapFocus (#1755) [ToggleShow] Fix typo and better description (#1753) Fix wrong hour pluralization Implement button active state Styling fixes Fix Playground Commit snapshots Harmonize typography Fix Flex margin bug and add examples Update package-lock.json Use explicit export Implement ButtonIcon component Remove wrong ref prop Implement new button api Read env in watchers.ts working on the tests ... unnused Merge branch 'clickoutside' of github.com:coralproject/talk into clickoutside * 'clickoutside' of github.com:coralproject/talk: (42 commits) unnused working on the tests Added simulant Added simulant docz added [next] Implement AriaInfo (#1756) e render props for TrapFocus (#1755) [ToggleShow] Fix typo and better description (#1753) Fix wrong hour pluralization Implement button active state Styling fixes Fix Playground Commit snapshots Harmonize typography Fix Flex margin bug and add examples Update package-lock.json Use explicit export Implement ButtonIcon component Remove wrong ref prop Implement new button api ... Merge branch 'clickoutside' of github.com:coralproject/talk into clickoutside * 'clickoutside' of github.com:coralproject/talk: (42 commits) unnused working on the tests Added simulant Added simulant docz added [next] Implement AriaInfo (#1756) e render props for TrapFocus (#1755) [ToggleShow] Fix typo and better description (#1753) Fix wrong hour pluralization Implement button active state Styling fixes Fix Playground Commit snapshots Harmonize typography Fix Flex margin bug and add examples Update package-lock.json Use explicit export Implement ButtonIcon component Remove wrong ref prop Implement new button api ... Merge branch 'clickoutside' of github.com:coralproject/talk into clickoutside * 'clickoutside' of github.com:coralproject/talk: (43 commits) working on the tests unnused working on the tests Added simulant Added simulant docz added [next] Implement AriaInfo (#1756) e render props for TrapFocus (#1755) [ToggleShow] Fix typo and better description (#1753) Fix wrong hour pluralization Implement button active state Styling fixes Fix Playground Commit snapshots Harmonize typography Fix Flex margin bug and add examples Update package-lock.json Use explicit export Implement ButtonIcon component Remove wrong ref prop ... * Implement passing tests * Use html as snapshot * Refactor and simplify test * Remove unused import * ts * simulant moved to devdeps --- package-lock.json | 5 ++ package.json | 1 + .../components/ClickOutside/ClickOutside.mdx | 27 ++++++++ .../ClickOutside/ClickOutside.spec.tsx | 62 +++++++++++++++++++ .../components/ClickOutside/ClickOutside.tsx | 33 ++++++++++ .../__snapshots__/ClickOutside.spec.tsx.snap | 3 + src/types/simulant.d.ts | 16 +++++ 7 files changed, 147 insertions(+) create mode 100644 src/core/client/ui/components/ClickOutside/ClickOutside.mdx create mode 100644 src/core/client/ui/components/ClickOutside/ClickOutside.spec.tsx create mode 100644 src/core/client/ui/components/ClickOutside/ClickOutside.tsx create mode 100644 src/core/client/ui/components/ClickOutside/__snapshots__/ClickOutside.spec.tsx.snap create mode 100644 src/types/simulant.d.ts diff --git a/package-lock.json b/package-lock.json index 4f66c4e68..7517b6b8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20221,6 +20221,11 @@ } } }, + "simulant": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simulant/-/simulant-0.2.2.tgz", + "integrity": "sha1-8bzlJxK2p6DaON392n6DsgsdoB4=" + }, "sinon": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.1.3.tgz", diff --git a/package.json b/package.json index b3f29fe42..61a456398 100644 --- a/package.json +++ b/package.json @@ -146,6 +146,7 @@ "relay-runtime": "github:coralproject/patched#relay-runtime", "relay-test-utils": "github:coralproject/patched#relay-test-utils", "sane": "^2.5.2", + "simulant": "^0.2.2", "sinon": "^6.1.3", "style-loader": "^0.21.0", "ts-jest": "^23.0.0", diff --git a/src/core/client/ui/components/ClickOutside/ClickOutside.mdx b/src/core/client/ui/components/ClickOutside/ClickOutside.mdx new file mode 100644 index 000000000..0d8126b5d --- /dev/null +++ b/src/core/client/ui/components/ClickOutside/ClickOutside.mdx @@ -0,0 +1,27 @@ +--- +name: ClickOutside +menu: UI Kit +--- + +import { Playground, PropsTable } from 'docz' +import ClickOutside from './ClickOutside' +import Button from '../Button/Button' + +# ClickOutside + +A Component to handle click events outside the children components. + +## Basic usage +Wrap a Component with `` and pass a function to `onClickOutside`. This function will trigger when the user +clicks outside the component. + +### Test +Click the blue background. It should trigger an alert. Nothing should happen if you click the button. + + +
+ alert('You clicked outside!')}> + + +
+
diff --git a/src/core/client/ui/components/ClickOutside/ClickOutside.spec.tsx b/src/core/client/ui/components/ClickOutside/ClickOutside.spec.tsx new file mode 100644 index 000000000..fd5ba04b8 --- /dev/null +++ b/src/core/client/ui/components/ClickOutside/ClickOutside.spec.tsx @@ -0,0 +1,62 @@ +import { mount } from "enzyme"; +import React from "react"; +import simulant from "simulant"; +import sinon from "sinon"; + +import ClickOutside from "./ClickOutside"; + +let container: HTMLElement; + +beforeAll(() => { + container = document.createElement("div"); + document.body.appendChild(container); +}); + +afterAll(() => { + document.body.removeChild(container); +}); + +it("should render correctly", () => { + const noop = () => null; + const wrapper = mount( + + Hello World! + + ); + expect(wrapper.html()).toMatchSnapshot(); + wrapper.unmount(); +}); + +it("should detect click outside", () => { + const onClickOutside = sinon.spy(); + const wrapper = mount( + + Hello World! + , + { + attachTo: container, + } + ); + simulant.fire(container, "click"); + + expect(onClickOutside.calledOnce).toEqual(true); + wrapper.unmount(); +}); + +it("should ignore click inside", () => { + const onClickOutside = sinon.spy(); + const wrapper = mount( + + + , + { + attachTo: container, + } + ); + + const target = document.getElementById("click-outside-test-button")!; + simulant.fire(target, "click"); + + expect(onClickOutside.calledOnce).toEqual(false); + wrapper.unmount(); +}); diff --git a/src/core/client/ui/components/ClickOutside/ClickOutside.tsx b/src/core/client/ui/components/ClickOutside/ClickOutside.tsx new file mode 100644 index 000000000..cf13762f0 --- /dev/null +++ b/src/core/client/ui/components/ClickOutside/ClickOutside.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import { findDOMNode } from "react-dom"; + +interface Props { + onClickOutside: () => void; + children: React.ReactNode; +} + +class ClickOutside extends React.Component { + public domNode: Element | null = null; + + public handleClick = (e: MouseEvent) => { + const { onClickOutside } = this.props; + if (!e || !this.domNode!.contains(e.target as HTMLInputElement)) { + // tslint:disable-next-line:no-unused-expression + onClickOutside && onClickOutside(); + } + }; + + public componentDidMount() { + this.domNode = findDOMNode(this) as Element; + document.addEventListener("click", this.handleClick, true); + } + + public componentWillUnmount() { + document.removeEventListener("click", this.handleClick, true); + } + + public render() { + return this.props.children; + } +} +export default ClickOutside; diff --git a/src/core/client/ui/components/ClickOutside/__snapshots__/ClickOutside.spec.tsx.snap b/src/core/client/ui/components/ClickOutside/__snapshots__/ClickOutside.spec.tsx.snap new file mode 100644 index 000000000..883a02a51 --- /dev/null +++ b/src/core/client/ui/components/ClickOutside/__snapshots__/ClickOutside.spec.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = `"Hello World!"`; diff --git a/src/types/simulant.d.ts b/src/types/simulant.d.ts new file mode 100644 index 000000000..0537e0911 --- /dev/null +++ b/src/types/simulant.d.ts @@ -0,0 +1,16 @@ +declare module "simulant" { + type SimulantEvent = {}; + + interface Simulant { + (event: string, extendedParams: Record): SimulantEvent; + fire( + target: HTMLElement, + event: string | SimulantEvent, + extendedParams?: Record + ): void; + polyfill(): void; + } + + const simulant: Simulant; + export default simulant; +}