UNPKG

tldraw

Version:

A tiny little drawing editor.

385 lines (384 loc) • 13.9 kB
import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { ArrowShapeArrowheadEndStyle, ArrowShapeArrowheadStartStyle, ArrowShapeKindStyle, DefaultColorStyle, DefaultDashStyle, DefaultFillStyle, DefaultFontStyle, DefaultHorizontalAlignStyle, DefaultSizeStyle, DefaultTextAlignStyle, DefaultVerticalAlignStyle, GeoShapeGeoStyle, LineShapeSplineStyle, getDefaultColorTheme, minBy, useEditor, useIsDarkMode, useValue } from "@tldraw/editor"; import React, { useCallback } from "react"; import { STYLES } from "../../../styles.mjs"; import { kickoutOccludedShapes } from "../../../tools/SelectTool/selectHelpers.mjs"; import { useUiEvents } from "../../context/events.mjs"; import { useTranslation } from "../../hooks/useTranslation/useTranslation.mjs"; import { TldrawUiButtonIcon } from "../primitives/Button/TldrawUiButtonIcon.mjs"; import { TldrawUiButtonPicker } from "../primitives/TldrawUiButtonPicker.mjs"; import { TldrawUiSlider } from "../primitives/TldrawUiSlider.mjs"; import { TldrawUiToolbar, TldrawUiToolbarButton } from "../primitives/TldrawUiToolbar.mjs"; import { DoubleDropdownPicker } from "./DoubleDropdownPicker.mjs"; import { DropdownPicker } from "./DropdownPicker.mjs"; function DefaultStylePanelContent({ styles }) { const isDarkMode = useIsDarkMode(); if (!styles) return null; const geo = styles.get(GeoShapeGeoStyle); const arrowheadEnd = styles.get(ArrowShapeArrowheadEndStyle); const arrowheadStart = styles.get(ArrowShapeArrowheadStartStyle); const arrowKind = styles.get(ArrowShapeKindStyle); const spline = styles.get(LineShapeSplineStyle); const font = styles.get(DefaultFontStyle); const hideGeo = geo === void 0; const hideArrowHeads = arrowheadEnd === void 0 && arrowheadStart === void 0; const hideSpline = spline === void 0; const hideArrowKind = arrowKind === void 0; const hideText = font === void 0; const theme = getDefaultColorTheme({ isDarkMode }); return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(CommonStylePickerSet, { theme, styles }), !hideText && /* @__PURE__ */ jsx(TextStylePickerSet, { theme, styles }), !(hideGeo && hideArrowHeads && hideSpline && hideArrowKind) && /* @__PURE__ */ jsxs("div", { className: "tlui-style-panel__section", children: [ /* @__PURE__ */ jsx(GeoStylePickerSet, { styles }), /* @__PURE__ */ jsx(ArrowStylePickerSet, { styles }), /* @__PURE__ */ jsx(ArrowheadStylePickerSet, { styles }), /* @__PURE__ */ jsx(SplineStylePickerSet, { styles }) ] }) ] }); } function useStyleChangeCallback() { const editor = useEditor(); const trackEvent = useUiEvents(); return React.useMemo( () => (function handleStyleChange(style, value) { editor.run(() => { if (editor.isIn("select")) { editor.setStyleForSelectedShapes(style, value); } editor.setStyleForNextShapes(style, value); editor.updateInstanceState({ isChangingStyle: true }); }); trackEvent("set-style", { source: "style-panel", id: style.id, value }); }), [editor, trackEvent] ); } function CommonStylePickerSet({ styles, theme }) { const msg = useTranslation(); const editor = useEditor(); const onHistoryMark = useCallback((id) => editor.markHistoryStoppingPoint(id), [editor]); const handleValueChange = useStyleChangeCallback(); const color = styles.get(DefaultColorStyle); const fill = styles.get(DefaultFillStyle); const dash = styles.get(DefaultDashStyle); const size = styles.get(DefaultSizeStyle); const showPickers = fill !== void 0 || dash !== void 0 || size !== void 0; return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs("div", { className: "tlui-style-panel__section__common", "data-testid": "style.panel", children: [ color === void 0 ? null : /* @__PURE__ */ jsx(TldrawUiToolbar, { label: msg("style-panel.color"), children: /* @__PURE__ */ jsx( TldrawUiButtonPicker, { title: msg("style-panel.color"), uiType: "color", style: DefaultColorStyle, items: STYLES.color, value: color, onValueChange: handleValueChange, theme, onHistoryMark } ) }), /* @__PURE__ */ jsx(OpacitySlider, {}) ] }), showPickers && /* @__PURE__ */ jsxs("div", { className: "tlui-style-panel__section", children: [ fill === void 0 ? null : /* @__PURE__ */ jsx(TldrawUiToolbar, { label: msg("style-panel.fill"), children: /* @__PURE__ */ jsx( TldrawUiButtonPicker, { title: msg("style-panel.fill"), uiType: "fill", style: DefaultFillStyle, items: STYLES.fill, value: fill, onValueChange: handleValueChange, theme, onHistoryMark } ) }), dash === void 0 ? null : /* @__PURE__ */ jsx(TldrawUiToolbar, { label: msg("style-panel.dash"), children: /* @__PURE__ */ jsx( TldrawUiButtonPicker, { title: msg("style-panel.dash"), uiType: "dash", style: DefaultDashStyle, items: STYLES.dash, value: dash, onValueChange: handleValueChange, theme, onHistoryMark } ) }), size === void 0 ? null : /* @__PURE__ */ jsx(TldrawUiToolbar, { label: msg("style-panel.size"), children: /* @__PURE__ */ jsx( TldrawUiButtonPicker, { title: msg("style-panel.size"), uiType: "size", style: DefaultSizeStyle, items: STYLES.size, value: size, onValueChange: (style, value) => { handleValueChange(style, value); const selectedShapeIds = editor.getSelectedShapeIds(); if (selectedShapeIds.length > 0) { kickoutOccludedShapes(editor, selectedShapeIds); } }, theme, onHistoryMark } ) }) ] }) ] }); } function TextStylePickerSet({ theme, styles }) { const msg = useTranslation(); const handleValueChange = useStyleChangeCallback(); const editor = useEditor(); const onHistoryMark = useCallback((id) => editor.markHistoryStoppingPoint(id), [editor]); const font = styles.get(DefaultFontStyle); const textAlign = styles.get(DefaultTextAlignStyle); const labelAlign = styles.get(DefaultHorizontalAlignStyle); const verticalLabelAlign = styles.get(DefaultVerticalAlignStyle); if (font === void 0 && labelAlign === void 0) { return null; } return /* @__PURE__ */ jsxs("div", { className: "tlui-style-panel__section", children: [ font === void 0 ? null : /* @__PURE__ */ jsx(TldrawUiToolbar, { label: msg("style-panel.font"), children: /* @__PURE__ */ jsx( TldrawUiButtonPicker, { title: msg("style-panel.font"), uiType: "font", style: DefaultFontStyle, items: STYLES.font, value: font, onValueChange: handleValueChange, theme, onHistoryMark } ) }), textAlign === void 0 ? null : /* @__PURE__ */ jsxs(TldrawUiToolbar, { label: msg("style-panel.align"), className: "tlui-style-panel__row", children: [ /* @__PURE__ */ jsx( TldrawUiButtonPicker, { title: msg("style-panel.align"), uiType: "align", style: DefaultTextAlignStyle, items: STYLES.textAlign, value: textAlign, onValueChange: handleValueChange, theme, onHistoryMark } ), /* @__PURE__ */ jsx("div", { className: "tlui-style-panel__row__extra-button", children: /* @__PURE__ */ jsx( TldrawUiToolbarButton, { type: "icon", title: msg("style-panel.vertical-align"), "data-testid": "vertical-align", disabled: true, children: /* @__PURE__ */ jsx(TldrawUiButtonIcon, { icon: "vertical-align-middle" }) } ) }) ] }), labelAlign === void 0 ? null : /* @__PURE__ */ jsxs(TldrawUiToolbar, { label: msg("style-panel.label-align"), className: "tlui-style-panel__row", children: [ /* @__PURE__ */ jsx( TldrawUiButtonPicker, { title: msg("style-panel.label-align"), uiType: "align", style: DefaultHorizontalAlignStyle, items: STYLES.horizontalAlign, value: labelAlign, onValueChange: handleValueChange, theme, onHistoryMark } ), /* @__PURE__ */ jsx("div", { className: "tlui-style-panel__row__extra-button", children: verticalLabelAlign === void 0 ? /* @__PURE__ */ jsx( TldrawUiToolbarButton, { type: "icon", title: msg("style-panel.vertical-align"), "data-testid": "vertical-align", disabled: true, children: /* @__PURE__ */ jsx(TldrawUiButtonIcon, { icon: "vertical-align-middle" }) } ) : /* @__PURE__ */ jsx( DropdownPicker, { type: "icon", id: "geo-vertical-alignment", uiType: "verticalAlign", stylePanelType: "vertical-align", style: DefaultVerticalAlignStyle, items: STYLES.verticalAlign, value: verticalLabelAlign, onValueChange: handleValueChange } ) }) ] }) ] }); } function GeoStylePickerSet({ styles }) { const msg = useTranslation(); const handleValueChange = useStyleChangeCallback(); const geo = styles.get(GeoShapeGeoStyle); if (geo === void 0) { return null; } return /* @__PURE__ */ jsx(TldrawUiToolbar, { label: msg("style-panel.geo"), children: /* @__PURE__ */ jsx( DropdownPicker, { id: "geo", type: "menu", label: "style-panel.geo", uiType: "geo", stylePanelType: "geo", style: GeoShapeGeoStyle, items: STYLES.geo, value: geo, onValueChange: handleValueChange } ) }); } function SplineStylePickerSet({ styles }) { const msg = useTranslation(); const handleValueChange = useStyleChangeCallback(); const spline = styles.get(LineShapeSplineStyle); if (spline === void 0) { return null; } return /* @__PURE__ */ jsx(TldrawUiToolbar, { label: msg("style-panel.spline"), children: /* @__PURE__ */ jsx( DropdownPicker, { id: "spline", type: "menu", label: "style-panel.spline", uiType: "spline", stylePanelType: "spline", style: LineShapeSplineStyle, items: STYLES.spline, value: spline, onValueChange: handleValueChange } ) }); } function ArrowStylePickerSet({ styles }) { const msg = useTranslation(); const handleValueChange = useStyleChangeCallback(); const arrowKind = styles.get(ArrowShapeKindStyle); if (arrowKind === void 0) { return null; } return /* @__PURE__ */ jsx(TldrawUiToolbar, { label: msg("style-panel.arrow-kind"), children: /* @__PURE__ */ jsx( DropdownPicker, { id: "arrow-kind", type: "menu", label: "style-panel.arrow-kind", uiType: "arrow-kind", stylePanelType: "arrow-kind", style: ArrowShapeKindStyle, items: STYLES.arrowKind, value: arrowKind, onValueChange: handleValueChange } ) }); } function ArrowheadStylePickerSet({ styles }) { const handleValueChange = useStyleChangeCallback(); const arrowheadEnd = styles.get(ArrowShapeArrowheadEndStyle); const arrowheadStart = styles.get(ArrowShapeArrowheadStartStyle); if (!arrowheadEnd || !arrowheadStart) { return null; } return /* @__PURE__ */ jsx( DoubleDropdownPicker, { label: "style-panel.arrowheads", uiTypeA: "arrowheadStart", styleA: ArrowShapeArrowheadStartStyle, itemsA: STYLES.arrowheadStart, valueA: arrowheadStart, uiTypeB: "arrowheadEnd", styleB: ArrowShapeArrowheadEndStyle, itemsB: STYLES.arrowheadEnd, valueB: arrowheadEnd, onValueChange: handleValueChange, labelA: "style-panel.arrowhead-start", labelB: "style-panel.arrowhead-end" } ); } const tldrawSupportedOpacities = [0.1, 0.25, 0.5, 0.75, 1]; function OpacitySlider() { const editor = useEditor(); const onHistoryMark = useCallback((id) => editor.markHistoryStoppingPoint(id), [editor]); const opacity = useValue("opacity", () => editor.getSharedOpacity(), [editor]); const trackEvent = useUiEvents(); const msg = useTranslation(); const handleOpacityValueChange = React.useCallback( (value) => { const item = tldrawSupportedOpacities[value]; editor.run(() => { if (editor.isIn("select")) { editor.setOpacityForSelectedShapes(item); } editor.setOpacityForNextShapes(item); editor.updateInstanceState({ isChangingStyle: true }); }); trackEvent("set-style", { source: "style-panel", id: "opacity", value }); }, [editor, trackEvent] ); if (opacity === void 0) return null; const opacityIndex = opacity.type === "mixed" ? -1 : tldrawSupportedOpacities.indexOf( minBy( tldrawSupportedOpacities, (supportedOpacity) => Math.abs(supportedOpacity - opacity.value) ) ); return /* @__PURE__ */ jsx( TldrawUiSlider, { "data-testid": "style.opacity", value: opacityIndex >= 0 ? opacityIndex : tldrawSupportedOpacities.length - 1, label: opacity.type === "mixed" ? "style-panel.mixed" : `opacity-style.${opacity.value}`, onValueChange: handleOpacityValueChange, steps: tldrawSupportedOpacities.length - 1, title: msg("style-panel.opacity"), onHistoryMark } ); } export { ArrowStylePickerSet, ArrowheadStylePickerSet, CommonStylePickerSet, DefaultStylePanelContent, GeoStylePickerSet, OpacitySlider, SplineStylePickerSet, TextStylePickerSet }; //# sourceMappingURL=DefaultStylePanelContent.mjs.map