import { Editor, TLNullableShapeProps, TLStyleItem, useEditor } from '@tldraw/editor' import React, { useCallback } from 'react' import { useValue } from 'signia-react' import { useTranslation } from '../../hooks/useTranslation/useTranslation' import { Button } from '../primitives/Button' import { ButtonPicker } from '../primitives/ButtonPicker' import { Slider } from '../primitives/Slider' import { DoubleDropdownPicker } from './DoubleDropdownPicker' import { DropdownPicker } from './DropdownPicker' interface StylePanelProps { isMobile?: boolean } /** @internal */ export const StylePanel = function StylePanel({ isMobile }: StylePanelProps) { const editor = useEditor() const props = useValue('props', () => editor.props, [editor]) const handlePointerOut = useCallback(() => { if (!isMobile) { editor.isChangingStyle = false } }, [editor, isMobile]) if (!props) return null const { geo, arrowheadEnd, arrowheadStart, spline, font } = props const hideGeo = geo === undefined const hideArrowHeads = arrowheadEnd === undefined && arrowheadStart === undefined const hideSpline = spline === undefined const hideText = font === undefined return (
{!hideText && } {!(hideGeo && hideArrowHeads && hideSpline) && (
)}
) } const { styles } = Editor function useStyleChangeCallback() { const editor = useEditor() return React.useCallback( (item: TLStyleItem, squashing: boolean) => { editor.batch(() => { editor.setProp(item.type, item.id, false, squashing) editor.isChangingStyle = true }) }, [editor] ) } function CommonStylePickerSet({ props }: { props: TLNullableShapeProps }) { const editor = useEditor() const msg = useTranslation() const handleValueChange = useStyleChangeCallback() const handleOpacityValueChange = React.useCallback( (value: number, ephemeral: boolean) => { const item = styles.opacity[value] editor.setProp(item.type, item.id, ephemeral) editor.isChangingStyle = true }, [editor] ) const { color, fill, dash, size, opacity } = props if ( color === undefined && fill === undefined && dash === undefined && size === undefined && opacity === undefined ) { return null } const showPickers = fill || dash || size const opacityIndex = styles.opacity.findIndex((s) => s.id === opacity) return ( <>
{color === undefined ? null : ( )} {opacity === undefined ? null : ( = 0 ? opacityIndex : styles.opacity.length - 1} label={opacity ? `opacity-style.${opacity}` : 'style-panel.mixed'} onValueChange={handleOpacityValueChange} steps={styles.opacity.length - 1} title={msg('style-panel.opacity')} /> )}
{showPickers && (
{fill === undefined ? null : ( )} {dash === undefined ? null : ( )} {size === undefined ? null : ( )}
)} ) } function TextStylePickerSet({ props }: { props: TLNullableShapeProps }) { const msg = useTranslation() const handleValueChange = useStyleChangeCallback() const { font, align, verticalAlign } = props if (font === undefined && align === undefined) { return null } return (
{font === undefined ? null : ( )} {align === undefined ? null : (
{verticalAlign === undefined ? (
)}
) } function GeoStylePickerSet({ props }: { props: TLNullableShapeProps }) { const handleValueChange = useStyleChangeCallback() const { geo } = props if (geo === undefined) { return null } return ( ) } function SplineStylePickerSet({ props }: { props: TLNullableShapeProps }) { const handleValueChange = useStyleChangeCallback() const { spline } = props if (spline === undefined) { return null } return ( ) } function ArrowheadStylePickerSet({ props }: { props: TLNullableShapeProps }) { const handleValueChange = useStyleChangeCallback() const { arrowheadEnd, arrowheadStart } = props if (arrowheadEnd === undefined && arrowheadStart === undefined) { return null } return ( ) }