Skip to content

Commit

Permalink
fix submenu positioning on sidebar collapsed
Browse files Browse the repository at this point in the history
  • Loading branch information
azouaoui-med committed May 26, 2020
1 parent ff2f142 commit bf28db2
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- use direction:rtl instead of row-reverse
- fix submenu positioning on sidebar collapsed using popperjs and resize-observer-polyfill for resize event listener

## [0.3.0] - 2020-05-11

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@
]
},
"dependencies": {
"@popperjs/core": "^2.4.0",
"classnames": "^2.2.6",
"react-slidedown": "^2.4.5"
"react-slidedown": "^2.4.5",
"resize-observer-polyfill": "^1.5.1"
}
}
1 change: 1 addition & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ export default {
],
}),
],
external: ['react', 'react-dom', 'prop-types'],
};
7 changes: 5 additions & 2 deletions src/ProSidebar/Menu/Menu.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/* eslint-disable react/no-array-index-key */
import React, { forwardRef, LegacyRef } from 'react';
import classNames from 'classnames';

export type IconShapeType = 'square' | 'round' | 'circle';

export interface Props {
className?: string;
children?: React.ReactNode;
children?: any;
iconShape?: IconShapeType;
}

Expand All @@ -23,7 +24,9 @@ const Menu: React.ForwardRefRenderFunction<unknown, Props> = (
[`shaped ${iconShape}`]: ['square', 'round', 'circle'].indexOf(iconShape) >= 0,
})}
>
<ul>{children}</ul>
<ul>
{React.Children.map(children, (child) => React.cloneElement(child, { firstchild: 1 }))}
</ul>
</nav>
);
};
Expand Down
80 changes: 72 additions & 8 deletions src/ProSidebar/Menu/SubMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React, { useState, forwardRef, LegacyRef } from 'react';
import React, { useState, forwardRef, LegacyRef, useRef, useEffect, useContext } from 'react';
import classNames from 'classnames';
import SlideDown from 'react-slidedown';
import { createPopper } from '@popperjs/core';
import ResizeObserver from 'resize-observer-polyfill';
import { SidebarContext } from '../ProSidebar';

