diff --git a/demo/ts/components/theme-builder/accordion.tsx b/demo/ts/components/theme-builder/accordion.tsx index 02ac5a557..5578b4d5a 100644 --- a/demo/ts/components/theme-builder/accordion.tsx +++ b/demo/ts/components/theme-builder/accordion.tsx @@ -2,8 +2,20 @@ import React from "react"; import clsx from "clsx"; import { FaChevronDown } from "react-icons/fa"; -const Accordion = ({ id, title, children }) => { - const [isOpen, setIsOpen] = React.useState(false); +type AccordionProps = { + id: string; + title: string; + children: React.ReactNode; + defaultOpen?: boolean; +}; + +const Accordion = ({ + id, + title, + children, + defaultOpen = false, +}: AccordionProps) => { + const [isOpen, setIsOpen] = React.useState(defaultOpen); const toggleAccordion = () => { setIsOpen(!isOpen); diff --git a/demo/ts/components/theme-builder/color-picker.tsx b/demo/ts/components/theme-builder/color-picker.tsx index 2759c2af0..ba1609469 100644 --- a/demo/ts/components/theme-builder/color-picker.tsx +++ b/demo/ts/components/theme-builder/color-picker.tsx @@ -6,7 +6,7 @@ type ColorPickerProps = { label?: string; color: string; id: string; - onColorChange: (event: React.ChangeEvent) => void; + onColorChange: (color: string) => void; showColorName?: boolean; }; @@ -21,7 +21,7 @@ const ColorPicker = ({ const handleChange = (event: React.ChangeEvent) => { if (onColorChange) { - onColorChange(event); + onColorChange(event.target.value); } }; @@ -33,7 +33,7 @@ const ColorPicker = ({ )}
{!showColorName && (
@@ -82,7 +82,7 @@ const ColorPicker = ({ )} ; + newColor: string; index: number; colorScale: string; }; @@ -13,7 +13,7 @@ type ColorScaleOptionsProps = { palette?: VictoryThemeDefinition["palette"]; activeColorScale?: ColorScalePropType; onColorChange: (args: ColorChangeArgs) => void; - onColorScaleChange: (event: React.ChangeEvent) => void; + onColorScaleChange: (colorScale: string) => void; }; const colorScales = [ @@ -57,6 +57,7 @@ const ColorScaleOptions = ({ onChange={onColorScaleChange} options={colorScales} label="Color Scale" + className="mb-5" />
{palette?.[activeColorScale as string]?.map((color, i) => ( @@ -64,9 +65,9 @@ const ColorScaleOptions = ({ key={i} color={color} id={`color-${i}`} - onColorChange={(event) => + onColorChange={(newColor) => onColorChange({ - event, + newColor, index: i, colorScale: activeColorScale as string, }) diff --git a/demo/ts/components/theme-builder/config-mapper.tsx b/demo/ts/components/theme-builder/config-mapper.tsx index 1c069426d..41f12a845 100644 --- a/demo/ts/components/theme-builder/config-mapper.tsx +++ b/demo/ts/components/theme-builder/config-mapper.tsx @@ -4,39 +4,68 @@ import Accordion from "./accordion"; import Select from "./select"; import Slider from "./slider"; import ColorPicker from "./color-picker"; +import ColorScaleOptions from "./color-scale-options"; +import { getConfigValue } from "./utils"; const ConfigMapper = ({ + themeConfig, activeColorScale, + updateThemeConfig, handleColorScaleChange, - handleLabelConfigChange, }) => { + const handleColorChange = ({ newColor, index, colorScale }) => { + const updatedColors = themeConfig?.palette?.[colorScale]?.map((color, i) => + i === index ? newColor : color, + ); + updateThemeConfig(`palette.${colorScale}`, updatedColors); + }; + return ( <> - {optionsConfig.map((section) => ( - + {optionsConfig.map((section, index) => ( + {section.fields.map((field) => { if (field.type === "colorScale") { return ( - + updateThemeConfig(field.path, newValue) } /> ); @@ -47,10 +76,11 @@ const ConfigMapper = ({ id={field.label} key={field.label} label={field.label} - color={field.default} - onColorChange={(color) => - handleLabelConfigChange({ [field.label]: color }) + color={configValue as string} + onColorChange={(newColor) => + updateThemeConfig(field.path, newColor) } + showColorName /> ); } diff --git a/demo/ts/components/theme-builder/index.tsx b/demo/ts/components/theme-builder/index.tsx index 83a4f252c..b0847411e 100644 --- a/demo/ts/components/theme-builder/index.tsx +++ b/demo/ts/components/theme-builder/index.tsx @@ -1,7 +1,8 @@ import React from "react"; +import "./tailwind.css"; + import { ColorScalePropType, - LabelProps, VictoryTheme, VictoryThemeDefinition, } from "victory-core"; @@ -10,14 +11,11 @@ import { VictoryAxis } from "victory-axis"; import { VictoryStack } from "victory-stack"; import { VictoryBar } from "victory-bar"; import { VictoryArea } from "victory-area"; -import ColorScaleOptions, { ColorChangeArgs } from "./color-scale-options"; import Select from "./select"; import ConfigPreview from "./config-preview"; import Button from "./button"; - -import "./tailwind.css"; -import LabelOptions from "./label-options"; import ConfigMapper from "./config-mapper"; +import { setNestedConfigValue } from "./utils"; export type ThemeOption = { name: string; @@ -84,50 +82,24 @@ const ThemeBuilder = () => { const [showThemeConfigPreview, setShowThemeConfigPreview] = React.useState(false); - const handleThemeSelect = (event: React.ChangeEvent) => { - const themeName = event.target.value; + const handleThemeSelect = (themeName: string) => { const theme = themes.find((t) => t.name === themeName); setBaseTheme(theme); setCustomThemeConfig({ ...theme?.config }); }; - const handleLabelConfigChange = (newLabelConfig: Partial) => { - if (customThemeConfig) { - const updatedConfig = { - ...customThemeConfig, - axis: { - ...customThemeConfig.axis, - style: { - ...customThemeConfig.axis?.style, - axisLabel: { - ...customThemeConfig.axis?.style?.axisLabel, - ...newLabelConfig, - }, - }, - }, - }; - setCustomThemeConfig(updatedConfig as VictoryThemeDefinition); - } - }; - - const handleColorChange = ({ event, index, colorScale }: ColorChangeArgs) => { - const newColor = event.target.value; - const updatedConfig = { - ...customThemeConfig, - palette: { - ...customThemeConfig?.palette, - [colorScale]: customThemeConfig?.palette?.[colorScale]?.map( - (color, i) => (i === index ? newColor : color), - ), - }, - }; + const updateCustomThemeConfig = (path: string, newValue: unknown) => { + if (!customThemeConfig) return; + const updatedConfig = setNestedConfigValue( + customThemeConfig, + path, + newValue, + ); setCustomThemeConfig(updatedConfig); }; - const handleColorScaleChange = ( - event: React.ChangeEvent, - ) => { - setActiveColorScale(event.target.value as ColorScalePropType); + const handleColorScaleChange = (colorScale: string) => { + setActiveColorScale(colorScale as ColorScalePropType); }; const handleThemeConfigPreviewOpen = () => { @@ -155,29 +127,12 @@ const ThemeBuilder = () => { /> {customThemeConfig && (
-

Customization Options

+

Customization Options

-
- )} - {false && ( -
-

Customization Options

-

Color Options

- -
)} diff --git a/demo/ts/components/theme-builder/label-options.tsx b/demo/ts/components/theme-builder/label-options.tsx deleted file mode 100644 index 6370f999a..000000000 --- a/demo/ts/components/theme-builder/label-options.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import { LabelProps } from "victory-core"; -import Slider from "./slider"; -import ColorPicker from "./color-picker"; - -type LabelOptionsProps = { - labelConfig?: LabelProps; - onLabelConfigChange: (labelConfig: LabelProps) => void; -}; - -const LabelOptions = ({ - labelConfig, - onLabelConfigChange, -}: LabelOptionsProps) => { - if (!labelConfig) return null; - return ( -
-

Axis Label Options

- - onLabelConfigChange({ fontSize: parseInt(event.target.value) }) - } - /> - - onLabelConfigChange({ padding: parseInt(event.target.value) }) - } - /> -
- - onLabelConfigChange({ fill: event.target.value }) - } - /> -
-
- ); -}; -export default LabelOptions; diff --git a/demo/ts/components/theme-builder/options-config.ts b/demo/ts/components/theme-builder/options-config.ts index dad4d267b..e5c285e91 100644 --- a/demo/ts/components/theme-builder/options-config.ts +++ b/demo/ts/components/theme-builder/options-config.ts @@ -6,8 +6,6 @@ const optionsConfig = [ { type: "colorScale", label: "Color Scale", - options: ["Qualitative", "Sequential", "Diverging"], - default: "Qualitative", }, ], }, @@ -20,21 +18,21 @@ const optionsConfig = [ label: "Font Size", min: 10, max: 24, - default: 12, unit: "px", + path: "axis.style.axisLabel.fontSize", }, { type: "slider", label: "Padding", min: 0, max: 50, - default: 35, unit: "px", + path: "axis.style.axisLabel.padding", }, { type: "colorPicker", label: "Fill", - default: "#292929", + path: "axis.style.axisLabel.fill", }, ], }, diff --git a/demo/ts/components/theme-builder/select.tsx b/demo/ts/components/theme-builder/select.tsx index 675fa5a6b..0bb7b9d17 100644 --- a/demo/ts/components/theme-builder/select.tsx +++ b/demo/ts/components/theme-builder/select.tsx @@ -1,4 +1,5 @@ import React from "react"; +import clsx from "clsx"; export type SelectOption = { label: string; @@ -10,25 +11,38 @@ type SelectProps = { label?: string; options: SelectOption[]; value: string; - onChange: (event: React.ChangeEvent) => void; + onChange: (value: string) => void; + className?: string; }; -const Select = ({ id, label, options, value, onChange }: SelectProps) => { +const Select = ({ + id, + label, + options, + value, + onChange, + className, +}: SelectProps) => { + const handleChange = (event: React.ChangeEvent) => { + if (onChange) { + onChange(event.target.value); + } + }; return ( -
+
{label && ( -