diff --git a/README.md b/README.md
index aecabd37..b797d701 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,7 @@ A lightweight and fast control to render a select component that can display hie
- [keepOpenOnSelect](#keepopenonselect)
- [mode](#mode)
- [multiSelect](#multiSelect)
+ - [hierarchical](#hierarchical)
- [simpleSelect](#simpleSelect)
- [radioSelect](#radioSelect)
- [showPartiallySelected](#showpartiallyselected)
@@ -327,7 +328,13 @@ Defines how the dropdown is rendered / behaves
#### multiSelect
-This is the default mode. A multi selectable dropdown which supports hierarchical data.
+A multi selectable dropdown which supports tree data with parent-child relationships. This is the default mode.
+
+#### hierarchical
+
+A multi selectable dropdown which supports tree data **without** parent-child relationships. In this mode, selecting a node has no ripple effects on its descendants or ancestors. Subsequently, `showPartiallySelected` becomes a moot flag and has no effect as well.
+
+⚠️ Note that `hierarchical=true` negates/overrides `showPartiallySelected`.
#### simpleSelect
diff --git a/docs/src/stories/Options/index.js b/docs/src/stories/Options/index.js
index ed6a6c79..a75339b0 100644
--- a/docs/src/stories/Options/index.js
+++ b/docs/src/stories/Options/index.js
@@ -45,7 +45,6 @@ class WithOptions extends PureComponent {
showPartiallySelected,
disabled,
readOnly,
- hierarchical,
} = this.state
return (
@@ -66,6 +65,7 @@ class WithOptions extends PureComponent {
+
-
diff --git a/package.json b/package.json
index 7f76eebb..c4a65e25 100644
--- a/package.json
+++ b/package.json
@@ -184,7 +184,7 @@
}
},
"lint-staged": {
- "*.{js,json,css,md}": [
+ "*.{js,json,css,md,ts}": [
"prettier --write",
"git add -f"
]
diff --git a/src/index.js b/src/index.js
index d373ca5b..6d03592c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -42,11 +42,10 @@ class DropdownTreeSelect extends Component {
onNodeToggle: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
- mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect']),
+ mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect', 'hierarchical']),
showPartiallySelected: PropTypes.bool,
disabled: PropTypes.bool,
readOnly: PropTypes.bool,
- hierarchical: PropTypes.bool,
id: PropTypes.string,
}
@@ -67,12 +66,11 @@ class DropdownTreeSelect extends Component {
this.clientId = props.id || clientIdGenerator.get(this)
}
- initNewProps = ({ data, mode, showPartiallySelected, hierarchical }) => {
+ initNewProps = ({ data, mode, showPartiallySelected }) => {
this.treeManager = new TreeManager({
data,
mode,
showPartiallySelected,
- hierarchical,
rootPrefixId: this.clientId,
})
// Restore focus-state
@@ -94,8 +92,8 @@ class DropdownTreeSelect extends Component {
}
componentWillMount() {
- const { data, hierarchical } = this.props
- this.initNewProps({ data, hierarchical, ...this.props })
+ const { data, mode, showPartiallySelected } = this.props
+ this.initNewProps({ data, mode, showPartiallySelected })
}
componentWillUnmount() {
diff --git a/src/tree-manager/index.js b/src/tree-manager/index.js
index b5efa456..f345ffa1 100644
--- a/src/tree-manager/index.js
+++ b/src/tree-manager/index.js
@@ -5,23 +5,24 @@ import nodeVisitor from './nodeVisitor'
import keyboardNavigation, { FocusActionNames } from './keyboardNavigation'
class TreeManager {
- constructor({ data, mode, showPartiallySelected, hierarchical, rootPrefixId }) {
+ constructor({ data, mode, showPartiallySelected, rootPrefixId }) {
this._src = data
this.simpleSelect = mode === 'simpleSelect'
this.radioSelect = mode === 'radioSelect'
+ this.hierarchical = mode === 'hierarchical'
const { list, defaultValues, singleSelectedNode } = flattenTree({
tree: JSON.parse(JSON.stringify(data)),
simple: this.simpleSelect,
radio: this.radioSelect,
showPartialState: showPartiallySelected,
- hierarchical,
+ hierarchical: this.hierarchical,
rootPrefixId,
})
this.tree = list
this.defaultValues = defaultValues
- this.showPartialState = !hierarchical && showPartiallySelected
+ this.showPartialState = !this.hierarchical && showPartiallySelected
this.searchMaps = new Map()
- this.hierarchical = hierarchical
+
if ((this.simpleSelect || this.radioSelect) && singleSelectedNode) {
// Remembers initial check on single select dropdowns
this.currentChecked = singleSelectedNode._id
diff --git a/src/tree-node/index.js b/src/tree-node/index.js
index de719944..cb94a2db 100644
--- a/src/tree-node/index.js
+++ b/src/tree-node/index.js
@@ -69,7 +69,7 @@ class TreeNode extends PureComponent {
onNodeToggle: PropTypes.func,
onAction: PropTypes.func,
onCheckboxChange: PropTypes.func,
- mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect']),
+ mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect', 'hierarchical']),
showPartiallySelected: PropTypes.bool,
readOnly: PropTypes.bool,
clientId: PropTypes.string,
diff --git a/src/tree-node/node-label.js b/src/tree-node/node-label.js
index 1a2912b7..a5bc4ef6 100644
--- a/src/tree-node/node-label.js
+++ b/src/tree-node/node-label.js
@@ -19,7 +19,7 @@ class NodeLabel extends PureComponent {
partial: PropTypes.bool,
disabled: PropTypes.bool,
dataset: PropTypes.object,
- mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect']),
+ mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect', 'hierarchical']),
showPartiallySelected: PropTypes.bool,
onCheckboxChange: PropTypes.func,
readOnly: PropTypes.bool,
diff --git a/src/tree/index.js b/src/tree/index.js
index c697b996..d8b53c82 100644
--- a/src/tree/index.js
+++ b/src/tree/index.js
@@ -23,7 +23,7 @@ class Tree extends Component {
onNodeToggle: PropTypes.func,
onAction: PropTypes.func,
onCheckboxChange: PropTypes.func,
- mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect']),
+ mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect', 'hierarchical']),
showPartiallySelected: PropTypes.bool,
pageSize: PropTypes.number,
readOnly: PropTypes.bool,
diff --git a/src/trigger/index.js b/src/trigger/index.js
index 60d47f58..ae69745a 100644
--- a/src/trigger/index.js
+++ b/src/trigger/index.js
@@ -14,7 +14,7 @@ class Trigger extends PureComponent {
disabled: PropTypes.bool,
readOnly: PropTypes.bool,
showDropdown: PropTypes.bool,
- mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect']),
+ mode: PropTypes.oneOf(['multiSelect', 'simpleSelect', 'radioSelect', 'hierarchical']),
texts: PropTypes.object,
}
diff --git a/types/react-dropdown-tree-select.d.ts b/types/react-dropdown-tree-select.d.ts
index 27a2f5d1..ebe58afd 100644
--- a/types/react-dropdown-tree-select.d.ts
+++ b/types/react-dropdown-tree-select.d.ts
@@ -1,165 +1,174 @@
// tslint:disable:interface-name
-declare module "react-dropdown-tree-select" {
- import * as React from "react";
+declare module 'react-dropdown-tree-select' {
+ import * as React from 'react'
- export type TreeData = Object | TreeNodeProps[];
+ export type TreeData = Object | TreeNodeProps[]
- export interface DropdownTreeSelectProps {
- data: TreeData;
- /** Clear the input search if a node has been selected/unselected */
- clearSearchOnChange?: boolean;
- /** Displays search results as a tree instead of flattened results */
- keepTreeOnSearch?: boolean;
- /** Displays children of found nodes to allow searching for a parent node on
- * then selecting any child node of the found node. Defaults to false
- * NOTE this works only in combination with keepTreeOnSearch
- */
- keepChildrenOnSearch?: boolean;
- /** Keeps single selects open after selection. Defaults to `false`
- * NOTE this works only in combination with simpleSelect or radioSelect
- */
- keepOpenOnSelect?: boolean;
- /** Texts to override output for */
- texts?: TextProps;
- /** 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
- */
- 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
- */
- className?: string;
- /** Fires when a node change event occurs. Currently the following actions trigger a node change:
- * Checkbox click which checks/unchecks the item
- * Closing of pill (which unchecks the corresponding checkbox item)
+ export interface DropdownTreeSelectProps {
+ data: TreeData
+ /** Clear the input search if a node has been selected/unselected */
+ clearSearchOnChange?: boolean
+ /** Displays search results as a tree instead of flattened results */
+ keepTreeOnSearch?: boolean
+ /** Displays children of found nodes to allow searching for a parent node on
+ * then selecting any child node of the found node. Defaults to false
+ * NOTE this works only in combination with keepTreeOnSearch
+ */
+ keepChildrenOnSearch?: boolean
+ /** Keeps single selects open after selection. Defaults to `false`
+ * NOTE this works only in combination with simpleSelect or radioSelect
+ */
+ keepOpenOnSelect?: boolean
+ /** Texts to override output for */
+ texts?: TextProps
+ /** 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
+ */
+ 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
+ */
+ className?: string
+ /** Fires when a node change event occurs. Currently the following actions trigger a node change:
+ * Checkbox click which checks/unchecks the item
+ * Closing of pill (which unchecks the corresponding checkbox item)
+ *
+ * Calls the handler with the current node object and all selected nodes (if any)
+ */
+ onChange?: (currentNode: TreeNode, selectedNodes: TreeNode[]) => void
+ /** Fired on click of the action */
+ onAction?: (currentNode: TreeNode, currentAction: NodeAction) => void
+ /** Fires when a node is expanded or collapsed.
+ * Calls the handler with the current node object
+ */
+ onNodeToggle?: (currentNode: TreeNode) => void
+ /** Fires when input box receives focus or the dropdown arrow is clicked.
+ * This is helpful for setting dirty or touched flags with forms
+ */
+ onFocus?: () => void
+ /** Fires when input box loses focus or the dropdown arrow is clicked again (and the dropdown collapses).
+ * This is helpful for setting dirty or touched flags with forms
+ */
+ onBlur?: () => void
+ /** Defines how the dropdown is rendered / behaves
*
- * Calls the handler with the current node object and all selected nodes (if any)
- */
- onChange?: (currentNode: TreeNode, selectedNodes: TreeNode[]) => void;
- /** Fired on click of the action */
- onAction?: (currentNode: TreeNode, currentAction: NodeAction) => void;
- /** Fires when a node is expanded or collapsed.
- * Calls the handler with the current node object
- */
- onNodeToggle?: (currentNode: TreeNode) => void;
- /** Fires when input box receives focus or the dropdown arrow is clicked.
- * This is helpful for setting dirty or touched flags with forms
- */
- onFocus?: () => void;
- /** Fires when input box loses focus or the dropdown arrow is clicked again (and the dropdown collapses).
- * This is helpful for setting dirty or touched flags with forms
- */
- onBlur?: () => void;
- /** Defines how the dropdown is rendered / behaves
- *
* - multiSelect
- * A multi selectable dropdown which supports hierarchial data.
- *
+ * A multi selectable dropdown which supports tree data with parent-child relationships. This is the default mode.
+ *
+ * - hierarchical
+ * A multi selectable dropdown which supports tree data **without** parent-child relationships. In this mode, selecting a node has no ripple effects on its descendants or ancestors. Subsequently, `showPartiallySelected` becomes a moot flag and has no effect as well.
+ *
+ * ⚠️ Note that `hierarchical=true` negates/overrides `showPartiallySelected`.
+ *
* - simpleSelect
- * Turns the dropdown into a simple, single select dropdown. If you pass tree data, only immediate children are picked, grandchildren nodes are ignored. Defaults to false.
- *
- * NOTE if multiple nodes in data are selected, checked or isDefaultValue, only the first visited node is selected
- *
+ * Turns the dropdown into a simple, single select dropdown. If you pass tree data, only immediate children are picked, grandchildren nodes are ignored.
+ *
+ * ⚠️ If multiple nodes in data are selected - by setting either `checked` or `isDefaultValue`, only the first visited node stays selected.
+ *
* - radioSelect
- * Turns the dropdown into radio select dropdown. Similar to simpleSelect but keeps tree/children. Defaults to false.
- *
- * NOTE if multiple nodes in data are selected, checked or isDefaultValue, only the first visited node is selected */
- mode?: 'multiSelect' | 'simpleSelect' | 'radioSelect';
- /** If set to true, shows checkboxes in a partial state when one, but not all of their children are selected.
- * Allows styling of partially selected nodes as well, by using :indeterminate pseudo class.
- * Simply add desired styles to .node.partial .checkbox-item:indeterminate { ... } in your CSS
- */
- showPartiallySelected?: boolean;
- /** disabled=true disables the dropdown completely. This is useful during form submit events */
- disabled?: boolean;
- /** readOnly=true makes the dropdown read only,
- * which means that the user can still interact with it but cannot change any of its values.
- * This can be useful for display only forms
- */
- readOnly?: boolean;
- hierarchical?: boolean;
- /** Specific id for container. The container renders with a default id of `rdtsN` where N is count of the current component rendered
- * Use to ensure a own unique id when a simple counter is not sufficient, e.g in a partial server render (SSR)
- */
- id?: string;
- }
+ * Turns the dropdown into radio select dropdown.
+
+ * Like `simpleSelect`, you can only select one value; but keeps the tree/children structure.
+ *
+ * ⚠️ If multiple nodes in data are selected - by setting either `checked` or `isDefaultValue`, only the first visited node stays selected.
+ *
+ *
+ * */
+ mode?: 'multiSelect' | 'simpleSelect' | 'radioSelect' | 'hierarchical'
+ /** If set to true, shows checkboxes in a partial state when one, but not all of their children are selected.
+ * Allows styling of partially selected nodes as well, by using :indeterminate pseudo class.
+ * Simply add desired styles to .node.partial .checkbox-item:indeterminate { ... } in your CSS
+ */
+ showPartiallySelected?: boolean
+ /** disabled=true disables the dropdown completely. This is useful during form submit events */
+ disabled?: boolean
+ /** readOnly=true makes the dropdown read only,
+ * which means that the user can still interact with it but cannot change any of its values.
+ * This can be useful for display only forms
+ */
+ readOnly?: boolean
+ /** Specific id for container. The container renders with a default id of `rdtsN` where N is count of the current component rendered
+ * Use to ensure a own unique id when a simple counter is not sufficient, e.g in a partial server render (SSR)
+ */
+ id?: string
+ }
- export interface DropdownTreeSelectState {
- showDropdown: boolean;
- searchModeOn: boolean;
- allNodesHidden: boolean;
- tree: TreeNode[];
- tags: TreeNode[];
- }
+ export interface DropdownTreeSelectState {
+ showDropdown: boolean
+ searchModeOn: boolean
+ allNodesHidden: boolean
+ tree: TreeNode[]
+ tags: TreeNode[]
+ }
- export default class DropdownTreeSelect extends React.Component {
- node: HTMLDivElement;
- searchInput: HTMLInputElement;
- keepDropdownActive: boolean;
- handleClick(): void;
- }
+ export default class DropdownTreeSelect extends React.Component {
+ node: HTMLDivElement
+ searchInput: HTMLInputElement
+ keepDropdownActive: boolean
+ handleClick(): void
+ }
- export interface TreeNode {
- /** Checkbox label */
- label: string;
- /** Checkbox value */
- value: string;
- /** Initial state of checkbox. if true, checkbox is selected and corresponding pill is rendered. */
- checked?: boolean;
- /** Selectable state of checkbox. if true, the checkbox is disabled and the node is not selectable. */
- disabled?: boolean;
- /** If true, the node is expanded
- * (children of children nodes are not expanded by default unless children nodes also have expanded: true).
- */
- expanded?: boolean;
- /** Additional css class for the node. This is helpful to style the nodes your way */
- className?: string;
- /** Css class for the corresponding tag. Use this to add custom style the pill corresponding to the node. */
- tagClassName?: string;
- /** An array of extra action on the node (such as displaying an info icon or any custom icons/elements) */
- actions?: NodeAction[];
- /** Allows data-* attributes to be set on the node and tag elements */
- dataset?: NodeDataSet;
- /** Indicate if a node is a default value.
- * When true, the dropdown will automatically select the node(s) when there is no other selected node.
- * Can be used on more than one node.
- */
- isDefaultValue?: boolean;
- /** Any extra properties that you'd like to receive during `onChange` event */
- [property: string]: any;
- }
+ export interface TreeNode {
+ /** Checkbox label */
+ label: string
+ /** Checkbox value */
+ value: string
+ /** Initial state of checkbox. if true, checkbox is selected and corresponding pill is rendered. */
+ checked?: boolean
+ /** Selectable state of checkbox. if true, the checkbox is disabled and the node is not selectable. */
+ disabled?: boolean
+ /** If true, the node is expanded
+ * (children of children nodes are not expanded by default unless children nodes also have expanded: true).
+ */
+ expanded?: boolean
+ /** Additional css class for the node. This is helpful to style the nodes your way */
+ className?: string
+ /** Css class for the corresponding tag. Use this to add custom style the pill corresponding to the node. */
+ tagClassName?: string
+ /** An array of extra action on the node (such as displaying an info icon or any custom icons/elements) */
+ actions?: NodeAction[]
+ /** Allows data-* attributes to be set on the node and tag elements */
+ dataset?: NodeDataSet
+ /** Indicate if a node is a default value.
+ * When true, the dropdown will automatically select the node(s) when there is no other selected node.
+ * Can be used on more than one node.
+ */
+ isDefaultValue?: boolean
+ /** Any extra properties that you'd like to receive during `onChange` event */
+ [property: string]: any
+ }
- export interface TreeNodeProps extends TreeNode {
- /** Array of child objects */
- children?: TreeNode[];
- }
+ export interface TreeNodeProps extends TreeNode {
+ /** Array of child objects */
+ children?: TreeNode[]
+ }
- export interface TextProps {
- /** The text to display as placeholder on the search box. Defaults to Choose... */
- placeholder?: string;
- /** The text to display when the search does not find results in the content list. Defaults to No matches found */
- noMatches?: string;
- /** Adds `aria-labelledby` to search input when input starts with `#`, adds `aria-label` to search input when label has value (not containing '#') */
- label?: string;
- /** The text to display for `aria-label` on tag delete buttons which is combined with `aria-labelledby` pointing to the node label. Defaults to `Remove */
- labelRemove?: string;
- }
+ export interface TextProps {
+ /** The text to display as placeholder on the search box. Defaults to Choose... */
+ placeholder?: string
+ /** The text to display when the search does not find results in the content list. Defaults to No matches found */
+ noMatches?: string
+ /** Adds `aria-labelledby` to search input when input starts with `#`, adds `aria-label` to search input when label has value (not containing '#') */
+ label?: string
+ /** The text to display for `aria-label` on tag delete buttons which is combined with `aria-labelledby` pointing to the node label. Defaults to `Remove */
+ labelRemove?: string
+ }
- export interface NodeAction {
- /** CSS class for the node. e.g. `fa fa-info` */
- className: string;
- /** HTML tooltip text */
- title?: string;
- /** Any text to be displayed. This is helpful to pass ligatures if you're using ligature fonts */
- text?: string;
- /** Any extra properties that you'd like to receive during `onChange` event */
- [property: string]: any;
- }
+ export interface NodeAction {
+ /** CSS class for the node. e.g. `fa fa-info` */
+ className: string
+ /** HTML tooltip text */
+ title?: string
+ /** Any text to be displayed. This is helpful to pass ligatures if you're using ligature fonts */
+ text?: string
+ /** Any extra properties that you'd like to receive during `onChange` event */
+ [property: string]: any
+ }
- export interface NodeDataSet {
- [property: string]: any;
- }
-}
\ No newline at end of file
+ export interface NodeDataSet {
+ [property: string]: any
+ }
+}