export interface Props {
className?: string;
Expand All @@ -10,18 +13,67 @@ export interface Props {
open?: boolean;
prefix?: React.ReactNode;
suffix?: React.ReactNode;
firstchild?: boolean;
}

const SubMenu: React.ForwardRefRenderFunction<unknown, Props> = (
{ children, icon, className, title, defaultOpen = false, open, prefix, suffix, ...rest },
{
children,
icon,
className,
title,
defaultOpen = false,
open,
prefix,
suffix,
firstchild,
...rest
},
ref,
) => {
let popperInstance;
const { collapsed, rtl } = useContext(SidebarContext);
const [closed, setClosed] = useState(!defaultOpen);
const popperElRef = useRef();
const referenceElement = useRef();
const popperElement = useRef();

const handleToggleSubMenu = () => {
setClosed(!closed);
};

useEffect(() => {
if (firstchild) {
if (popperInstance) popperInstance.destroy();

if (referenceElement.current && popperElement.current) {
popperInstance = createPopper(referenceElement.current, popperElement.current, {
placement: 'right',
strategy: 'fixed',
modifiers: [
{
name: 'computeStyles',
options: {
adaptive: false,
},
},
],
});
}

if (popperElRef.current) {
const ro = new ResizeObserver(() => {
if (popperInstance) {
popperInstance.update();
}
});

ro.observe(popperElRef.current);
ro.observe(referenceElement.current);
}
}
}, [collapsed, rtl]);

const subMenuRef: LegacyRef<HTMLLIElement> = (ref as any) || React.createRef<HTMLLIElement>();

return (
Expand All @@ -33,6 +85,7 @@ const SubMenu: React.ForwardRefRenderFunction<unknown, Props> = (
>
<div
{...rest}
ref={referenceElement}
className="pro-inner-item"
onClick={handleToggleSubMenu}
onKeyPress={handleToggleSubMenu}
Expand All @@ -51,12 +104,23 @@ const SubMenu: React.ForwardRefRenderFunction<unknown, Props> = (
<span className="pro-arrow" />
</span>
</div>
<SlideDown
closed={typeof open === 'undefined' ? closed : !open}
className="pro-inner-list-item"
>
<ul>{children}</ul>
</SlideDown>

{firstchild && collapsed ? (
<div ref={popperElement} className="pro-inner-list-item">
<div ref={popperElRef}>
<ul>{children}</ul>
</div>
</div>
) : (
<SlideDown
closed={typeof open === 'undefined' ? closed : !open}
className="pro-inner-list-item"
>
<div ref={popperElRef}>
<ul>{children}</ul>
</div>
</SlideDown>
)}
</li>
);
};
Expand Down
43 changes: 33 additions & 10 deletions src/ProSidebar/ProSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { forwardRef, LegacyRef } from 'react';
import React, { forwardRef, LegacyRef, createContext, useEffect, useState } from 'react';
import '../scss/styles.scss';
import classNames from 'classnames';

Expand All @@ -11,21 +11,44 @@ export interface Props {
children?: React.ReactNode;
}

export interface SidebarContextProps {
collapsed: boolean;
rtl: boolean;
}

export const SidebarContext = createContext<SidebarContextProps>({
collapsed: false,
rtl: false,
});

const ProSidebar: React.ForwardRefRenderFunction<unknown, Props> = (
{ children, className, width, collapsed, rtl, image, ...rest },
ref,
) => {
const [sidebarState, setSidebarState] = useState({ collapsed: false, rtl: false });

const sidebarRef: LegacyRef<HTMLDivElement> = (ref as any) || React.createRef<HTMLDivElement>();

useEffect(() => {
setSidebarState({ ...sidebarState, collapsed });
}, [collapsed]);

useEffect(() => {
setSidebarState({ ...sidebarState, rtl });
}, [rtl]);

return (
<div
{...rest}
ref={sidebarRef}
className={classNames('pro-sidebar', className, { collapsed, rtl })}
style={{ width }}
>
{image ? <img src={image} alt="sidebar background" className="sidebar-bg" /> : null}
<div className="pro-sidebar-inner">{children}</div>
</div>
<SidebarContext.Provider value={sidebarState}>
<div
{...rest}
ref={sidebarRef}
className={classNames('pro-sidebar', className, { collapsed, rtl })}
style={{ width }}
>
{image ? <img src={image} alt="sidebar background" className="sidebar-bg" /> : null}
<div className="pro-sidebar-inner">{children}</div>
</div>
</SidebarContext.Provider>
);
};

Expand Down
7 changes: 5 additions & 2 deletions src/scss/partials/_menu.scss
Original file line number Diff line number Diff line change
Expand Up @@ -254,12 +254,15 @@
position: fixed;
left: $sidebar-collapsed-width;
transform: translateY(-50px);
display: none !important;
visibility: hidden;
width: 270px;
max-height: 100%;
overflow-y: auto;
}
&:hover {
> .pro-inner-list-item {
display: block !important;
transition: transform 0.3s;
visibility: visible;
}
.pro-icon-wrapper {
.pro-icon {
Expand Down
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
"@nodelib/fs.scandir" "2.1.3"
fastq "^1.6.0"

"@popperjs/core@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.4.0.tgz#0e1bdf8d021e7ea58affade33d9d607e11365915"
integrity sha512-NMrDy6EWh9TPdSRiHmHH2ye1v5U0gBD7pRYwSwJvomx7Bm4GG04vu63dYiVzebLOx2obPpJugew06xVP0Nk7hA==

"@rollup/plugin-commonjs@^11.1.0":
version "11.1.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-11.1.0.tgz#60636c7a722f54b41e419e1709df05c7234557ef"
Expand Down Expand Up @@ -3504,6 +3509,11 @@ require-main-filename@^2.0.0:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==

resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==

resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
Expand Down

0 comments on commit bf28db2

Please sign in to comment.