mirror of
https://github.com/strapi/strapi.git
synced 2025-09-27 09:25:46 +00:00
Merge pull request #13886 from strapi/feature/replace-virtualized-window
ComponentIconPicker: Replace react-virtualized with react-window
This commit is contained in:
commit
21b95f9954
@ -119,7 +119,7 @@
|
|||||||
"react-refresh": "0.11.0",
|
"react-refresh": "0.11.0",
|
||||||
"react-router": "5.2.0",
|
"react-router": "5.2.0",
|
||||||
"react-router-dom": "5.2.0",
|
"react-router-dom": "5.2.0",
|
||||||
"react-virtualized": "^9.22.3",
|
"react-window": "1.8.7",
|
||||||
"redux": "^4.0.1",
|
"redux": "^4.0.1",
|
||||||
"redux-saga": "^0.16.0",
|
"redux-saga": "^0.16.0",
|
||||||
"reselect": "^4.0.0",
|
"reselect": "^4.0.0",
|
||||||
|
@ -28,7 +28,7 @@ const aliasExactMatch = [
|
|||||||
'react-redux',
|
'react-redux',
|
||||||
'react-router',
|
'react-router',
|
||||||
'react-router-dom',
|
'react-router-dom',
|
||||||
'react-virtualized',
|
'react-window',
|
||||||
'react-select',
|
'react-select',
|
||||||
'redux',
|
'redux',
|
||||||
'reselect',
|
'reselect',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useEffect, useState, useRef } from 'react';
|
import React, { useEffect, useState, useRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { AutoSizer, Collection } from 'react-virtualized';
|
import { FixedSizeGrid } from 'react-window';
|
||||||
import { Searchbar } from '@strapi/design-system/Searchbar';
|
import { Searchbar } from '@strapi/design-system/Searchbar';
|
||||||
import { IconButton } from '@strapi/design-system/IconButton';
|
import { IconButton } from '@strapi/design-system/IconButton';
|
||||||
import Search from '@strapi/icons/Search';
|
import Search from '@strapi/icons/Search';
|
||||||
@ -10,11 +10,14 @@ import { Box } from '@strapi/design-system/Box';
|
|||||||
import { Flex } from '@strapi/design-system/Flex';
|
import { Flex } from '@strapi/design-system/Flex';
|
||||||
import { Stack } from '@strapi/design-system/Stack';
|
import { Stack } from '@strapi/design-system/Stack';
|
||||||
import { Typography } from '@strapi/design-system/Typography';
|
import { Typography } from '@strapi/design-system/Typography';
|
||||||
|
|
||||||
|
import { getIndexFromColAndRow } from './utils/getIndexFromColAndRow';
|
||||||
import useDataManager from '../../hooks/useDataManager';
|
import useDataManager from '../../hooks/useDataManager';
|
||||||
import getTrad from '../../utils/getTrad';
|
import getTrad from '../../utils/getTrad';
|
||||||
import Cell from './Cell';
|
import Cell from './Cell';
|
||||||
|
|
||||||
const CELL_WIDTH = 44;
|
const CELL_WIDTH = 42;
|
||||||
|
const COLUMN_COUNT = 18;
|
||||||
|
|
||||||
const ComponentIconPicker = ({ error, intlLabel, name, onChange, value }) => {
|
const ComponentIconPicker = ({ error, intlLabel, name, onChange, value }) => {
|
||||||
const { allIcons } = useDataManager();
|
const { allIcons } = useDataManager();
|
||||||
@ -37,26 +40,32 @@ const ComponentIconPicker = ({ error, intlLabel, name, onChange, value }) => {
|
|||||||
setIcons(() => allIcons.filter(icon => icon.includes(value)));
|
setIcons(() => allIcons.filter(icon => icon.includes(value)));
|
||||||
};
|
};
|
||||||
|
|
||||||
const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
|
// eslint-disable-next-line react/prop-types
|
||||||
|
const IconRenderer = ({ columnIndex, rowIndex, style }) => {
|
||||||
|
const icon = icons[getIndexFromColAndRow(columnIndex, rowIndex, COLUMN_COUNT)];
|
||||||
|
|
||||||
const cellSizeAndPositionGetter = ({ index }) => {
|
return (
|
||||||
const columnCount = 16;
|
<div style={style} key={`col-${columnIndex}`}>
|
||||||
const columnPosition = index % (columnCount || 1);
|
{icon && (
|
||||||
|
<Cell
|
||||||
const height = CELL_WIDTH;
|
style={{ width: '100%', height: '100%' }}
|
||||||
const width = CELL_WIDTH;
|
alignItems="center"
|
||||||
const x = columnPosition * (width + 1);
|
justifyContent="center"
|
||||||
const y = parseInt(index / 16, 10) * CELL_WIDTH;
|
onClick={() => {
|
||||||
|
onChange({ target: { name, value: icon } });
|
||||||
return {
|
}}
|
||||||
height,
|
isSelected={icon === value}
|
||||||
width,
|
as="button"
|
||||||
x,
|
type="button"
|
||||||
y,
|
>
|
||||||
};
|
<FontAwesomeIcon icon={icon} />
|
||||||
|
</Cell>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const cellCount = icons.length;
|
const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
@ -105,44 +114,17 @@ const ComponentIconPicker = ({ error, intlLabel, name, onChange, value }) => {
|
|||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
<Box background="neutral100" borderColor={error ? 'danger600' : ''} hasRadius>
|
<Box padding={1} background="neutral100" borderColor={error ? 'danger600' : ''} hasRadius>
|
||||||
<Box>
|
<FixedSizeGrid
|
||||||
<AutoSizer disableHeight>
|
columnCount={COLUMN_COUNT}
|
||||||
{({ width }) => {
|
columnWidth={CELL_WIDTH}
|
||||||
return (
|
height={132}
|
||||||
<Collection
|
rowHeight={CELL_WIDTH}
|
||||||
cellCount={cellCount}
|
rowCount={Math.ceil(icons.length / COLUMN_COUNT)}
|
||||||
cellRenderer={({ index, key, style }) => {
|
width={CELL_WIDTH * COLUMN_COUNT}
|
||||||
const icon = icons[index];
|
>
|
||||||
const isSelected = icon === value;
|
{IconRenderer}
|
||||||
const handleClick = () => {
|
</FixedSizeGrid>
|
||||||
onChange({ target: { name, value: icon } });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ ...style, width: CELL_WIDTH }} key={key}>
|
|
||||||
<Cell
|
|
||||||
style={{ width: '100%', height: CELL_WIDTH }}
|
|
||||||
alignItems="center"
|
|
||||||
justifyContent="center"
|
|
||||||
onClick={handleClick}
|
|
||||||
isSelected={isSelected}
|
|
||||||
as="button"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={icon} />
|
|
||||||
</Cell>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
cellSizeAndPositionGetter={cellSizeAndPositionGetter}
|
|
||||||
height={132}
|
|
||||||
width={width}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</AutoSizer>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
{error && (
|
{error && (
|
||||||
<Typography
|
<Typography
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
export const getIndexFromColAndRow = (columnIndex, rowIndex, numCols) => {
|
||||||
|
return columnIndex + rowIndex * numCols;
|
||||||
|
};
|
@ -0,0 +1,21 @@
|
|||||||
|
import { getIndexFromColAndRow } from '../getIndexFromColAndRow';
|
||||||
|
|
||||||
|
const FIXTURE = [
|
||||||
|
[[0, 0, 2], 0],
|
||||||
|
|
||||||
|
[[1, 0, 2], 1],
|
||||||
|
|
||||||
|
[[0, 1, 2], 2],
|
||||||
|
|
||||||
|
[[0, 2, 2], 4],
|
||||||
|
|
||||||
|
[[1, 4, 2], 9],
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('getIndexFromColAndRow', () => {
|
||||||
|
FIXTURE.forEach(([input, expected]) => {
|
||||||
|
test(`returns ${expected} for ${JSON.stringify(input)}`, () => {
|
||||||
|
expect(getIndexFromColAndRow(...input)).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
10
yarn.lock
10
yarn.lock
@ -18034,7 +18034,7 @@ memfs@^3.1.2, memfs@^3.2.2, memfs@^3.4.1, memfs@^3.4.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fs-monkey "^1.0.3"
|
fs-monkey "^1.0.3"
|
||||||
|
|
||||||
memoize-one@^5.0.0:
|
"memoize-one@>=3.1.1 <6", memoize-one@^5.0.0:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
|
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
|
||||||
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
|
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
|
||||||
@ -21671,6 +21671,14 @@ react-virtualized@^9.22.3:
|
|||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
react-lifecycles-compat "^3.0.4"
|
react-lifecycles-compat "^3.0.4"
|
||||||
|
|
||||||
|
react-window@1.8.7:
|
||||||
|
version "1.8.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.7.tgz#5e9fd0d23f48f432d7022cdb327219353a15f0d4"
|
||||||
|
integrity sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.0.0"
|
||||||
|
memoize-one ">=3.1.1 <6"
|
||||||
|
|
||||||
react@^17.0.2:
|
react@^17.0.2:
|
||||||
version "17.0.2"
|
version "17.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user