import { __ } from '@wordpress/i18n'; import { useState, useEffect, useCallback, useMemo } from 'react'; import { Flex, FlexBlock, } from '@wordpress/components'; export type Tab = { label: string, controls: string[], } type Props = { tabs: { [key in string]: Tab }, description?: string, } /** * コントロール要素をIDから取得する * Customizer API から container を取得する */ const getControlElementById = (controlId: string): HTMLElement | null => { const control = wp.customize.control(controlId); if (control?.container?.length) { return control.container[0] as HTMLElement; } return null; }; const isControlActive = (controlId: string): boolean => { const control = wp.customize.control(controlId); if (typeof control?.active?.get === 'function') { return Boolean(control.active.get()); } return true; }; export default function ApuraTabs({ tabs, description }: Props) { const keys = useMemo(() => Object.keys(tabs), [tabs]); // 最初のタブをアクティブにする const [activeTab, setActiveTab] = useState(keys[0]); const syncControlVisibility = useCallback((tabKey: string) => { Object.keys(tabs).forEach(key => { const isVisibleTab = key === tabKey; tabs[key].controls.forEach(controlId => { const controlElement = getControlElementById(controlId); if (!controlElement) { console.warn(`Control element not found for ID: ${controlId}`); return; } controlElement.style.display = isVisibleTab && isControlActive(controlId) ? '' : 'none'; }); }); }, [tabs]); const onChangeTab = useCallback((tabKey: string) => { setActiveTab(tabKey); }, []); // 初回レンダリング時に最初のタブをアクティブにする useEffect(() => { if (!keys.length) { return; } if (!tabs[activeTab]) { setActiveTab(keys[0]); } }, [activeTab, keys, tabs]); useEffect(() => { if (!activeTab) { return; } syncControlVisibility(activeTab); }, [activeTab, syncControlVisibility]); useEffect(() => { const unbinders: Array<() => void> = []; const controlIds = Array.from(new Set(keys.flatMap((key) => tabs[key].controls))); controlIds.forEach((controlId) => { const control = wp.customize.control(controlId); if (!control?.active || typeof control.active.bind !== 'function' || typeof control.active.unbind !== 'function') { return; } const listener = () => { syncControlVisibility(activeTab); }; control.active.bind(listener); unbinders.push(() => control.active.unbind(listener)); }); return () => { unbinders.forEach((unbind) => unbind()); }; }, [activeTab, keys, syncControlVisibility, tabs]); return (
{keys.map((key) => ( ))} {description && (
{description}
)}
); }