From ebaf71ec683aebed1fc05b868ff2462ab27c3401 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 14 Jun 2024 12:16:19 +0200 Subject: [PATCH] TASK: Decouple Drawer from redux store --- packages/neos-ui/package.json | 2 + .../neos-ui/src/Containers/Drawer/Drawer.tsx | 60 ++++++++++++------- .../Drawer/MenuItemGroup/MenuItemGroup.tsx | 8 ++- .../neos-ui/src/Containers/Drawer/index.ts | 2 +- .../MenuToggler/MenuToggler.tsx | 22 +++---- yarn.lock | 2 + 6 files changed, 55 insertions(+), 41 deletions(-) diff --git a/packages/neos-ui/package.json b/packages/neos-ui/package.json index 2b4845b352..dec01a3f3d 100644 --- a/packages/neos-ui/package.json +++ b/packages/neos-ui/package.json @@ -17,6 +17,8 @@ "@fortawesome/free-regular-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.15.3", "@friendsofreactjs/react-css-themr": "~4.2.0", + "@neos-project/framework-observable": "workspace:*", + "@neos-project/framework-observable-react": "workspace:*", "@neos-project/neos-ts-interfaces": "workspace:*", "@neos-project/neos-ui-backend-connector": "workspace:*", "@neos-project/neos-ui-ckeditor5-bindings": "workspace:*", diff --git a/packages/neos-ui/src/Containers/Drawer/Drawer.tsx b/packages/neos-ui/src/Containers/Drawer/Drawer.tsx index b6790ef438..325ac24999 100644 --- a/packages/neos-ui/src/Containers/Drawer/Drawer.tsx +++ b/packages/neos-ui/src/Containers/Drawer/Drawer.tsx @@ -9,37 +9,49 @@ */ import React from 'react'; import mergeClassNames from 'classnames'; -// @ts-ignore -import {connect} from 'react-redux'; -import {actions} from '@neos-project/neos-ui-redux-store'; import {neos} from '@neos-project/neos-ui-decorators'; -import {GlobalState} from '@neos-project/neos-ui-redux-store/src/System'; import {SynchronousRegistry} from '@neos-project/neos-ui-extensibility'; +import {createState} from '@neos-project/framework-observable'; +import {useLatestState} from '@neos-project/framework-observable-react'; import MenuItemGroup from './MenuItemGroup/index'; import style from './style.module.css'; import {THRESHOLD_MOUSE_LEAVE} from './constants'; -const withReduxState = connect((state: GlobalState) => ({ - isHidden: state?.ui?.drawer?.isHidden, - collapsedMenuGroups: state?.ui?.drawer?.collapsedMenuGroups -}), { - hideDrawer: actions.UI.Drawer.hide, - toggleMenuGroup: actions.UI.Drawer.toggleMenuGroup -}); - const withNeosGlobals = neos(globalRegistry => ({ containerRegistry: globalRegistry.get('containers') })); -const StatelessDrawer: React.FC<{ - isHidden: boolean; - collapsedMenuGroups: string[], +export const drawer$ = createState({ + isHidden: true, + collapsedMenuGroups: [] as string[] +}); - hideDrawer: () => void; - toggleMenuGroup: (menuGroup: string) => void; +export function toggleDrawer() { + drawer$.update((state) => ({ + ...state, + isHidden: !state.isHidden + })); +} +function hideDrawer() { + drawer$.update((state) => ({ + ...state, + isHidden: true + })); +} + +function toggleMenuGroup(menuGroupId: string) { + drawer$.update((state) => ({ + ...state, + collapsedMenuGroups: state.collapsedMenuGroups.includes(menuGroupId) + ? state.collapsedMenuGroups.filter((m) => m !== menuGroupId) + : [...state.collapsedMenuGroups, menuGroupId] + })); +} + +const StatelessDrawer: React.FC<{ containerRegistry: SynchronousRegistry; menuData: { @@ -57,6 +69,7 @@ const StatelessDrawer: React.FC<{ }[]; }[]; }> = (props) => { + const {isHidden, collapsedMenuGroups} = useLatestState(drawer$); const mouseLeaveTimeoutRef = React.useRef>(null); const handleMouseEnter = React.useCallback(() => { if (mouseLeaveTimeoutRef.current) { @@ -67,12 +80,12 @@ const StatelessDrawer: React.FC<{ const handleMouseLeave = React.useCallback(() => { if (!mouseLeaveTimeoutRef.current) { mouseLeaveTimeoutRef.current = setTimeout(() => { - props.hideDrawer(); + hideDrawer(); mouseLeaveTimeoutRef.current = null; }, THRESHOLD_MOUSE_LEAVE); } - }, [props.hideDrawer]); - const {isHidden, menuData, collapsedMenuGroups, toggleMenuGroup, containerRegistry} = props; + }, []); + const {menuData, containerRegistry} = props; const classNames = mergeClassNames({ [style.drawer]: true, [style['drawer--isHidden']]: isHidden @@ -91,8 +104,9 @@ const StatelessDrawer: React.FC<{ {Object.entries(menuData).map(([menuGroup, menuGroupConfiguration]) => ( toggleMenuGroup(menuGroup)} + id={menuGroup} + collapsed={collapsedMenuGroups.includes(menuGroup)} + onMenuGroupToggle={toggleMenuGroup} {...menuGroupConfiguration} /> ))} @@ -104,4 +118,4 @@ const StatelessDrawer: React.FC<{ ); } -export const Drawer = withReduxState(withNeosGlobals(StatelessDrawer as any)); +export const Drawer = withNeosGlobals(StatelessDrawer as any); diff --git a/packages/neos-ui/src/Containers/Drawer/MenuItemGroup/MenuItemGroup.tsx b/packages/neos-ui/src/Containers/Drawer/MenuItemGroup/MenuItemGroup.tsx index 1caa4a2cf3..09d97f96d4 100644 --- a/packages/neos-ui/src/Containers/Drawer/MenuItemGroup/MenuItemGroup.tsx +++ b/packages/neos-ui/src/Containers/Drawer/MenuItemGroup/MenuItemGroup.tsx @@ -17,12 +17,13 @@ import MenuItem from '../MenuItem/index'; import style from '../style.module.css'; export const MenuItemGroup: React.FC<{ + id: string; icon?: string; label: string; uri: string; target?: string; collapsed: boolean; - handleMenuGroupToggle: () => void; + onMenuGroupToggle: (menuGroupId: string) => void; children: { icon?: string; label: string; @@ -31,7 +32,10 @@ export const MenuItemGroup: React.FC<{ skipI18n?: boolean; }[]; }> = (props) => { - const {label, icon, children, uri, collapsed, handleMenuGroupToggle} = props; + const {label, icon, children, uri, collapsed} = props; + const handleMenuGroupToggle = React.useCallback(() => { + props.onMenuGroupToggle(props.id); + }, [props.id]) return ( diff --git a/packages/neos-ui/src/Containers/Drawer/index.ts b/packages/neos-ui/src/Containers/Drawer/index.ts index 6ab04ce43b..122c4c1382 100644 --- a/packages/neos-ui/src/Containers/Drawer/index.ts +++ b/packages/neos-ui/src/Containers/Drawer/index.ts @@ -7,4 +7,4 @@ * information, please view the LICENSE file which was distributed with this * source code. */ -export {Drawer as default} from './Drawer'; +export {Drawer as default, drawer$, toggleDrawer} from './Drawer'; diff --git a/packages/neos-ui/src/Containers/PrimaryToolbar/MenuToggler/MenuToggler.tsx b/packages/neos-ui/src/Containers/PrimaryToolbar/MenuToggler/MenuToggler.tsx index bab8ff0f7f..96b7cce780 100644 --- a/packages/neos-ui/src/Containers/PrimaryToolbar/MenuToggler/MenuToggler.tsx +++ b/packages/neos-ui/src/Containers/PrimaryToolbar/MenuToggler/MenuToggler.tsx @@ -8,15 +8,14 @@ * source code. */ import React from 'react'; -// @ts-ignore -import {connect} from 'react-redux'; import mergeClassNames from 'classnames'; import Button from '@neos-project/react-ui-components/src/Button/'; -import {actions} from '@neos-project/neos-ui-redux-store'; -import {GlobalState} from '@neos-project/neos-ui-redux-store/src/System'; import {neos} from '@neos-project/neos-ui-decorators'; import {I18nRegistry} from '@neos-project/neos-ts-interfaces'; +import {useLatestState} from '@neos-project/framework-observable-react'; + +import {drawer$, toggleDrawer} from '../../Drawer'; import style from './style.module.css'; @@ -24,24 +23,17 @@ const withNeosGlobals = neos(globalRegistry => ({ i18nRegistry: globalRegistry.get('i18n') })); -const withReduxState = connect((state: GlobalState) => ({ - isMenuHidden: state?.ui?.drawer?.isHidden -}), { - toggleDrawer: actions.UI.Drawer.toggle -}); - const StatelessMenuToggler: React.FC<{ i18nRegistry: I18nRegistry; className?: string; - isMenuHidden: boolean; - toggleDrawer: () => void; }> = (props) => { const handleToggle = React.useCallback(() => { - props.toggleDrawer(); + toggleDrawer(); }, []); - const {className, isMenuHidden, i18nRegistry} = props; + const {className, i18nRegistry} = props; + const {isHidden: isMenuHidden} = useLatestState(drawer$); const isMenuVisible = !isMenuHidden; const classNames = mergeClassNames({ [style.menuToggler]: true, @@ -70,4 +62,4 @@ const StatelessMenuToggler: React.FC<{ ); } -export const MenuToggler = withNeosGlobals(withReduxState(StatelessMenuToggler)); +export const MenuToggler = withNeosGlobals(StatelessMenuToggler as any); diff --git a/yarn.lock b/yarn.lock index 34839c6b44..c681ebe350 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2632,6 +2632,8 @@ __metadata: "@fortawesome/free-solid-svg-icons": ^5.15.3 "@friendsofreactjs/react-css-themr": ~4.2.0 "@neos-project/debug-reason-for-rendering": "workspace:*" + "@neos-project/framework-observable": "workspace:*" + "@neos-project/framework-observable-react": "workspace:*" "@neos-project/jest-preset-neos-ui": "workspace:*" "@neos-project/neos-ts-interfaces": "workspace:*" "@neos-project/neos-ui-backend-connector": "workspace:*"