import { ArrowShapeArrowheadEndStyle, ArrowShapeArrowheadStartStyle, DefaultColorStyle, DefaultDashStyle, DefaultFillStyle, DefaultFontStyle, DefaultHorizontalAlignStyle, DefaultSizeStyle, DefaultVerticalAlignStyle, GeoShapeGeoStyle, LineShapeSplineStyle, ReadonlySharedStyleMap, SharedStyle, StyleProp, minBy, useEditor, } from '@bigbluebutton/editor' import React, { useCallback } from 'react' import { useRelevantStyles } from '../../hooks/useRevelantStyles' 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' import { STYLES } from './styles' interface StylePanelProps { isMobile?: boolean } /** @internal */ export const StylePanel = function StylePanel({ isMobile }: StylePanelProps) { const editor = useEditor() const relevantStyles = useRelevantStyles() const handlePointerOut = useCallback(() => { if (!isMobile) { editor.updateInstanceState({ isChangingStyle: false }) } }, [editor, isMobile]) if (!relevantStyles) return null const { styles, opacity } = relevantStyles const geo = styles.get(GeoShapeGeoStyle) const arrowheadEnd = styles.get(ArrowShapeArrowheadEndStyle) const arrowheadStart = styles.get(ArrowShapeArrowheadStartStyle) const spline = styles.get(LineShapeSplineStyle) const font = styles.get(DefaultFontStyle) const hideGeo = geo === undefined const hideArrowHeads = arrowheadEnd === undefined && arrowheadStart === undefined const hideSpline = spline === undefined const hideText = font === undefined return (
{!hideText && } {!(hideGeo && hideArrowHeads && hideSpline) && (
)}
) } function useStyleChangeCallback() { const editor = useEditor() return React.useMemo(() => { return function handleStyleChange(style: StyleProp, value: T, squashing: boolean) { editor.batch(() => { if (editor.isIn('select')) { editor.setStyleForSelectedShapes(style, value, { squashing }) } editor.setStyleForNextShapes(style, value, { squashing }) editor.updateInstanceState({ isChangingStyle: true }) }) } }, [editor]) } const tldrawSupportedOpacities = [0.1, 0.25, 0.5, 0.75, 1] as const function CommonStylePickerSet({ styles, opacity, }: { styles: ReadonlySharedStyleMap opacity: SharedStyle }) { const editor = useEditor() const msg = useTranslation() const handleValueChange = useStyleChangeCallback() const handleOpacityValueChange = React.useCallback( (value: number, ephemeral: boolean) => { const item = tldrawSupportedOpacities[value] editor.batch(() => { if (editor.isIn('select')) { editor.setOpacityForSelectedShapes(item, { ephemeral }) } editor.setOpacityForNextShapes(item, { ephemeral }) editor.updateInstanceState({ isChangingStyle: true }) }) }, [editor] ) const color = styles.get(DefaultColorStyle) const fill = styles.get(DefaultFillStyle) const dash = styles.get(DefaultDashStyle) const size = styles.get(DefaultSizeStyle) const showPickers = fill !== undefined || dash !== undefined || size !== undefined const opacityIndex = opacity.type === 'mixed' ? -1 : tldrawSupportedOpacities.indexOf( minBy(tldrawSupportedOpacities, (supportedOpacity) => Math.abs(supportedOpacity - opacity.value) )! ) return ( <>
{color === undefined ? null : ( )} {opacity === undefined ? null : ( = 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')} /> )}
{showPickers && (
{fill === undefined ? null : ( )} {dash === undefined ? null : ( )} {size === undefined ? null : ( )}
)} ) } function TextStylePickerSet({ styles }: { styles: ReadonlySharedStyleMap }) { const msg = useTranslation() const handleValueChange = useStyleChangeCallback() const font = styles.get(DefaultFontStyle) const align = styles.get(DefaultHorizontalAlignStyle) const verticalAlign = styles.get(DefaultVerticalAlignStyle) if (font === undefined && align === undefined) { return null } return (
{font === undefined ? null : ( )} {align === undefined ? null : (
{verticalAlign === undefined ? (
)}
) } function GeoStylePickerSet({ styles }: { styles: ReadonlySharedStyleMap }) { const handleValueChange = useStyleChangeCallback() const geo = styles.get(GeoShapeGeoStyle) if (geo === undefined) { return null } return ( ) } function SplineStylePickerSet({ styles }: { styles: ReadonlySharedStyleMap }) { const handleValueChange = useStyleChangeCallback() const spline = styles.get(LineShapeSplineStyle) if (spline === undefined) { return null } return ( ) } function ArrowheadStylePickerSet({ styles }: { styles: ReadonlySharedStyleMap }) { const handleValueChange = useStyleChangeCallback() const arrowheadEnd = styles.get(ArrowShapeArrowheadEndStyle) const arrowheadStart = styles.get(ArrowShapeArrowheadStartStyle) if (!arrowheadEnd || !arrowheadStart) { return null } return ( ) }