diff --git a/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts b/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts index aa7c933115..f9313030b0 100644 --- a/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts +++ b/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts @@ -33,7 +33,7 @@ export enum actionTypes { SET_AS_LOADED = '@neos/neos-ui/UI/ContentTree/SET_AS_LOADED', } -const toggle = (contextPath: NodeContextPath) => createAction(actionTypes.TOGGLE, contextPath); +const toggle = (contextPath: NodeContextPath, collapseChildren: boolean, childrenContextPaths: NodeContextPath[], childrenCollapsedByDefault: boolean) => createAction(actionTypes.TOGGLE, {contextPath, collapseChildren, childrenContextPaths, childrenCollapsedByDefault}); const startLoading = () => createAction(actionTypes.START_LOADING); const stopLoading = () => createAction(actionTypes.STOP_LOADING); const reloadTree = () => createAction(actionTypes.RELOAD_TREE); @@ -70,8 +70,16 @@ export const reducer = (state: State = defaultState, action: InitAction | Action break; } case actionTypes.TOGGLE: { - const contextPath = action.payload; - if (draft.toggled.includes(contextPath)) { + const {contextPath, collapseChildren, childrenContextPaths, childrenCollapsedByDefault} = action.payload; + if (collapseChildren) { + childrenContextPaths.forEach(child => { + if (!childrenCollapsedByDefault && !draft.toggled.includes(child)) { + draft.toggled.push(child); + } else if (childrenCollapsedByDefault && draft.toggled.includes(child)) { + draft.toggled = draft.toggled.filter(i => i !== child); + } + }) + } else if (draft.toggled.includes(contextPath)) { draft.toggled = draft.toggled.filter(i => i !== contextPath); } else { draft.toggled.push(contextPath); diff --git a/packages/neos-ui-redux-store/src/UI/PageTree/index.ts b/packages/neos-ui-redux-store/src/UI/PageTree/index.ts index 8b55561600..5c5d295cbf 100644 --- a/packages/neos-ui-redux-store/src/UI/PageTree/index.ts +++ b/packages/neos-ui-redux-store/src/UI/PageTree/index.ts @@ -44,7 +44,7 @@ export enum actionTypes { } const focus = (contextPath: NodeContextPath, _: undefined, selectionMode: SelectionModeTypes = SelectionModeTypes.SINGLE_SELECT) => createAction(actionTypes.FOCUS, {contextPath, selectionMode}); -const toggle = (contextPath: NodeContextPath) => createAction(actionTypes.TOGGLE, {contextPath}); +const toggle = (contextPath: NodeContextPath, collapseChildren: boolean, childrenContextPaths: NodeContextPath[], childrenCollapsedByDefault: boolean) => createAction(actionTypes.TOGGLE, {contextPath, collapseChildren, childrenContextPaths, childrenCollapsedByDefault}); const invalidate = (contextPath: NodeContextPath) => createAction(actionTypes.INVALIDATE, {contextPath}); const requestChildren = (contextPath: NodeContextPath, {unCollapse = true, activate = false} = {}) => createAction(actionTypes.REQUEST_CHILDREN, {contextPath, opts: {unCollapse, activate}}); const setAsLoading = (contextPath: NodeContextPath) => createAction(actionTypes.SET_AS_LOADING, {contextPath}); @@ -96,8 +96,16 @@ export const reducer = (state: State = defaultState, action: InitAction | Action break; } case actionTypes.TOGGLE: { - const {contextPath} = action.payload; - if (draft.toggled.includes(contextPath)) { + const {contextPath, collapseChildren, childrenContextPaths, childrenCollapsedByDefault} = action.payload; + if (collapseChildren) { + childrenContextPaths.forEach(child => { + if (!childrenCollapsedByDefault && !draft.toggled.includes(child)) { + draft.toggled.push(child); + } else if (childrenCollapsedByDefault && draft.toggled.includes(child)) { + draft.toggled = draft.toggled.filter(i => i !== child); + } + }) + } else if (draft.toggled.includes(contextPath)) { draft.toggled = draft.toggled.filter(i => i !== contextPath); } else { draft.toggled.push(contextPath); diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/Node/index.js b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/Node/index.js index 1b61b760e4..1c4bfac2dd 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/Node/index.js +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/Node/index.js @@ -358,9 +358,23 @@ export default class Node extends PureComponent { ); } - handleNodeToggle = () => { - const {node, onNodeToggle} = this.props; - onNodeToggle(node.contextPath); + handleNodeToggle = (e) => { + const {node, onNodeToggle, childNodes, isContentTreeNode, loadingDepth, rootNode} = this.props; + const children = [...childNodes]; + const childrenLoaded = children[0] !== undefined; + const childrenContextPaths = []; + let childrenCollapsedByDefault = false; + + if (childrenLoaded) { + childrenCollapsedByDefault = loadingDepth === 0 ? false : (node.depth + 1) - rootNode.depth >= loadingDepth; + const childrenWithChildren = children.filter((child) => child.children.length > (isContentTreeNode ? 0 : 1)); + + childrenWithChildren.forEach(child => { + childrenContextPaths.push(child.contextPath); + }) + } + + onNodeToggle(node.contextPath, e.shiftKey, childrenContextPaths, childrenCollapsedByDefault); } handleNodeClick = e => { diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js index 5efdd420b5..5fb624fcc8 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js @@ -39,10 +39,9 @@ export default class NodeTree extends PureComponent { currentlyDraggedNodes: [] }; - handleToggle = contextPath => { + handleToggle = (contextPath, collapseChildren, childrenContextPaths, childrenCollapsedByDefault) => { const {toggle} = this.props; - - toggle(contextPath); + toggle(contextPath, collapseChildren, childrenContextPaths, childrenCollapsedByDefault); } handleFocus = (contextPath, metaKeyPressed, altKeyPressed, shiftKeyPressed) => { diff --git a/packages/react-ui-components/src/Tree/node.module.css b/packages/react-ui-components/src/Tree/node.module.css index 1c2299216c..e3b4395c08 100644 --- a/packages/react-ui-components/src/Tree/node.module.css +++ b/packages/react-ui-components/src/Tree/node.module.css @@ -18,7 +18,7 @@ cursor: pointer; - &:hover { + &:hover > svg { color: var(--colors-PrimaryBlue); } } @@ -43,6 +43,11 @@ display: inline-block; position: absolute; text-align: center; + + .header:hover & > svg, + .header__data--isActive & > svg { + color: var(--colors-PrimaryBlue); + } } .header__data { @@ -100,6 +105,7 @@ composes: reset from '../reset.module.css'; margin-left: 2em; + .header:hover &, .header__data--isActive & { color: var(--colors-PrimaryBlue); } @@ -119,6 +125,7 @@ [data-is-drag-happening] & { visibility: visible; + height: 5px; } } .dropTarget--before {