0

fix: Prevent color selector from closing on choosing a color (#2783)

* improv: wrap ColorPicker in memo to prevent unnecessary rerenders

* improv appearance: wrap updateColor in useCallback to prevent unnecessary rerenders due to changing reference to the func

* improv: define ColorCollection Component as top level, and modify it to prevent unnecessary rerenders
This commit is contained in:
Pranav Joglekar 2023-03-09 01:43:57 +05:30 committed by GitHub
parent 108eda0a6a
commit e80db09ab1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,4 +1,4 @@
import React, { FC, useContext, useEffect, useState } from 'react';
import React, { FC, useContext, useCallback, useEffect, useState } from 'react';
import { Button, Col, Collapse, Row, Slider, Space } from 'antd';
import Paragraph from 'antd/lib/typography/Paragraph';
@ -24,6 +24,11 @@ interface AppearanceVariable {
description: string;
}
type ColorCollectionProps = {
variables: { name; description; value }[];
updateColor: (variable: string, color: string, description: string) => void;
};
const chatColorVariables = [
{ name: 'theme-color-users-0', description: '' },
{ name: 'theme-color-users-1', description: '' },
@ -70,18 +75,18 @@ const allAvailableValues = [...componentColorVariables, ...chatColorVariables, .
);
// eslint-disable-next-line react/function-component-definition
function ColorPicker({
value,
name,
description,
onChange,
}: {
value: string;
name: string;
description: string;
onChange: (name: string, value: string, description: string) => void;
}) {
return (
const ColorPicker = React.memo(
({
value,
name,
description,
onChange,
}: {
value: string;
name: string;
description: string;
onChange: (name: string, value: string, description: string) => void;
}) => (
<Col span={3} key={name}>
<input
type="color"
@ -94,8 +99,26 @@ function ColorPicker({
/>
<div style={{ padding: '2px' }}>{description}</div>
</Col>
);
}
),
);
const ColorCollection: FC<ColorCollectionProps> = ({ variables, updateColor }) => {
const cc = variables.map(colorVar => {
const { name, description, value } = colorVar;
return (
<ColorPicker
key={name}
value={value}
name={name}
description={description}
onChange={updateColor}
/>
);
});
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{cc}</>;
};
// eslint-disable-next-line react/function-component-definition
export default function Appearance() {
@ -144,12 +167,12 @@ export default function Appearance() {
setCustomValues(c);
}, [appearanceVariables]);
const updateColor = (variable: string, color: string, description: string) => {
setCustomValues({
...customValues,
const updateColor = useCallback((variable: string, color: string, description: string) => {
setCustomValues(oldCustomValues => ({
...oldCustomValues,
[variable]: { value: color, description },
});
};
}));
}, []);
const reset = async () => {
await postConfigUpdateToAPI({
@ -193,34 +216,18 @@ export default function Appearance() {
updateColor(variableName, `${value.toString()}px`, '');
};
type ColorCollectionProps = {
variables: { name; description }[];
};
// eslint-disable-next-line react/no-unstable-nested-components
const ColorCollection: FC<ColorCollectionProps> = ({ variables }) => {
const cc = variables.map(colorVar => {
const source = customValues?.[colorVar.name] ? customValues : defaultValues;
const { name, description } = colorVar;
const { value } = source[name];
return (
<ColorPicker
key={name}
value={value}
name={name}
description={description}
onChange={updateColor}
/>
);
});
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{cc}</>;
};
if (!defaultValues) {
return <div>Loading...</div>;
}
const transformToColorMap = variables =>
variables.map(colorVar => {
const source = customValues?.[colorVar.name] ? customValues : defaultValues;
const { name, description } = colorVar;
const { value } = source[name];
return { name, description, value };
});
return (
<Space direction="vertical">
<Title>Customize Appearance</Title>
@ -232,15 +239,20 @@ export default function Appearance() {
Certain sections of the interface can be customized by selecting new colors for them.
</p>
<Row gutter={[16, 16]}>
<ColorCollection variables={componentColorVariables} />
<ColorCollection
variables={transformToColorMap(componentColorVariables)}
updateColor={updateColor}
/>
</Row>
</Panel>
<Panel header={<Title level={3}>Chat User Colors</Title>} key="2">
<Row gutter={[16, 16]}>
<ColorCollection variables={chatColorVariables} />
<ColorCollection
variables={transformToColorMap(chatColorVariables)}
updateColor={updateColor}
/>
</Row>
</Panel>
<Panel header={<Title level={3}>Other Settings</Title>} key="4">
How rounded should corners be?
<Row gutter={[16, 16]}>