@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
185 lines (184 loc) • 8.24 kB
JavaScript
import * as React from 'react';
import FormLayout, { FormRow } from '../../components/FormLayout';
import { useAdaptable } from '../AdaptableContext';
import AdaptableInput from '../Components/AdaptableInput';
import throttle from 'lodash/throttle';
import SimpleButton from '../../components/SimpleButton';
import { Box, Flex, Text } from 'rebass';
import Panel from '../../components/Panel';
import { Field } from './ThemeField';
import { VariantSelector } from './VariantSelector';
import { getAccessLevelForObject } from '../../Utilities/Helpers/AdaptableHelper';
const fields = [
{
name: 'Primary Color',
type: 'color',
variable: '--ab-color-primary',
},
{
name: 'Primary Dark Color',
type: 'color',
variable: '--ab-color-primarydark',
},
{
name: 'Primary Light Color',
type: 'color',
variable: '--ab-color-primarylight',
},
{
name: 'Text on Primary Color',
type: 'color',
variable: '--ab-color-text-on-primary',
},
{
name: 'Text on Primary Dark Color',
type: 'color',
variable: '--ab-color-text-on-primarydark',
},
{
name: 'Secondary Color',
type: 'color',
variable: '--ab-color-secondary',
},
{
name: 'Secondary Dark Color',
type: 'color',
variable: '--ab-color-secondarydark',
},
{
name: 'Secondary Light Color',
type: 'color',
variable: '--ab-color-secondarylight',
},
{
name: 'Text on Secondary Color',
type: 'color',
variable: '--ab-color-text-on-secondary',
},
{
name: 'Text on Secondary Light Color',
type: 'color',
variable: '--ab-color-text-on-secondarylight',
},
{
name: 'Default background',
type: 'color',
variable: '--ab-color-defaultbackground',
},
{
name: 'Text Color on Default Background',
type: 'color',
variable: '--ab-color-text-on-defaultbackground',
},
];
export const ThemeEditor = (props) => {
const adaptable = useAdaptable();
const allThemes = adaptable.api.themeApi.getUserThemes();
const [currentThemeObject, setCurrentThemeObject] = React.useState(() => {
return adaptable.api.themeApi.getCurrentThemeObject();
});
const currentThemeAccessLevel = getAccessLevelForObject(currentThemeObject, props.accessLevel);
const currentThemeIsReadOnly = currentThemeAccessLevel !== 'Full';
// THEME variables
const themeVariables = currentThemeObject?.CSSVariables;
const valuesFromTheme = fields.reduce((acc, field) => {
if (themeVariables?.[field.variable]) {
acc[field.variable] = themeVariables?.[field.variable];
}
return acc;
}, {});
React.useEffect(() => {
setCurrentThemeObject(adaptable.api.themeApi.getCurrentThemeObject());
}, [props.theme]);
// This is needed when clearing variables, so the new value is pickedup up from the document
React.useEffect(() => {
const updateTheme = () => {
const theme = adaptable.api.themeApi.getCurrentThemeObject();
setCurrentThemeObject({ ...theme });
};
const themeChangedUnsubscribe = adaptable.api.eventApi.on('ThemeChanged', updateTheme);
return () => {
themeChangedUnsubscribe();
};
}, []);
const handleNameDescriptionChangeThrottled = React.useMemo(() => {
return throttle((key, value) => {
const theme = adaptable.api.themeApi.getCurrentThemeObject();
const newTheme = {
...theme,
[key]: value,
};
adaptable.api.themeApi.editTheme(newTheme);
}, 600);
}, []);
const handleDescriptionChange = React.useCallback((key, value) => {
setCurrentThemeObject((prev) => ({ ...prev, [key]: value }));
handleNameDescriptionChangeThrottled(key, value);
}, []);
const handleDeleteTheme = React.useCallback(() => {
adaptable.api.themeApi.loadLightTheme();
adaptable.api.themeApi.deleteUserTheme(currentThemeObject);
}, []);
const handleSaveName = () => {
const name = currentThemeObject.Name;
setCurrentThemeObject((prev) => ({ ...prev, Name: name }));
handleNameDescriptionChangeThrottled('Name', name);
};
const handleVariantChange = (variant) => {
const newTheme = { ...currentThemeObject };
if (!variant) {
delete newTheme.Variant;
}
else {
newTheme.Variant = variant;
}
setCurrentThemeObject(newTheme);
adaptable.api.themeApi.editTheme(newTheme);
};
const nameHasChanged = currentThemeObject.Name !== props.theme;
const nameIsNotUnique = allThemes.some((theme) => theme.Uuid !== currentThemeObject.Uuid && currentThemeObject.Name === theme.Name);
const saveNameDisabled = !nameHasChanged || nameIsNotUnique || currentThemeObject.Name === '';
return (React.createElement(Panel, { header: React.createElement(Flex, { alignItems: "center", width: "100%" },
React.createElement(Box, { flex: 1 }, " Edit Custom Theme"),
React.createElement(SimpleButton, { "data-name": "delete", accessLevel: currentThemeAccessLevel, icon: "delete", onClick: handleDeleteTheme, variant: "text" })) },
React.createElement(FormLayout, null,
React.createElement(FormRow, { label: "Theme Name" },
React.createElement(AdaptableInput, { disabled: currentThemeIsReadOnly, mr: 2, onChange: (event) => setCurrentThemeObject({
...currentThemeObject,
Name: event.target.value.replace(/ /g, '-'),
}), value: currentThemeObject.Name ?? '' }),
React.createElement(SimpleButton, { onClick: handleSaveName, disabled: saveNameDisabled || currentThemeIsReadOnly, icon: "save", hidden: currentThemeIsReadOnly }),
React.createElement(Text, { fontSize: 2, marginTop: 1 }, "The name cannot contain spaces."),
nameIsNotUnique && (React.createElement(Text, { fontSize: 2, color: "var(--ab-color-error)" }, "Name must be unique."))),
React.createElement(FormRow, { label: "Description" },
React.createElement(AdaptableInput, { disabled: currentThemeIsReadOnly, onChange: (event) => handleDescriptionChange('Description', event.target.value), value: currentThemeObject?.Description ?? '' })),
React.createElement(FormRow, { label: "Variant" },
React.createElement(VariantSelector, { onChange: handleVariantChange, theme: currentThemeObject, disabled: currentThemeIsReadOnly })),
fields.map((field) => {
return (React.createElement(Field, { disabled: currentThemeIsReadOnly, key: field.name, type: field.type, name: field.name, value: valuesFromTheme[field.variable], variable: field.variable, onChange: (val) => {
// needs a fresh copy
const currentThemeObject = adaptable.api.themeApi.getCurrentThemeObject();
let newTheme = null;
if (val === false) {
newTheme = {
...currentThemeObject,
CSSVariables: {
...currentThemeObject?.CSSVariables,
},
};
delete newTheme.CSSVariables[field.variable];
}
else {
newTheme = {
...currentThemeObject,
CSSVariables: {
...currentThemeObject?.CSSVariables,
[field.variable]: val,
},
};
}
setCurrentThemeObject(newTheme);
adaptable.api.themeApi.editTheme(newTheme);
} }));
}))));
};