import * as React from 'react' import {__, _x} from '@wordpress/i18n' import { useContext, useState, } from '@wordpress/element' import { Icon, MenuItem, Modal, __experimentalVStack as VStack, CheckboxControl, } from '@wordpress/components' import { useSelect, useDispatch, } from '@wordpress/data' import { store as blockEditorStore, // @ts-expect-error } from '@wordpress/block-editor' import { store as noticesStore, } from '@wordpress/notices' import { undo as undoIcon, } from '@wordpress/icons' import { ActionInput, } from '@ska/components' import { useSkaBlocksDispatch, } from '../../../tailwind/reducer' import { InspectorControlsContext, type MenuItemProps, } from '../../../tailwind/inspector-controls' import { getAs, } from '../../../supports' import type { tBlockAttributes, } from '@ska/shared' import type { SelectorsValue, } from '..' const MoveToParentModal: React.FC<{parentClientId: string, onRequestClose: () => void}> = ({ parentClientId, onRequestClose, }) => { const { attributes, setAttributes, features, } = useContext(InspectorControlsContext) const { className = '', skaBlocksAs = {}, skaBlocksSelectors = {}, } = attributes const firstClassName = className.split(' ')[0].trim() const [AsElement] = getAs({skaBlocksAs}) const hasAs = Object.keys(skaBlocksAs).length > 0 && !['div', 'span'].includes(AsElement) const initialSelector = firstClassName ? `[&>.${firstClassName}]` : (hasAs ? `[&>${AsElement}]` : `*`) const { createSuccessNotice, } = useDispatch(noticesStore) const parentAttributes = useSelect((select: any) => select(blockEditorStore).getBlockAttributes(parentClientId), [parentClientId]) const {updateBlockAttributes} = useDispatch(blockEditorStore) const setParentAttributes = (nextAttributes: tBlockAttributes) => updateBlockAttributes(parentClientId, nextAttributes) const parentDispatch = useSkaBlocksDispatch(parentAttributes, setParentAttributes) const dispatch = useSkaBlocksDispatch(attributes, setAttributes) const [selector, setSelector] = useState(initialSelector) const usedFeatures = features.filter(({hasValue}) => hasValue) const [excludedFeatures, setExcludedFeatures] = useState([]) const selectors = Object.keys(skaBlocksSelectors) const [excludedSelectors, setExcludedSelectors] = useState([]) const onMove = () => { let targetSelector = selector.trim() if(targetSelector) { // Trim `:` from the right. while(targetSelector[targetSelector.length - 1] === ':') { targetSelector = targetSelector.substring(0, targetSelector.length - 1) } } const { skaBlocksSelectors: parentSkaBlocksSelectors = {}, } = parentAttributes const nextSelectors = selectors.reduce((acc, cur) => { if(!excludedSelectors.includes(cur)) { acc[cur] = { ...acc[cur], ...skaBlocksSelectors[cur], } } return acc }, {...parentSkaBlocksSelectors[targetSelector]} as SelectorsValue) const keptSelectors = selectors.reduce((acc, cur) => { if(excludedSelectors.includes(cur)) { acc[cur] = { ...skaBlocksSelectors[cur], } } return acc }, {} as SelectorsValue) const includedFeatures = usedFeatures.filter(({id}) => !excludedFeatures.includes(id)) const targetAttributes = includedFeatures.reduce((acc, {id}) => { acc[id] = attributes[id] return acc }, {skaBlocksSelectors: nextSelectors} as tBlockAttributes) if(targetSelector) { parentDispatch.updateSelectorValue({ selector: targetSelector, attributes: targetAttributes, }) } else { parentDispatch.setAttributes(targetAttributes) } dispatch.batch([ dispatch.actions.resetFeatures(includedFeatures.map(({id}) => id)), dispatch.actions.setSelectors(keptSelectors), ]) createSuccessNotice(__('Moved classes to parent block', 'ska-blocks'), {type: 'snackbar'}) onRequestClose() } return ( setSelector('')} onSubmit={onMove} disabledWhenBlank={false} />

{__(`Add a selector (e.g. "[&>p]") to create on the parent block or leave blank to apply this block's classes directly on the parent.`, 'ska-blocks')}

{usedFeatures.length > 0 && (
{__('Features', 'ska-blocks')} {usedFeatures.map(({id, label}) => ( setExcludedFeatures( excludedFeatures.includes(id) ? excludedFeatures.filter(eid => eid !== id) : excludedFeatures.concat(id) )} __nextHasNoMarginBottom /> ))}
)} {selectors.length > 0 && (
{__('Selectors', 'ska-blocks')} {selectors.map(selector => ( setExcludedSelectors( excludedSelectors.includes(selector) ? excludedSelectors.filter(s => s !== selector) : excludedSelectors.concat(selector) )} __nextHasNoMarginBottom /> ))}
)}
) } const MoveToParentMenuItem: React.FC = props => { const { clientId, attributes, onClose, } = props const [isOpen, setIsOpen] = useState(false) const blockParents = useSelect((select: any) => select(blockEditorStore).getBlockParents(clientId), [clientId]) const hasParent = blockParents.length > 0 if(!hasParent) { return null } const parent = blockParents[blockParents.length - 1] const { skaBlocks = {}, skaBlocksSelectors = {}, } = attributes const { cx: tailwindClasses = '', } = skaBlocks const hasSelectors = Object.keys(skaBlocksSelectors).length > 0 if(!tailwindClasses && !hasSelectors) { return null } return <> } children={__('Move classes to parent', 'ska-blocks')} onClick={() => { setIsOpen(true) }} /> {isOpen && ( { setIsOpen(false) onClose() }} /> )} } export default MoveToParentMenuItem