From 4ce383a7c5c8a0779f7327e0ea55f424b6d023ec Mon Sep 17 00:00:00 2001 From: Sandy M Date: Tue, 23 Apr 2019 19:25:49 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20Ability=20to=20keep=20the=20dropdown=20?= =?UTF-8?q?open=20always=20(#241)=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #239 --- README.md | 7 ++ __snapshots__/src/index.test.js.md | 150 ++++++++++++++++++++++++++ __snapshots__/src/index.test.js.snap | Bin 3066 -> 3167 bytes src/index.js | 7 +- src/index.test.js | 13 +++ types/react-dropdown-tree-select.d.ts | 3 + 6 files changed, 177 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bf95e1f7..b89db1af 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ A lightweight and fast control to render a select component that can display hie - [radioSelect](#radioSelect) - [showPartiallySelected](#showpartiallyselected) - [showDropdown](#showDropdown) + - [showDropdownAlways](#showDropdownAlways) - [form states (disabled|readOnly)](#formstates) - [id](#id) - [Styling and Customization](#styling-and-customization) @@ -341,6 +342,12 @@ Type: `bool` (default: `false`) If set to true, shows the dropdown when rendered. This can be used to render the component with the dropdown open as its initial state. +### showDropdownAlways + +Type: `bool` + +If set to true, always shows the dropdown when rendered, and toggling dropdown will be disabled. + ### form states (disabled|readOnly) Type: `bool` (default: `false`) diff --git a/__snapshots__/src/index.test.js.md b/__snapshots__/src/index.test.js.md index 0b9b76f1..599fb5a8 100644 --- a/__snapshots__/src/index.test.js.md +++ b/__snapshots__/src/index.test.js.md @@ -407,4 +407,154 @@ Generated by [AVA](https://ava.li). /> + Snapshot 1 + +
+
+ + + +
+ { + _children: [ + 'rdts-0-0', + 'rdts-0-1', + ], + _depth: 0, + _id: 'rdts-0', + children: undefined, + label: 'item1', + value: 'value1', + }, + 'rdts-0-0' => { + _children: [ + 'rdts-0-0-0', + 'rdts-0-0-1', + ], + _depth: 1, + _id: 'rdts-0-0', + _parent: 'rdts-0', + children: undefined, + label: 'item1-1', + value: 'value1-1', + }, + 'rdts-0-0-0' => { + _depth: 2, + _id: 'rdts-0-0-0', + _parent: 'rdts-0-0', + label: 'item1-1-1', + value: 'value1-1-1', + }, + 'rdts-0-0-1' => { + _depth: 2, + _id: 'rdts-0-0-1', + _parent: 'rdts-0-0', + label: 'item1-1-2', + value: 'value1-1-2', + }, + 'rdts-0-1' => { + _depth: 1, + _id: 'rdts-0-1', + _parent: 'rdts-0', + label: 'item1-2', + value: 'value1-2', + }, + 'rdts-1' => { + _children: [ + 'rdts-1-0', + 'rdts-1-1', + ], + _depth: 0, + _id: 'rdts-1', + children: undefined, + label: 'item2', + value: 'value2', + }, + 'rdts-1-0' => { + _children: [ + 'rdts-1-0-0', + 'rdts-1-0-1', + 'rdts-1-0-2', + ], + _depth: 1, + _id: 'rdts-1-0', + _parent: 'rdts-1', + children: undefined, + label: 'item2-1', + value: 'value2-1', + }, + 'rdts-1-0-0' => { + _depth: 2, + _id: 'rdts-1-0-0', + _parent: 'rdts-1-0', + label: 'item2-1-1', + value: 'value2-1-1', + }, + 'rdts-1-0-1' => { + _depth: 2, + _id: 'rdts-1-0-1', + _parent: 'rdts-1-0', + label: 'item2-1-2', + value: 'value2-1-2', + }, + 'rdts-1-0-2' => { + _children: [ + 'rdts-1-0-2-0', + ], + _depth: 2, + _id: 'rdts-1-0-2', + _parent: 'rdts-1-0', + children: undefined, + label: 'item2-1-3', + value: 'value2-1-3', + }, + 'rdts-1-0-2-0' => { + _depth: 3, + _id: 'rdts-1-0-2-0', + _parent: 'rdts-1-0-2', + label: 'item2-1-3-1', + value: 'value2-1-3-1', + }, + 'rdts-1-1' => { + _depth: 1, + _id: 'rdts-1-1', + _parent: 'rdts-1', + label: 'item2-2', + value: 'value2-2', + }, + } + } + onAction={Function {}} + onCheckboxChange={Function {}} + onNodeToggle={Function {}} + pageSize={100} + searchModeOn={false} + /> +
+
diff --git a/__snapshots__/src/index.test.js.snap b/__snapshots__/src/index.test.js.snap index 30da685cb898c01e790943f11b87751a15ebb3b9..ec82ecf27c523ecec3af21a59216d7fac195c241 100644 GIT binary patch literal 3167 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 F0001HAJqT= literal 3066 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 I+ZQ|l0LgaK5&!@I diff --git a/src/index.js b/src/index.js index 3be305c2..0f8646d9 100644 --- a/src/index.js +++ b/src/index.js @@ -28,6 +28,7 @@ class DropdownTreeSelect extends Component { keepOpenOnSelect: PropTypes.bool, placeholderText: PropTypes.string, showDropdown: PropTypes.bool, + showDropdownAlways: PropTypes.bool, className: PropTypes.string, onChange: PropTypes.func, onAction: PropTypes.func, @@ -53,7 +54,7 @@ class DropdownTreeSelect extends Component { constructor(props) { super(props) this.state = { - showDropdown: this.props.showDropdown || false, + showDropdown: this.props.showDropdown || this.props.showDropdownAlways || false, searchModeOn: false, } this.clientId = props.id || clientIdGenerator.get(this) @@ -97,7 +98,7 @@ class DropdownTreeSelect extends Component { handleClick = () => { this.setState(prevState => { // keep dropdown active when typing in search box - const showDropdown = this.keepDropdownActive || !prevState.showDropdown + const showDropdown = this.props.showDropdownAlways || this.keepDropdownActive || !prevState.showDropdown // register event listeners only if there is a state change if (showDropdown !== prevState.showDropdown) { @@ -116,7 +117,7 @@ class DropdownTreeSelect extends Component { } handleOutsideClick = e => { - if (!isOutsideClick(e, this.node)) { + if (this.props.showDropdownAlways || !isOutsideClick(e, this.node)) { return } diff --git a/src/index.test.js b/src/index.test.js index 3e86b94d..625549ad 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -72,6 +72,19 @@ test('shows dropdown', t => { t.snapshot(toJson(wrapper)) }) +test('always shows dropdown', t => { + const { tree } = t.context + const wrapper = shallow() + t.snapshot(toJson(wrapper)) +}) + +test('keeps dropdown open for showDropdownAlways', t => { + const { tree } = t.context + const wrapper = mount() + wrapper.instance().handleClick() + t.true(wrapper.state().showDropdown) +}) + test('notifies on action', t => { const handler = spy() const { tree } = t.context diff --git a/types/react-dropdown-tree-select.d.ts b/types/react-dropdown-tree-select.d.ts index f5a21005..40f10ad3 100644 --- a/types/react-dropdown-tree-select.d.ts +++ b/types/react-dropdown-tree-select.d.ts @@ -25,6 +25,9 @@ declare module "react-dropdown-tree-select" { * This can be used to render the component with the dropdown open as its initial state */ showDropdown?: boolean; + /** If set to true, always shows the dropdown when rendered, and toggling dropdown will be disabled. + */ + showDropdownAlways?: boolean; /** Additional classname for container. * The container renders with a default classname of react-dropdown-tree-select */