diff --git a/lerna-publish-summary.json b/lerna-publish-summary.json index 6245ee2d..cc3c2bd9 100644 --- a/lerna-publish-summary.json +++ b/lerna-publish-summary.json @@ -1 +1 @@ -[{"packageName":"react-complex-tree-autodemo","version":"2.5.0"},{"packageName":"react-complex-tree-blueprintjs-renderers","version":"2.5.0"},{"packageName":"react-complex-tree","version":"2.5.0"}] \ No newline at end of file +[{"packageName":"react-complex-tree-autodemo","version":"2.5.1-alpha.0"},{"packageName":"react-complex-tree-blueprintjs-renderers","version":"2.5.1-alpha.0"},{"packageName":"react-complex-tree","version":"2.5.1-alpha.0"}] \ No newline at end of file diff --git a/lerna.json b/lerna.json index 9c10fb7b..5fdbdb85 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "packages": ["packages/*"], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.5.0" + "version": "2.5.1-alpha.0" } diff --git a/next-release-notes.md b/next-release-notes.md index f77d5bd6..4cb64522 100644 --- a/next-release-notes.md +++ b/next-release-notes.md @@ -1,9 +1,5 @@ - \ No newline at end of file +- If a tree environment renders without an item defined as focused in its `viewState` parameter, it will invoke the `onFocusItem` + prop with the first item in the tree during its render. In the past, this was implicitly and silently set in the `viewState` prop, + now this assignment is triggered explicitly with the handler call (#363) +- Fixed a bug where an additional invalid drop target would be available at the bottom-most location when dragging via keyboard interactions (#363) \ No newline at end of file diff --git a/packages/autodemo/package.json b/packages/autodemo/package.json index c5df087d..7a4efbd9 100644 --- a/packages/autodemo/package.json +++ b/packages/autodemo/package.json @@ -1,6 +1,6 @@ { "name": "react-complex-tree-autodemo", - "version": "2.5.0", + "version": "2.5.1-alpha.0", "main": "lib/index.js", "types": "lib/index.d.ts", "repository": { @@ -23,10 +23,10 @@ "@types/react-dom": "^18.0.7", "babel-jest": "^27.5.1", "babel-loader": "^9.1.0", - "demodata": "^2.5.0", + "demodata": "^2.5.1-alpha.0", "jest": "^26.6.3", "react": "^18.2.0", - "react-complex-tree": "^2.5.0", + "react-complex-tree": "^2.5.1-alpha.0", "react-dom": "^18.2.0", "react-test-renderer": "^18.2.0", "ts-node": "^10.7.0", diff --git a/packages/blueprintjs-renderers/package.json b/packages/blueprintjs-renderers/package.json index 322a4a0b..95e969d8 100644 --- a/packages/blueprintjs-renderers/package.json +++ b/packages/blueprintjs-renderers/package.json @@ -1,6 +1,6 @@ { "name": "react-complex-tree-blueprintjs-renderers", - "version": "2.5.0", + "version": "2.5.1-alpha.0", "main": "lib/index.js", "types": "lib/index.d.ts", "repository": { @@ -26,10 +26,10 @@ "@types/react-dom": "^18.0.7", "babel-jest": "^27.5.1", "babel-loader": "^9.1.0", - "demodata": "^2.5.0", + "demodata": "^2.5.1-alpha.0", "jest": "^26.6.3", "react": "^18.2.0", - "react-complex-tree": "^2.5.0", + "react-complex-tree": "^2.5.1-alpha.0", "react-dom": "^18.2.0", "react-test-renderer": "^18.2.0", "ts-node": "^10.7.0", diff --git a/packages/core/package.json b/packages/core/package.json index 6b782172..b95d8cf2 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "react-complex-tree", - "version": "2.5.0", + "version": "2.5.1-alpha.0", "main": "lib/cjs/index.js", "module": "lib/esm/index.js", "esnext": "lib/esnext/index.js", @@ -35,7 +35,7 @@ "babel-jest": "^27.5.1", "babel-loader": "^9.1.0", "cpy-cli": "^3.1.1", - "demodata": "^2.5.0", + "demodata": "^2.5.1-alpha.0", "jest": "^29.2.2", "jest-dom": "^4.0.0", "jest-environment-jsdom": "^29.2.2", diff --git a/packages/core/src/controlledEnvironment/ControlledTreeEnvironment.tsx b/packages/core/src/controlledEnvironment/ControlledTreeEnvironment.tsx index 1c65b014..65679036 100644 --- a/packages/core/src/controlledEnvironment/ControlledTreeEnvironment.tsx +++ b/packages/core/src/controlledEnvironment/ControlledTreeEnvironment.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { useContext } from 'react'; +import { useContext, useEffect } from 'react'; import { ControlledTreeEnvironmentProps, TreeEnvironmentContextProps, @@ -21,26 +21,24 @@ export const ControlledTreeEnvironment = React.forwardRef< >((props, ref) => { const environmentContextProps = useControlledTreeEnvironmentProps(props); - const { viewState } = props; + const { viewState, onFocusItem } = props; // Make sure that every tree view state has a focused item - for (const treeId of Object.keys(environmentContextProps.trees)) { - // TODO if the focus item is dragged out of the tree and is not within the expanded items - // TODO of that tree, the tree does not show any focus item anymore. - // Fix: use linear items to see if focus item is visible, and reset if not. Only refresh that - // information when the viewstate changes - if ( - !viewState[treeId]?.focusedItem && - environmentContextProps.trees[treeId] - ) { - viewState[treeId] = { - ...viewState[treeId], - focusedItem: - props.items[environmentContextProps.trees[treeId].rootItem] - ?.children?.[0], - }; + useEffect(() => { + for (const treeId of Object.keys(environmentContextProps.trees)) { + const firstItemIndex = + props.items[environmentContextProps.trees[treeId].rootItem] + ?.children?.[0]; + const firstItem = firstItemIndex && props.items[firstItemIndex]; + if ( + !viewState[treeId]?.focusedItem && + environmentContextProps.trees[treeId] && + firstItem + ) { + onFocusItem?.(firstItem, treeId, false); + } } - } + }, [environmentContextProps.trees, onFocusItem, props.items, viewState]); return ( diff --git a/packages/core/src/drag/DragAndDropProvider.tsx b/packages/core/src/drag/DragAndDropProvider.tsx index f5517478..642a0317 100644 --- a/packages/core/src/drag/DragAndDropProvider.tsx +++ b/packages/core/src/drag/DragAndDropProvider.tsx @@ -282,7 +282,7 @@ export const DragAndDropProvider: React.FC = ({ if (environment.activeTreeId) { setProgrammaticDragIndex(oldIndex => Math.min( - viableDragPositions[environment.activeTreeId!].length, + viableDragPositions[environment.activeTreeId!].length - 1, oldIndex + 1 ) ); diff --git a/packages/core/src/stories/363.stories.tsx b/packages/core/src/stories/363.stories.tsx new file mode 100644 index 00000000..3315f986 --- /dev/null +++ b/packages/core/src/stories/363.stories.tsx @@ -0,0 +1,59 @@ +import { Meta } from '@storybook/react'; +import React, { useState } from 'react'; +import { longTree } from 'demodata'; +import { Tree } from '../tree/Tree'; +import { ControlledTreeEnvironment } from '../controlledEnvironment/ControlledTreeEnvironment'; +import { TreeItemIndex } from '../types'; + +export default { + title: 'Core/Issue Report Reproduction', +} as Meta; + +export const Issue363 = () => { + const [focusedItem, setFocusedItem] = useState(); + const [expandedItems, setExpandedItems] = useState([]); + const [selectedItems, setSelectedItems] = useState([]); + return ( + + canDragAndDrop + canDropOnFolder + canReorderItems + items={longTree.items} + getItemTitle={item => item.data} + onFocusItem={item => { + setFocusedItem(item.index); + console.log(`Focused item: ${item.index}`); + }} + onSelectItems={items => { + setSelectedItems(items); + }} + onExpandItem={item => { + setExpandedItems([...expandedItems, item.index]); + }} + onCollapseItem={item => { + setExpandedItems(expandedItems.filter(i => i !== item.index)); + }} + viewState={{ + 'tree-1': { + focusedItem, + expandedItems, + selectedItems, + }, + }} + > + + +
+        {JSON.stringify(
+          {
+            focusedItem,
+            expandedItems,
+            selectedItems,
+          },
+          null,
+          2
+        )}
+      
+ + ); +}; diff --git a/packages/core/test/dnd-restrictions.spec.tsx b/packages/core/test/dnd-restrictions.spec.tsx index d2f6ba4c..1ae92642 100644 --- a/packages/core/test/dnd-restrictions.spec.tsx +++ b/packages/core/test/dnd-restrictions.spec.tsx @@ -118,7 +118,7 @@ describe('dnd restrictions', () => { describe('canDrag', () => { it('respects disabled value', async () => { - const canDrag = jest.fn(items => items[0].data !== 'aab'); + const canDrag = jest.fn(items => items[0]?.data !== 'aab'); const test = await new TestUtil().renderOpenTree({ canDrag, }); @@ -131,7 +131,7 @@ describe('dnd restrictions', () => { }); it('works for other item', async () => { - const canDrag = jest.fn(items => items[0].data !== 'aab'); + const canDrag = jest.fn(items => items[0]?.data !== 'aab'); const test = await new TestUtil().renderOpenTree({ canDrag, }); diff --git a/packages/demodata/package.json b/packages/demodata/package.json index 26e1e9d7..72953349 100644 --- a/packages/demodata/package.json +++ b/packages/demodata/package.json @@ -1,6 +1,6 @@ { "name": "demodata", - "version": "2.5.0", + "version": "2.5.1-alpha.0", "main": "lib/index.js", "repository": { "type": "git", diff --git a/packages/docs/package.json b/packages/docs/package.json index ed034b27..e1cc4b94 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "docs", - "version": "2.5.0", + "version": "2.5.1-alpha.0", "private": true, "scripts": { "docusaurus": "docusaurus", @@ -21,7 +21,7 @@ "@mdx-js/react": "^1.6.21", "@svgr/webpack": "^6.5.1", "clsx": "^1.1.1", - "demodata": "^2.5.0", + "demodata": "^2.5.1-alpha.0", "docusaurus-plugin-react-docgen-typescript": "^1.0.2", "docusaurus-plugin-typedoc": "^0.18.0", "file-loader": "^6.2.0", @@ -29,9 +29,9 @@ "iframe-resizer-react": "^1.1.0", "prism-react-renderer": "^1.2.1", "react": "^18.2.0", - "react-complex-tree": "^2.5.0", - "react-complex-tree-autodemo": "^2.5.0", - "react-complex-tree-blueprintjs-renderers": "^2.5.0", + "react-complex-tree": "^2.5.1-alpha.0", + "react-complex-tree-autodemo": "^2.5.1-alpha.0", + "react-complex-tree-blueprintjs-renderers": "^2.5.1-alpha.0", "react-docgen-typescript": "^2.2.2", "react-dom": "^18.2.0", "typedoc": "^0.23.18", diff --git a/yarn.lock b/yarn.lock index 319b66d6..20c823c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11803,7 +11803,7 @@ __metadata: languageName: node linkType: hard -"demodata@^2.5.0, demodata@workspace:packages/demodata": +"demodata@^2.5.1-alpha.0, demodata@workspace:packages/demodata": version: 0.0.0-use.local resolution: "demodata@workspace:packages/demodata" dependencies: @@ -12029,7 +12029,7 @@ __metadata: "@mdx-js/react": ^1.6.21 "@svgr/webpack": ^6.5.1 clsx: ^1.1.1 - demodata: ^2.5.0 + demodata: ^2.5.1-alpha.0 docusaurus-plugin-react-docgen-typescript: ^1.0.2 docusaurus-plugin-typedoc: ^0.18.0 file-loader: ^6.2.0 @@ -12037,9 +12037,9 @@ __metadata: iframe-resizer-react: ^1.1.0 prism-react-renderer: ^1.2.1 react: ^18.2.0 - react-complex-tree: ^2.5.0 - react-complex-tree-autodemo: ^2.5.0 - react-complex-tree-blueprintjs-renderers: ^2.5.0 + react-complex-tree: ^2.5.1-alpha.0 + react-complex-tree-autodemo: ^2.5.1-alpha.0 + react-complex-tree-blueprintjs-renderers: ^2.5.1-alpha.0 react-docgen-typescript: ^2.2.2 react-dom: ^18.2.0 typedoc: ^0.23.18 @@ -21548,7 +21548,7 @@ __metadata: languageName: node linkType: hard -"react-complex-tree-autodemo@^2.5.0, react-complex-tree-autodemo@workspace:packages/autodemo": +"react-complex-tree-autodemo@^2.5.1-alpha.0, react-complex-tree-autodemo@workspace:packages/autodemo": version: 0.0.0-use.local resolution: "react-complex-tree-autodemo@workspace:packages/autodemo" dependencies: @@ -21562,10 +21562,10 @@ __metadata: "@types/react-dom": ^18.0.7 babel-jest: ^27.5.1 babel-loader: ^9.1.0 - demodata: ^2.5.0 + demodata: ^2.5.1-alpha.0 jest: ^26.6.3 react: ^18.2.0 - react-complex-tree: ^2.5.0 + react-complex-tree: ^2.5.1-alpha.0 react-dom: ^18.2.0 react-test-renderer: ^18.2.0 ts-node: ^10.7.0 @@ -21573,7 +21573,7 @@ __metadata: languageName: unknown linkType: soft -"react-complex-tree-blueprintjs-renderers@^2.5.0, react-complex-tree-blueprintjs-renderers@workspace:packages/blueprintjs-renderers": +"react-complex-tree-blueprintjs-renderers@^2.5.1-alpha.0, react-complex-tree-blueprintjs-renderers@workspace:packages/blueprintjs-renderers": version: 0.0.0-use.local resolution: "react-complex-tree-blueprintjs-renderers@workspace:packages/blueprintjs-renderers" dependencies: @@ -21589,10 +21589,10 @@ __metadata: "@types/react-dom": ^18.0.7 babel-jest: ^27.5.1 babel-loader: ^9.1.0 - demodata: ^2.5.0 + demodata: ^2.5.1-alpha.0 jest: ^26.6.3 react: ^18.2.0 - react-complex-tree: ^2.5.0 + react-complex-tree: ^2.5.1-alpha.0 react-dom: ^18.2.0 react-test-renderer: ^18.2.0 ts-node: ^10.7.0 @@ -21640,7 +21640,7 @@ __metadata: languageName: unknown linkType: soft -"react-complex-tree@^2.5.0, react-complex-tree@workspace:packages/core": +"react-complex-tree@^2.5.1-alpha.0, react-complex-tree@workspace:packages/core": version: 0.0.0-use.local resolution: "react-complex-tree@workspace:packages/core" dependencies: @@ -21658,7 +21658,7 @@ __metadata: babel-jest: ^27.5.1 babel-loader: ^9.1.0 cpy-cli: ^3.1.1 - demodata: ^2.5.0 + demodata: ^2.5.1-alpha.0 jest: ^29.2.2 jest-dom: ^4.0.0 jest-environment-jsdom: ^29.2.2