UNPKG

@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
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); } })); })))); };