mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 08:19:07 +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-router": "5.2.0",
|
||||
"react-router-dom": "5.2.0",
|
||||
"react-virtualized": "^9.22.3",
|
||||
"react-window": "1.8.7",
|
||||
"redux": "^4.0.1",
|
||||
"redux-saga": "^0.16.0",
|
||||
"reselect": "^4.0.0",
|
||||
|
@ -28,7 +28,7 @@ const aliasExactMatch = [
|
||||
'react-redux',
|
||||
'react-router',
|
||||
'react-router-dom',
|
||||
'react-virtualized',
|
||||
'react-window',
|
||||
'react-select',
|
||||
'redux',
|
||||
'reselect',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { AutoSizer, Collection } from 'react-virtualized';
|
||||
import { FixedSizeGrid } from 'react-window';
|
||||
import { Searchbar } from '@strapi/design-system/Searchbar';
|
||||
import { IconButton } from '@strapi/design-system/IconButton';
|
||||
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 { Stack } from '@strapi/design-system/Stack';
|
||||
import { Typography } from '@strapi/design-system/Typography';
|
||||
|
||||
import { getIndexFromColAndRow } from './utils/getIndexFromColAndRow';
|
||||
import useDataManager from '../../hooks/useDataManager';
|
||||
import getTrad from '../../utils/getTrad';
|
||||
import Cell from './Cell';
|
||||
|
||||
const CELL_WIDTH = 44;
|
||||
const CELL_WIDTH = 42;
|
||||
const COLUMN_COUNT = 18;
|
||||
|
||||
const ComponentIconPicker = ({ error, intlLabel, name, onChange, value }) => {
|
||||
const { allIcons } = useDataManager();
|
||||
@ -37,26 +40,32 @@ const ComponentIconPicker = ({ error, intlLabel, name, onChange, 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 }) => {
|
||||
const columnCount = 16;
|
||||
const columnPosition = index % (columnCount || 1);
|
||||
|
||||
const height = CELL_WIDTH;
|
||||
const width = CELL_WIDTH;
|
||||
const x = columnPosition * (width + 1);
|
||||
const y = parseInt(index / 16, 10) * CELL_WIDTH;
|
||||
|
||||
return {
|
||||
height,
|
||||
width,
|
||||
x,
|
||||
y,
|
||||
};
|
||||
return (
|
||||
<div style={style} key={`col-${columnIndex}`}>
|
||||
{icon && (
|
||||
<Cell
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
onClick={() => {
|
||||
onChange({ target: { name, value: icon } });
|
||||
}}
|
||||
isSelected={icon === value}
|
||||
as="button"
|
||||
type="button"
|
||||
>
|
||||
<FontAwesomeIcon icon={icon} />
|
||||
</Cell>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const cellCount = icons.length;
|
||||
const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
|
||||
|
||||
return (
|
||||
<Box>
|
||||
@ -105,44 +114,17 @@ const ComponentIconPicker = ({ error, intlLabel, name, onChange, value }) => {
|
||||
)}
|
||||
</Flex>
|
||||
<Stack spacing={1}>
|
||||
<Box background="neutral100" borderColor={error ? 'danger600' : ''} hasRadius>
|
||||
<Box>
|
||||
<AutoSizer disableHeight>
|
||||
{({ width }) => {
|
||||
return (
|
||||
<Collection
|
||||
cellCount={cellCount}
|
||||
cellRenderer={({ index, key, style }) => {
|
||||
const icon = icons[index];
|
||||
const isSelected = icon === value;
|
||||
const handleClick = () => {
|
||||
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 padding={1} background="neutral100" borderColor={error ? 'danger600' : ''} hasRadius>
|
||||
<FixedSizeGrid
|
||||
columnCount={COLUMN_COUNT}
|
||||
columnWidth={CELL_WIDTH}
|
||||
height={132}
|
||||
rowHeight={CELL_WIDTH}
|
||||
rowCount={Math.ceil(icons.length / COLUMN_COUNT)}
|
||||
width={CELL_WIDTH * COLUMN_COUNT}
|
||||
>
|
||||
{IconRenderer}
|
||||
</FixedSizeGrid>
|
||||
</Box>
|
||||
{error && (
|
||||
<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:
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
|
||||
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
|
||||
@ -21671,6 +21671,14 @@ react-virtualized@^9.22.3:
|
||||
prop-types "^15.7.2"
|
||||
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:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
||||
|
Loading…
x
Reference in New Issue
Block a user