import { useState, useMemo } from "react"; import { InspectorControls, BlockControls, MediaUpload, MediaUploadCheck, __experimentalLinkControl as LinkControl, } from "@wordpress/block-editor"; import { Button, SelectControl, TextareaControl, ToolbarButton, ToolbarGroup, Popover, __experimentalToolsPanel as ToolsPanel, __experimentalToolsPanelItem as ToolsPanelItem, __experimentalUnitControl as UnitControl, __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOption as ToggleGroupControlOption, } from "@wordpress/components"; import { __ } from "@wordpress/i18n"; import { alignNone, caption as captionIcon, fullscreen, Icon, link, linkOff, replace, } from "@wordpress/icons"; import { prependHTTP } from "@wordpress/url"; import { BorderControl, BorderRadiusControl, ToolbarWithDropdown, } from "@tableberg/components"; import { CellKey } from "../../attributes"; import { useTableStore } from "../../store"; import { ImageElementAttributes, imageAttrDefaults } from "./element"; import { ElementBindings } from "../../dynamic-data/types"; import { DynamicDataPanel } from "../../components/DynamicDataPanel"; import { ElementDeleteButton } from "../../components/ElementDeleteButton"; import { ElementOptionsBlockControls } from "../../components/ElementOptionsButton"; const ASPECT_RATIO_OPTIONS = [ { label: __("Original", "tableberg"), value: "" }, { label: __("Square - 1:1", "tableberg"), value: "1" }, { label: __("Standard - 4:3", "tableberg"), value: "4/3" }, { label: __("Portrait - 3:4", "tableberg"), value: "3/4" }, { label: __("Classic - 3:2", "tableberg"), value: "3/2" }, { label: __("Classic Portrait - 2:3", "tableberg"), value: "2/3" }, { label: __("Wide - 16:9", "tableberg"), value: "16/9" }, { label: __("Tall - 9:16", "tableberg"), value: "9/16" }, ]; const SCALE_OPTIONS = [ { value: "cover", label: __("Cover", "tableberg"), help: __("Fill the space by clipping what doesn't fit.", "tableberg"), }, { value: "contain", label: __("Contain", "tableberg"), help: __("Fit the content to the space without clipping.", "tableberg"), }, ]; const SIZE_SLUG_OPTIONS = [ { label: __("Thumbnail", "tableberg"), value: "thumbnail" }, { label: __("Medium", "tableberg"), value: "medium" }, { label: __("Large", "tableberg"), value: "large" }, { label: __("Full Size", "tableberg"), value: "full" }, ]; export function ImageElementControls({ attributes, bindings, showCaption, setShowCaption, cellCoords, elementIndex, updateAttrs: updateAttrsProp, }: { attributes: ImageElementAttributes; bindings?: ElementBindings; showCaption: boolean; setShowCaption: (show: boolean) => void; cellCoords: CellKey; elementIndex: number; // Native block edits inject a setAttributes-based updater; store-backed // element renderers use the table-store fallback. updateAttrs?: (attrs: Partial) => void; }) { const { media, alt, aspectRatio, height, width, scale, sizeSlug, href, linkTarget, lightbox, align, border, borderRadius, caption, } = attributes; const storeUpdateAttrs = useTableStore( state => state.updateSelectedElementAttrs ); const updateAttrs = updateAttrsProp ?? storeUpdateAttrs; const [isEditingURL, setIsEditingURL] = useState(false); const isURLSet = !!href; const isLightboxEnabled = !!lightbox?.enabled; const hasLinkAction = isURLSet || isLightboxEnabled; const opensInNewTab = linkTarget === "_blank"; const linkValue = useMemo( () => ({ url: href, opensInNewTab }), [href, opensInNewTab] ); const unlink = () => { updateAttrs({ href: "", linkTarget: "_self", lightbox: imageAttrDefaults.lightbox, }); setIsEditingURL(false); }; const toggleLightbox = () => { updateAttrs({ lightbox: { enabled: !isLightboxEnabled, }, ...(!isLightboxEnabled ? { href: "", linkTarget: "_self", } : {}), }); setIsEditingURL(false); }; const onSelectMedia = (newMedia: any) => { if (!newMedia || !newMedia.url) { updateAttrs({ media: {} }); return; } updateAttrs({ media: { id: newMedia.id, url: newMedia.url, alt: newMedia.alt || "", title: newMedia.title || "", sizes: newMedia.sizes || {}, }, alt: newMedia.alt || "", }); }; const hasImage = !!media.url || !!media.id; const scaleHelp = useMemo(() => { return SCALE_OPTIONS.reduce( (acc: { [key: string]: string }, option) => { acc[option.value] = option.help; return acc; }, {} ); }, []); const resetAll = () => { updateAttrs({ alt: "", aspectRatio: "", height: "", scale: "cover", width: "150px", sizeSlug: "large", lightbox: imageAttrDefaults.lightbox, }); }; return ( <> { if (newVal) { updateAttrs({ align: newVal as "left" | "center" | "right", }); } }} controlset="alignment" /> { setShowCaption(!showCaption); if (showCaption && caption) { updateAttrs({ caption: "" }); } }} icon={captionIcon} isPressed={showCaption} label={ showCaption ? __("Remove caption", "tableberg") : __("Add caption", "tableberg") } /> setIsEditingURL(true)} isActive={hasLinkAction} /> {isEditingURL && ( setIsEditingURL(false)} shift > {isLightboxEnabled ? (
{__( "Enlarge on click", "tableberg" )} {__( "Scales the image with a lightbox effect", "tableberg" )}
) : ( <> { updateAttrs({ href: prependHTTP(newURL), linkTarget: newOpensInNewTab ? "_blank" : "_self", lightbox: imageAttrDefaults.lightbox, }); }} onRemove={unlink} /> {hasImage && (
)} )}
)}
{hasImage && ( ( )} /> )} !!alt} label={__("Alternative Text", "tableberg")} onDeselect={() => updateAttrs({ alt: "" })} > updateAttrs({ alt: newValue }) } help={__( "Describe the image for screen readers.", "tableberg" )} /> updateAttrs({ aspectRatio: "" })} hasValue={() => aspectRatio !== ""} > updateAttrs({ aspectRatio: newValue }) } /> {aspectRatio && ( scale !== "cover"} onDeselect={() => updateAttrs({ scale: "cover" })} > updateAttrs({ scale: newScale as string }) } __nextHasNoMarginBottom > {SCALE_OPTIONS.map(option => ( ))} )}
width !== "" && width !== "150px"} onDeselect={() => updateAttrs({ width: "150px" })} > updateAttrs({ width: newWidth || "" }) } /> height !== ""} onDeselect={() => updateAttrs({ height: "" })} > updateAttrs({ height: newHeight || "" }) } />
{hasImage && media.sizes && Object.keys(media.sizes).length > 0 && ( sizeSlug !== "large"} onDeselect={() => updateAttrs({ sizeSlug: "large" }) } > media.sizes?.[opt.value] )} onChange={(newSlug: string) => updateAttrs({ sizeSlug: newSlug }) } help={__( "Select the size of the source image.", "tableberg" )} /> )}
updateAttrs({ border: newBorder }) } onDeselect={() => updateAttrs({ border: imageAttrDefaults.border }) } hasValue={() => !!border.top || !!border.right || !!border.bottom || !!border.left } /> updateAttrs({ borderRadius: newRadius }) } onDeselect={() => updateAttrs({ borderRadius: imageAttrDefaults.borderRadius, }) } hasValue={() => !!borderRadius.topLeft || !!borderRadius.topRight || !!borderRadius.bottomLeft || !!borderRadius.bottomRight } /> ); }