import React from "react"; import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types"; import { getCommonAttributeOfSelectedElements, isSomeElementSelected, } from "../scene"; import { ButtonSelect } from "../components/ButtonSelect"; import { isTextElement, redrawTextBoundingBox } from "../element"; import { ColorPicker } from "../components/ColorPicker"; import { AppState } from "../../src/types"; import { t } from "../i18n"; import { DEFAULT_FONT } from "../appState"; import { register } from "./register"; import { newElementWith } from "../element/mutateElement"; const changeProperty = ( elements: readonly ExcalidrawElement[], appState: AppState, callback: (element: ExcalidrawElement) => ExcalidrawElement, ) => { return elements.map(element => { if (appState.selectedElementIds[element.id]) { return callback(element); } return element; }); }; const getFormValue = function( elements: readonly ExcalidrawElement[], appState: AppState, getAttribute: (element: ExcalidrawElement) => T, defaultValue?: T, ): T | null { const editingElement = appState.editingElement; return ( (editingElement && getAttribute(editingElement)) ?? (isSomeElementSelected(elements, appState) ? getCommonAttributeOfSelectedElements(elements, appState, getAttribute) : defaultValue) ?? null ); }; export const actionChangeStrokeColor = register({ name: "changeStrokeColor", perform: (elements, appState, value) => { return { elements: changeProperty(elements, appState, el => newElementWith(el, { strokeColor: value, }), ), appState: { ...appState, currentItemStrokeColor: value }, commitToHistory: true, }; }, PanelComponent: ({ elements, appState, updateData }) => ( <> element.strokeColor, appState.currentItemStrokeColor, )} onChange={updateData} /> ), }); export const actionChangeBackgroundColor = register({ name: "changeBackgroundColor", perform: (elements, appState, value) => { return { elements: changeProperty(elements, appState, el => newElementWith(el, { backgroundColor: value, }), ), appState: { ...appState, currentItemBackgroundColor: value }, commitToHistory: true, }; }, PanelComponent: ({ elements, appState, updateData }) => ( <> element.backgroundColor, appState.currentItemBackgroundColor, )} onChange={updateData} /> ), }); export const actionChangeFillStyle = register({ name: "changeFillStyle", perform: (elements, appState, value) => { return { elements: changeProperty(elements, appState, el => newElementWith(el, { fillStyle: value, }), ), appState: { ...appState, currentItemFillStyle: value }, commitToHistory: true, }; }, PanelComponent: ({ elements, appState, updateData }) => (
{t("labels.fill")} element.fillStyle, appState.currentItemFillStyle, )} onChange={value => { updateData(value); }} />
), }); export const actionChangeStrokeWidth = register({ name: "changeStrokeWidth", perform: (elements, appState, value) => { return { elements: changeProperty(elements, appState, el => newElementWith(el, { strokeWidth: value, }), ), appState: { ...appState, currentItemStrokeWidth: value }, commitToHistory: true, }; }, PanelComponent: ({ elements, appState, updateData }) => (
{t("labels.strokeWidth")} element.strokeWidth, appState.currentItemStrokeWidth, )} onChange={value => updateData(value)} />
), }); export const actionChangeSloppiness = register({ name: "changeSloppiness", perform: (elements, appState, value) => { return { elements: changeProperty(elements, appState, el => newElementWith(el, { roughness: value, }), ), appState: { ...appState, currentItemRoughness: value }, commitToHistory: true, }; }, PanelComponent: ({ elements, appState, updateData }) => (
{t("labels.sloppiness")} element.roughness, appState.currentItemRoughness, )} onChange={value => updateData(value)} />
), }); export const actionChangeOpacity = register({ name: "changeOpacity", perform: (elements, appState, value) => { return { elements: changeProperty(elements, appState, el => newElementWith(el, { opacity: value, }), ), appState: { ...appState, currentItemOpacity: value }, commitToHistory: true, }; }, PanelComponent: ({ elements, appState, updateData }) => ( ), }); export const actionChangeFontSize = register({ name: "changeFontSize", perform: (elements, appState, value) => { return { elements: changeProperty(elements, appState, el => { if (isTextElement(el)) { const element: ExcalidrawTextElement = newElementWith(el, { font: `${value}px ${el.font.split("px ")[1]}`, }); redrawTextBoundingBox(element); return element; } return el; }), appState: { ...appState, currentItemFont: `${value}px ${ appState.currentItemFont.split("px ")[1] }`, }, commitToHistory: true, }; }, PanelComponent: ({ elements, appState, updateData }) => (
{t("labels.fontSize")} isTextElement(element) && +element.font.split("px ")[0], +(appState.currentItemFont || DEFAULT_FONT).split("px ")[0], )} onChange={value => updateData(value)} />
), }); export const actionChangeFontFamily = register({ name: "changeFontFamily", perform: (elements, appState, value) => { return { elements: changeProperty(elements, appState, el => { if (isTextElement(el)) { const element: ExcalidrawTextElement = newElementWith(el, { font: `${el.font.split("px ")[0]}px ${value}`, }); redrawTextBoundingBox(element); return element; } return el; }), appState: { ...appState, currentItemFont: `${ appState.currentItemFont.split("px ")[0] }px ${value}`, }, commitToHistory: true, }; }, PanelComponent: ({ elements, appState, updateData }) => (
{t("labels.fontFamily")} isTextElement(element) && element.font.split("px ")[1], (appState.currentItemFont || DEFAULT_FONT).split("px ")[1], )} onChange={value => updateData(value)} />
), });