diff --git a/README.md b/README.md index e9cc292d..5a043758 100644 --- a/README.md +++ b/README.md @@ -151,8 +151,8 @@ const data = { const onChange = (currentNode, selectedNodes) => { console.log('onChange::', currentNode, selectedNodes) } -const onAction = ({ action, node }) => { - console.log(`onAction:: [${action}]`, node) +const onAction = ({ action, id }) => { + console.log(`onAction:: [${action}]`, id) } const onNodeToggle = currentNode => { console.log('onNodeToggle::', currentNode) @@ -211,6 +211,20 @@ function onNodeToggle(currentNode) { return ``` +### onAction + +Type: `function` + +Fires when a action is triggered. Example: + +```jsx +function onAction({action, id}) { + console.log(`onAction:: [${action}]`, id) +} + +return +``` + ### onFocus Type: `function` @@ -251,7 +265,6 @@ The `action` object requires the following structure: ```js { className, // required: CSS class for the node. e.g. `fa fa-info` - onAction, // required: Fired on click of the action. The event handler receives `action` object as well as the `node` object. title, // optional: HTML tooltip text text, // optional: Any text to be displayed. This is helpful to pass ligatures if you're using ligature fonts ... // optional: Any extra properties that you'd like to receive during `onChange` event @@ -315,7 +328,7 @@ Type: `bool` (default: `false`) Type: `string` -Specific id for container. The container renders with a default id of `rdtsN` where N is count of the current component rendered. +Specific id for container. The container renders with a default id of `rdtsN` where N is the 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) diff --git a/docs/src/stories/BigData/index.js b/docs/src/stories/BigData/index.js index 9b1c1ec9..e7bd2435 100644 --- a/docs/src/stories/BigData/index.js +++ b/docs/src/stories/BigData/index.js @@ -8,8 +8,8 @@ import bigData from './big-data.json' const onChange = (curNode, selectedNodes) => { console.log('onChange::', curNode, selectedNodes) } -const onAction = ({ action, node }) => { - console.log(`onAction:: [${action}]`, node) +const onAction = ({ action, id }) => { + console.log(`onAction:: [${action}]`, id) } const onNodeToggle = curNode => { console.log('onNodeToggle::', curNode) diff --git a/docs/src/stories/DefaultValues/index.js b/docs/src/stories/DefaultValues/index.js index 5f5c0ca7..2cd140e1 100644 --- a/docs/src/stories/DefaultValues/index.js +++ b/docs/src/stories/DefaultValues/index.js @@ -9,8 +9,8 @@ import data from './data.json' const onChange = (curNode, selectedNodes) => { console.log('onChange::', curNode, selectedNodes) } -const onAction = ({ action, node }) => { - console.log(`onAction:: [${action}]`, node) +const onAction = ({ action, id }) => { + console.log(`onAction:: [${action}]`, id) } const onNodeToggle = curNode => { console.log('onNodeToggle::', curNode) diff --git a/docs/src/stories/Options/index.js b/docs/src/stories/Options/index.js index a6a20544..569b0e6c 100644 --- a/docs/src/stories/Options/index.js +++ b/docs/src/stories/Options/index.js @@ -25,8 +25,8 @@ class WithOptions extends PureComponent { onChange = (curNode, selectedNodes) => { console.log('onChange::', curNode, selectedNodes) } - onAction = ({ action, node }) => { - console.log(`onAction:: [${action}]`, node) + onAction = ({ action, id }) => { + console.log(`onAction:: [${action}]`, id) } onNodeToggle = curNode => { console.log('onNodeToggle::', curNode) diff --git a/docs/src/stories/Simple/index.js b/docs/src/stories/Simple/index.js index 8dc83d3b..850fc5af 100644 --- a/docs/src/stories/Simple/index.js +++ b/docs/src/stories/Simple/index.js @@ -8,8 +8,8 @@ import data from './data.json' const onChange = (curNode, selectedNodes) => { console.log('onChange::', curNode, selectedNodes) } -const onAction = ({ action, node }) => { - console.log(`onAction:: [${action}]`, node) +const onAction = ({ action, id }) => { + console.log(`onAction:: [${action}]`, id) } const onNodeToggle = curNode => { console.log('onNodeToggle::', curNode) diff --git a/package.json b/package.json index d2098710..9eabe2c5 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "search" ], "main": "dist/react-dropdown-tree-select.js", + "types": "dist/react-dropdown-tree-select.d.ts", "repository": "https://github.com/dowjones/react-dropdown-tree-select.git", "author": "Hrusikesh Panda ", "license": "MIT", @@ -65,6 +66,7 @@ "babel-preset-stage-0": "6.24.1", "commitizen": "^2.9.6", "conventional-changelog-cli": "^2.0.5", + "copy-webpack-plugin": "^5.0.1", "coveralls": "^3.0.0", "cross-env": "^5.0.5", "css-loader": "^0.28.0", diff --git a/types/react-dropdown-tree-select.d.ts b/types/react-dropdown-tree-select.d.ts new file mode 100644 index 00000000..9bc49257 --- /dev/null +++ b/types/react-dropdown-tree-select.d.ts @@ -0,0 +1,144 @@ +// tslint:disable:interface-name +declare module "react-dropdown-tree-select" { + import * as React from "react"; + + 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; + /** The text to display as placeholder on the search box. Defaults to Choose... */ + placeholderText?: string; + /** 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; + /** 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?: (event: ActionEvent) => 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; + /** 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 + */ + simpleSelect?: boolean; + /** The text to display when the search does not find results in the content list. Defaults to No matches found */ + noMatchesText?: string; + /** 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; + } + + 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 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?: Node[]; + } + + 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 ActionEvent { + action: string; + id: string; + } + + export interface NodeDataSet { + [property: string]: any; + } +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 21db6324..3b5444d7 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,7 @@ const path = require('path') const webpack = require('webpack') const MiniCssExtractPlugin = require('mini-css-extract-plugin') +const CopyPlugin = require('copy-webpack-plugin') const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') module.exports = { @@ -34,7 +35,10 @@ module.exports = { analyzerMode: 'static', openAnalyzer: false, generateStatsFile: true - }) + }), + new CopyPlugin([ + { from: path.join(__dirname, 'types'), to: path.join(__dirname, 'dist') } + ]) ], module: { rules: [