Removed unnecessary layout effect in favor of a setState

This commit is contained in:
Brian Vaughn
2019-04-07 15:19:17 -07:00
parent 2e5e88e127
commit 2ac815784b
2 changed files with 118 additions and 130 deletions
+14 -31
View File
@@ -5,7 +5,7 @@
}
.Component,
.FocusedComponent {
.SelectedComponent {
padding: 0.25rem;
margin-right: 0.5rem;
color: var(--color-component-name);
@@ -14,11 +14,8 @@
border-radius: 0.125rem;
border: none;
background: none;
}
.Component {
cursor: pointer;
color: var(--color-component-name);
text-align: left;
}
.Component:hover {
background-color: var(--color-hover-background);
@@ -28,52 +25,38 @@
background-color: var(--color-hover-background);
}
.FocusedComponent {
.SelectedComponent {
background-color: var(--color-selected-background);
color: var(--color-selected-foreground);
}
.FocusedComponent:focus {
.SelectedComponent:focus {
outline: none;
}
.ElementsBar {
.Bar {
display: flex;
flex: 1 0 auto;
}
.ElementsBarSelectedOnly {
margin-left: 0.25rem;
.Toggle {
margin-right: 0.5rem;
}
.ElementsBarSelectedOnly .Component {
visibility: hidden;
}
.ElementsBarSelectedOnly .FocusedComponent {
float: left;
}
.ElementsDropdown {
.DropdownWrapper {
display: inline-block;
position: relative;
}
.Dropdown {
z-index: 1;
position: absolute;
top: calc(100% + 5px);
top: calc(100% + 0.25rem);
left: 0;
background-color: var(--color-background);
border: 1px solid var(--color-selected-border);
overflow-y: auto;
}
.Dropdown .Component,
.Dropdown .FocusedComponent {
display: block;
margin: 0.25rem 0.75rem 0.35rem;
}
.DropdownButtonActive {
background-color: var(--color-selected-background);
color: var(--color-selected-foreground);
max-height: 10rem;
display: flex;
flex-direction: column;
}
.VRule {
+104 -99
View File
@@ -3,13 +3,12 @@ import React, {
useCallback,
useContext,
useLayoutEffect,
useRef,
useState,
createRef,
forwardRef,
} from 'react';
import classNames from 'classnames';
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
import Toggle from '../Toggle';
import { TreeContext } from './TreeContext';
import { StoreContext } from '../context';
import { useIsOverflowing } from '../hooks';
@@ -18,100 +17,15 @@ import type { Element } from './types';
import styles from './OwnersStack.css';
type ElementsDropdownProps = {
selectedElementIndex: number | null,
children: Array<any>,
};
function ElementsDropdown({
selectedElementIndex,
children,
}: ElementsDropdownProps) {
const [isDropdownVisible, setIsDropdownVisible] = useState(false);
const handleClick = useCallback(() => {
setIsDropdownVisible(!isDropdownVisible);
}, [isDropdownVisible, setIsDropdownVisible]);
useLayoutEffect(() => {
setIsDropdownVisible(false);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedElementIndex]);
return (
<div className={styles.ElementsDropdown}>
<Button
className={classNames(styles.IconButton, {
[styles.DropdownButtonActive]: isDropdownVisible,
})}
onClick={handleClick}
title="Open elements dropdown"
>
<ButtonIcon type="more" />
</Button>
{isDropdownVisible && <div className={styles.Dropdown}>{children}</div>}
</div>
);
}
type ElementsBarProps = {
elements: Array<any>,
showSelectedOnly: boolean,
};
const ElementsBar = forwardRef(
({ elements, showSelectedOnly }: ElementsBarProps, ref: Object) => {
return (
<div
className={classNames(styles.ElementsBar, {
[styles.ElementsBarSelectedOnly]: showSelectedOnly,
})}
ref={ref}
>
{elements}
</div>
);
}
);
type ElementViewProps = {
id: number,
index: number,
};
function ElementView({ id, index }: ElementViewProps) {
const { ownerStackIndex, selectOwner } = useContext(TreeContext);
const store = useContext(StoreContext);
const { displayName } = ((store.getElementByID(id): any): Element);
const isSelected = ownerStackIndex === index;
const handleClick = useCallback(() => {
if (!isSelected) {
selectOwner(id);
}
}, [id, isSelected, selectOwner]);
return (
<button
className={isSelected ? styles.FocusedComponent : styles.Component}
onClick={handleClick}
>
{displayName}
</button>
);
}
export default function OwnerStack() {
const { ownerStack, ownerStackIndex, resetOwnerStack } = useContext(
TreeContext
);
const [elementsTotalWidth, setElementsTotalWidth] = useState(0);
const elementsBarRef = createRef<HTMLDivElement | null>();
const elementsBarRef = useRef<HTMLDivElement | null>(null);
const isOverflowing = useIsOverflowing(elementsBarRef, elementsTotalWidth);
const elements = ownerStack.map((id, index) => (
<ElementView key={id} id={id} index={index} />
));
useLayoutEffect(() => {
if (elementsBarRef.current === null) {
return () => {};
@@ -140,17 +54,108 @@ export default function OwnerStack() {
>
<ButtonIcon type="close" />
</Button>
{isOverflowing && (
<ElementsDropdown selectedElementIndex={ownerStackIndex}>
{elements}
</ElementsDropdown>
)}
<div className={styles.VRule} />
<ElementsBar
elements={elements}
showSelectedOnly={isOverflowing}
ref={elementsBarRef}
/>
<div className={styles.Bar} ref={elementsBarRef}>
{isOverflowing && (
<ElementsDropdown
ownerStack={ownerStack}
ownerStackIndex={ownerStackIndex}
/>
)}
{isOverflowing ? (
<ElementView
id={ownerStack[((ownerStackIndex: any): number)]}
index={ownerStackIndex}
/>
) : (
ownerStack.map((id, index) => (
<ElementView key={id} id={id} index={index} />
))
)}
</div>
</div>
);
}
type ElementsDropdownProps = {
ownerStack: Array<number>,
ownerStackIndex: number | null,
};
function ElementsDropdown({
ownerStack,
ownerStackIndex,
}: ElementsDropdownProps) {
const store = useContext(StoreContext);
const { selectOwner } = useContext(TreeContext);
const [isDropdownVisible, setIsDropdownVisible] = useState(false);
const handleDropdownButtonClick = useCallback(() => {
setIsDropdownVisible(!isDropdownVisible);
}, [isDropdownVisible, setIsDropdownVisible]);
const handleElementClick = useCallback(
(id: number) => {
selectOwner(id);
setIsDropdownVisible(false);
},
[selectOwner, setIsDropdownVisible]
);
return (
<div className={styles.DropdownWrapper}>
<Toggle
className={styles.Toggle}
isChecked={isDropdownVisible}
onChange={handleDropdownButtonClick}
title="Open elements dropdown"
>
<ButtonIcon type="more" />
</Toggle>
{isDropdownVisible && (
<div className={styles.Dropdown}>
{ownerStack.map((id, index) => (
<button
className={
ownerStackIndex === index
? styles.SelectedComponent
: styles.Component
}
onClick={() => handleElementClick(id)}
>
{((store.getElementByID(id): any): Element).displayName}
</button>
))}
</div>
)}
</div>
);
}
type ElementViewProps = {
id: number,
index: number | null,
};
function ElementView({ id, index }: ElementViewProps) {
const store = useContext(StoreContext);
const { ownerStackIndex, selectOwner } = useContext(TreeContext);
const { displayName } = ((store.getElementByID(id): any): Element);
const isSelected = ownerStackIndex === index;
const handleClick = useCallback(() => {
if (!isSelected) {
selectOwner(id);
}
}, [id, isSelected, selectOwner]);
return (
<button
className={isSelected ? styles.SelectedComponent : styles.Component}
onClick={handleClick}
>
{displayName}
</button>
);
}