Skip to content

Commit

Permalink
Make open animation smoother
Browse files Browse the repository at this point in the history
  • Loading branch information
Heenawter committed Feb 4, 2025
1 parent 57268f4 commit 41f467a
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 201 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import classNames from 'classnames';
import { cloneDeep } from 'lodash';
import React, { useEffect, useLayoutEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
import { combineLatest, map, pairwise, skip } from 'rxjs';

import { css } from '@emotion/react';
Expand Down Expand Up @@ -155,6 +155,12 @@ export const GridRow = ({
);
}, [panelIds, gridLayoutStateManager, renderPanelContents, rowIndex]);

const toggleIsCollapsed = useCallback(() => {
const newLayout = cloneDeep(gridLayoutStateManager.gridLayout$.value);
newLayout[rowIndex].isCollapsed = !newLayout[rowIndex].isCollapsed;
gridLayoutStateManager.gridLayout$.next(newLayout);
}, [rowIndex, gridLayoutStateManager.gridLayout$]);

return (
<div
id={`kbnGridLayoutRow--${rowIndex}`}
Expand All @@ -167,11 +173,7 @@ export const GridRow = ({
<GridRowHeader
rowIndex={rowIndex}
gridLayoutStateManager={gridLayoutStateManager}
toggleIsCollapsed={() => {
const newLayout = cloneDeep(gridLayoutStateManager.gridLayout$.value);
newLayout[rowIndex].isCollapsed = !newLayout[rowIndex].isCollapsed;
gridLayoutStateManager.gridLayout$.next(newLayout);
}}
toggleIsCollapsed={toggleIsCollapsed}
/>
)}
{!isCollapsed && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,125 +19,128 @@ import { DeleteGridRowModal } from './delete_grid_row_modal';
import { GridRowTitle } from './grid_row_title';
import { useGridRowHeaderStyles } from './use_grid_row_header_styles';

export const GridRowHeader = ({
rowIndex,
gridLayoutStateManager,
toggleIsCollapsed,
}: {
rowIndex: number;
gridLayoutStateManager: GridLayoutStateManager;
toggleIsCollapsed: () => void;
}) => {
const headerStyles = useGridRowHeaderStyles();
export const GridRowHeader = React.memo(
({
rowIndex,
gridLayoutStateManager,
toggleIsCollapsed,
}: {
rowIndex: number;
gridLayoutStateManager: GridLayoutStateManager;
toggleIsCollapsed: () => void;
}) => {
const headerStyles = useGridRowHeaderStyles();

const [editTitleOpen, setEditTitleOpen] = useState<boolean>(false);
const [deleteModalVisible, setDeleteModalVisible] = useState<boolean>(false);
const [readOnly, setReadOnly] = useState<boolean>(
gridLayoutStateManager.accessMode$.getValue() === 'VIEW'
);
const [editTitleOpen, setEditTitleOpen] = useState<boolean>(false);
const [deleteModalVisible, setDeleteModalVisible] = useState<boolean>(false);
const [readOnly, setReadOnly] = useState<boolean>(
gridLayoutStateManager.accessMode$.getValue() === 'VIEW'
);

useEffect(() => {
const accessModeSubscription = gridLayoutStateManager.accessMode$
.pipe(distinctUntilChanged())
.subscribe((accessMode) => {
setReadOnly(accessMode === 'VIEW');
});
useEffect(() => {
const accessModeSubscription = gridLayoutStateManager.accessMode$
.pipe(distinctUntilChanged())
.subscribe((accessMode) => {
setReadOnly(accessMode === 'VIEW');
});

return () => {
accessModeSubscription.unsubscribe();
};
}, [gridLayoutStateManager]);
return () => {
accessModeSubscription.unsubscribe();
};
}, [gridLayoutStateManager]);

return (
<>
<EuiFlexGroup
gutterSize="xs"
alignItems="center"
css={headerStyles}
className="kbnGridRowHeader"
>
<EuiFlexItem grow={false}>
<EuiButtonIcon
color="text"
aria-label={i18n.translate('kbnGridLayout.row.toggleCollapse', {
defaultMessage: 'Toggle collapse',
})}
iconType={'arrowDown'}
onClick={toggleIsCollapsed}
css={styles.accordianArrow}
return (
<>
<EuiFlexGroup
gutterSize="xs"
alignItems="center"
css={headerStyles}
className="kbnGridRowHeader"
>
<EuiFlexItem grow={false}>
<EuiButtonIcon
color="text"
aria-label={i18n.translate('kbnGridLayout.row.toggleCollapse', {
defaultMessage: 'Toggle collapse',
})}
iconType={'arrowDown'}
onClick={toggleIsCollapsed}
css={styles.accordianArrow}
/>
</EuiFlexItem>
<GridRowTitle
rowIndex={rowIndex}
readOnly={readOnly}
toggleIsCollapsed={toggleIsCollapsed}
editTitleOpen={editTitleOpen}
setEditTitleOpen={setEditTitleOpen}
gridLayoutStateManager={gridLayoutStateManager}
/>
</EuiFlexItem>
<GridRowTitle
rowIndex={rowIndex}
readOnly={readOnly}
toggleIsCollapsed={toggleIsCollapsed}
editTitleOpen={editTitleOpen}
setEditTitleOpen={setEditTitleOpen}
gridLayoutStateManager={gridLayoutStateManager}
/>
{
/**
* Add actions at the end of the header section when the layout is editable + the section title
* is not in edit mode
*/
!editTitleOpen && (
<>
<EuiFlexItem grow={false} css={styles.hiddenOnCollapsed}>
<EuiText color="subdued" size="s">{`(${
/**
* we can get away with grabbing the panel count without React state because this count
* is only rendered when the section is collapsed, and the count can only be updated when
* the section isn't collapsed
*/
Object.keys(gridLayoutStateManager.gridLayout$.getValue()[rowIndex].panels).length
} panels)`}</EuiText>
</EuiFlexItem>
{!readOnly && (
<>
<EuiFlexItem grow={false}>
<EuiButtonIcon
iconType="trash"
color="danger"
className="kbnGridLayout--deleteRowIcon"
onClick={() => {
const panelCount = Object.keys(
gridLayoutStateManager.gridLayout$.getValue()[rowIndex].panels
).length;
if (!Boolean(panelCount)) {
const newLayout = deleteRow(
gridLayoutStateManager.gridLayout$.getValue(),
rowIndex
);
gridLayoutStateManager.gridLayout$.next(newLayout);
} else {
setDeleteModalVisible(true);
}
}}
/>
</EuiFlexItem>
<EuiFlexItem grow={false} css={[styles.hiddenOnCollapsed, styles.floatToRight]}>
<EuiButtonIcon
iconType="move"
color="text"
className="kbnGridLayout--moveRowIcon"
/>
</EuiFlexItem>
</>
)}
</>
)
}
</EuiFlexGroup>
{deleteModalVisible && (
<DeleteGridRowModal
rowIndex={rowIndex}
gridLayoutStateManager={gridLayoutStateManager}
setDeleteModalVisible={setDeleteModalVisible}
/>
)}
</>
);
};
{
/**
* Add actions at the end of the header section when the layout is editable + the section title
* is not in edit mode
*/
!editTitleOpen && (
<>
<EuiFlexItem grow={false} css={styles.hiddenOnCollapsed}>
<EuiText color="subdued" size="s">{`(${
/**
* we can get away with grabbing the panel count without React state because this count
* is only rendered when the section is collapsed, and the count can only be updated when
* the section isn't collapsed
*/
Object.keys(gridLayoutStateManager.gridLayout$.getValue()[rowIndex].panels)
.length
} panels)`}</EuiText>
</EuiFlexItem>
{!readOnly && (
<>
<EuiFlexItem grow={false}>
<EuiButtonIcon
iconType="trash"
color="danger"
className="kbnGridLayout--deleteRowIcon"
onClick={() => {
const panelCount = Object.keys(
gridLayoutStateManager.gridLayout$.getValue()[rowIndex].panels
).length;
if (!Boolean(panelCount)) {
const newLayout = deleteRow(
gridLayoutStateManager.gridLayout$.getValue(),
rowIndex
);
gridLayoutStateManager.gridLayout$.next(newLayout);
} else {
setDeleteModalVisible(true);
}
}}
/>
</EuiFlexItem>
<EuiFlexItem grow={false} css={[styles.hiddenOnCollapsed, styles.floatToRight]}>
<EuiButtonIcon
iconType="move"
color="text"
className="kbnGridLayout--moveRowIcon"
/>
</EuiFlexItem>
</>
)}
</>
)
}
</EuiFlexGroup>
{deleteModalVisible && (
<DeleteGridRowModal
rowIndex={rowIndex}
gridLayoutStateManager={gridLayoutStateManager}
setDeleteModalVisible={setDeleteModalVisible}
/>
)}
</>
);
}
);

const styles = {
accordianArrow: css({
Expand Down
Loading

0 comments on commit 41f467a

Please sign in to comment.