UNPKG

@wordpress/block-library

Version:
197 lines (196 loc) 6.68 kB
// packages/block-library/src/tab-list/edit.js import clsx from "clsx"; import { __ } from "@wordpress/i18n"; import { InspectorControls, useBlockProps, store as blockEditorStore, RichText, __experimentalUseBorderProps as useBorderProps, __experimentalUseColorProps as useColorProps, __experimentalGetSpacingClassesAndStyles as getSpacingClassesAndStyles } from "@wordpress/block-editor"; import { TextControl, __experimentalToolsPanel as ToolsPanel, __experimentalToolsPanelItem as ToolsPanelItem } from "@wordpress/components"; import { useSelect, useDispatch, useRegistry } from "@wordpress/data"; import { useEffect, useMemo, useRef } from "@wordpress/element"; import TabToolbarControls from "../tabs/tab-toolbar-controls.mjs"; import TabMovers from "./tab-movers.mjs"; import useTabActions from "../tabs/use-tab-actions.mjs"; import { useToolsPanelDropdownMenuProps } from "../utils/hooks.mjs"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; var EMPTY_ARRAY = []; function Edit({ attributes, clientId, setAttributes, __unstableLayoutClassNames: layoutClassNames }) { const { ariaLabel } = attributes; const colorProps = useColorProps(attributes); const borderProps = useBorderProps(attributes); const spacingProps = getSpacingClassesAndStyles(attributes); const dropdownMenuProps = useToolsPanelDropdownMenuProps(); const { tabsClientId, tabPanels, editorActiveTabIndex, activeTabIndex } = useSelect( (select) => { const { getBlockRootClientId, getBlockAttributes, getBlocks } = select(blockEditorStore); const rootClientId = getBlockRootClientId(clientId); const tabsAttributes = getBlockAttributes(rootClientId); const tabPanelsBlock = getBlocks(rootClientId)?.find( (block) => block.name === "core/tab-panels" ); return { tabsClientId: rootClientId, tabPanels: tabPanelsBlock?.innerBlocks ?? EMPTY_ARRAY, editorActiveTabIndex: tabsAttributes?.editorActiveTabIndex, activeTabIndex: tabsAttributes?.activeTabIndex ?? 0 }; }, [clientId] ); const registry = useRegistry(); const { isBlockSelected, hasSelectedInnerBlock } = useSelect(blockEditorStore); const { updateBlockAttributes, selectBlock, __unstableMarkNextChangeAsNotPersistent } = useDispatch(blockEditorStore); const { insertTab, removeTab } = useTabActions(tabsClientId); const effectiveActiveIndex = editorActiveTabIndex ?? activeTabIndex; const tabsList = useMemo( () => tabPanels.map((tab) => ({ label: tab.attributes.label || "", clientId: tab.clientId })), [tabPanels] ); function selectTabPanel(tabIndex) { if (tabsClientId && tabIndex !== effectiveActiveIndex) { registry.batch(() => { selectBlock(clientId); __unstableMarkNextChangeAsNotPersistent(); updateBlockAttributes(tabsClientId, { editorActiveTabIndex: tabIndex }); }); } } function handleLabelChange(tabIndex, newLabel) { const tab = tabsList[tabIndex]; if (tab?.clientId) { updateBlockAttributes(tab.clientId, { label: newLabel }); } } const menuRef = useRef(); const prevTabCountRef = useRef(tabsList.length); useEffect(() => { const prevCount = prevTabCountRef.current; prevTabCountRef.current = tabsList.length; if (!menuRef.current || tabsList.length === prevCount) { return; } if (!isBlockSelected(tabsClientId) && !hasSelectedInnerBlock(tabsClientId, true)) { return; } const focusButtonAt = (index) => { window.requestAnimationFrame(() => { const button = menuRef.current?.querySelectorAll("button")?.[index]; (button?.querySelector("[contenteditable]") ?? button)?.focus(); }); }; focusButtonAt(effectiveActiveIndex); }, [ effectiveActiveIndex, hasSelectedInnerBlock, isBlockSelected, tabsClientId, tabsList.length ]); const blockProps = useBlockProps({ role: "tablist", ref: menuRef, // Applied manually since this block has no inner blocks for the layout // support to add its container classes to. className: layoutClassNames }); const buttonClassName = clsx(colorProps.className, borderProps.className); const buttonStyle = { ...colorProps.style, ...borderProps.style, ...spacingProps.style }; return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(InspectorControls, { group: "settings", children: /* @__PURE__ */ jsx( ToolsPanel, { label: __("Settings"), resetAll: () => setAttributes({ ariaLabel: void 0 }), dropdownMenuProps, children: /* @__PURE__ */ jsx( ToolsPanelItem, { label: __("Label"), isShownByDefault: true, hasValue: () => !!ariaLabel, onDeselect: () => setAttributes({ ariaLabel: void 0 }), children: /* @__PURE__ */ jsx( TextControl, { label: __("Label"), help: __( "Briefly describe this tab section for screen reader users. Examples: Event information, Product details, and Account settings." ), value: ariaLabel || "", onChange: (value) => setAttributes({ ariaLabel: value || void 0 }) } ) } ) } ) }), /* @__PURE__ */ jsx(TabMovers, { tabsClientId }), /* @__PURE__ */ jsx(TabToolbarControls, { tabsClientId }), /* @__PURE__ */ jsx("div", { ...blockProps, children: tabsList.map((tab, index) => { const isActive = index === effectiveActiveIndex; return /* @__PURE__ */ jsx( "button", { type: "button", role: "tab", "aria-selected": isActive, className: buttonClassName || void 0, style: buttonStyle, tabIndex: -1, onFocus: () => { selectTabPanel(index); }, children: /* @__PURE__ */ jsx( RichText, { tagName: "span", withoutInteractiveFormatting: true, placeholder: __("Tab title"), value: tab.label, onChange: (newLabel) => handleLabelChange(index, newLabel), __unstableOnSplitAtEnd: () => insertTab(index + 1), onRemove: () => removeTab(index) } ) }, tab.clientId || index ); }) }) ] }); } var edit_default = Edit; export { edit_default as default }; //# sourceMappingURL=edit.mjs.map