Skip to content

Commit

Permalink
Multiple bug fixes for resizable container (#3699)
Browse files Browse the repository at this point in the history
* Bugfixes for resizable panels including arrow keys, nested panels, and mixed button sizes

* changelog
  • Loading branch information
chandlerprall committed Jul 7, 2020
1 parent 4cd2822 commit 4c0eb12
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 14 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
- Added SASS helper files for EUI theme globals ([#3691](https://github.com/elastic/eui/pull/3691))
- Add `label`, `labelProps` and `valueText` props to `EuiProgress` ([#3661](https://github.com/elastic/eui/pull/3661))

**Bug fixes**

- Fixed a bug in `EuiResizableContainer` preventing nested containers ([#3699](https://github.com/elastic/eui/pull/3699))
- Fixed a bug in `EuiResizableContainer` preventing resizing by arrow keys in some cases ([#3699](https://github.com/elastic/eui/pull/3699))

## [`26.3.0`](https://github.com/elastic/eui/tree/v26.3.0)

- Expanded `EuiBasicTable`'s default action's name configuration to accept any React node ([#3688](https://github.com/elastic/eui/pull/3688))
Expand Down
13 changes: 13 additions & 0 deletions src/components/resizable_container/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface EuiResizablePanelController {

export class EuiResizablePanelRegistry {
private panels: { [key: string]: EuiResizablePanelController } = {};
private resizerRefs = new Set<HTMLElement>();

registerPanel(panel: EuiResizablePanelController) {
this.panels[panel.id] = panel;
Expand All @@ -37,10 +38,22 @@ export class EuiResizablePanelRegistry {
delete this.panels[id];
}

registerResizerRef(resizerRef: HTMLElement) {
this.resizerRefs.add(resizerRef);
}

deregisterResizerRef(resizerRef: HTMLElement) {
this.resizerRefs.delete(resizerRef);
}

getResizerSiblings(prevPanelId: string, nextPanelId: string) {
return [this.panels[prevPanelId], this.panels[nextPanelId]];
}

getAllResizers() {
return Array.from(this.resizerRefs);
}

fetchAllPanels(
prevPanelId: string,
nextPanelId: string,
Expand Down
24 changes: 11 additions & 13 deletions src/components/resizable_container/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,13 @@ export const useContainerCallbacks = ({

const getResizerButtonsSize = useCallback(() => {
// get sum of all of resizer button sizes to proper calculate panels ratio
const allResizers = containerRef.current!.getElementsByClassName(
'euiResizableButton'
) as HTMLCollectionOf<HTMLButtonElement>;
const size = isHorizontal
? allResizers[0].offsetWidth
: allResizers[0].offsetHeight;

return size * allResizers.length;
}, [containerRef, isHorizontal]);
const allResizers = registryRef.current.getAllResizers();
return allResizers.reduce(
(size, resizer) =>
size + (isHorizontal ? resizer.offsetWidth : resizer.offsetHeight),
0
);
}, [registryRef, isHorizontal]);

const onMouseDown = useCallback(
(event: EuiResizableButtonMouseEvent) => {
Expand Down Expand Up @@ -150,16 +148,16 @@ export const useContainerCallbacks = ({
nextPanelId,
containerSize - resizersSize
);
if (prevPanelSize !== nextPanelSize && onPanelWidthChange) {

if (onPanelWidthChange) {
onPanelWidthChange({
...panelObject,
[prevPanelId]: prevPanelSize,
[nextPanelId]: nextPanelSize,
});

prevPanel.setSize(prevPanelSize);
nextPanel.setSize(nextPanelSize);
}
prevPanel.setSize(prevPanelSize);
nextPanel.setSize(nextPanelSize);
}
},
// `setState` is safe to omit from `useCallback`
Expand Down
22 changes: 22 additions & 0 deletions src/components/resizable_container/resizable_button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ import React, {
KeyboardEvent,
MouseEvent,
TouchEvent,
useCallback,
useRef,
} from 'react';
import classNames from 'classnames';

import { CommonProps } from '../common';
import { EuiI18n } from '../i18n';
import { EuiResizablePanelRegistry } from './context';

export type EuiResizableButtonMouseEvent =
| MouseEvent<HTMLButtonElement>
Expand All @@ -41,6 +44,7 @@ interface EuiResizableButtonControls {
onMouseDown: (eve: EuiResizableButtonMouseEvent) => void;
onTouchStart: (eve: EuiResizableButtonMouseEvent) => void;
isHorizontal: boolean;
registryRef: React.MutableRefObject<EuiResizablePanelRegistry>;
}

export interface EuiResizableButtonProps
Expand Down Expand Up @@ -69,6 +73,7 @@ export const EuiResizableButton: FunctionComponent<EuiResizableButtonProps> = ({
isHorizontal,
className,
size = 'm',
registryRef,
...rest
}) => {
const classes = classNames(
Expand All @@ -81,6 +86,22 @@ export const EuiResizableButton: FunctionComponent<EuiResizableButtonProps> = ({
className
);

const previousRef = useRef<HTMLElement>();
const onRef = useCallback(
(ref: HTMLElement | null) => {
if (ref) {
previousRef.current = ref;
registryRef!.current.registerResizerRef(ref);
} else {
if (previousRef.current != null) {
registryRef!.current.deregisterResizerRef(previousRef.current);
previousRef.current = undefined;
}
}
},
[registryRef]
);

const setFocus = (e: MouseEvent<HTMLButtonElement>) =>
e.currentTarget.focus();

Expand All @@ -96,6 +117,7 @@ export const EuiResizableButton: FunctionComponent<EuiResizableButtonProps> = ({
]}>
{([horizontalResizerAriaLabel, verticalResizerAriaLabel]: string[]) => (
<button
ref={onRef}
aria-label={
isHorizontal ? horizontalResizerAriaLabel : verticalResizerAriaLabel
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/resizable_container/resizable_container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,9 @@ export const EuiResizableContainer: FunctionComponent<
onMouseDown,
onTouchStart: onMouseDown,
isHorizontal,
registryRef,
}),
[onKeyDown, onMouseDown, isHorizontal]
[onKeyDown, onMouseDown, isHorizontal, registryRef]
);

const EuiResizablePanel = useCallback(
Expand Down

0 comments on commit 4c0eb12

Please sign in to comment.