/** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; import { Button, Modal, TextControl, ColorPicker, Card, CardBody, Popover, } from '@wordpress/components'; import { useState, useRef } from '@wordpress/element'; import { DndProvider, useDrag, useDrop } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; const ItemTypes = { DATASET_ITEM: 'dataset_item' }; const DatasetItem = ({ item, datasetKey, moveItem, updateItem, items }) => { const [showColorPicker, setShowColorPicker] = useState(false); const ref = useRef(null); const [{ isDragging }, drag] = useDrag({ type: ItemTypes.DATASET_ITEM, item: { id: item.id, datasetKey }, collect: (monitor) => ({ isDragging: monitor.isDragging(), }), }); const [{ isOver }, drop] = useDrop({ accept: ItemTypes.DATASET_ITEM, hover(draggedItem, monitor) { if (!ref.current) return; if (draggedItem.id === item.id) return; const hoverBoundingRect = ref.current.getBoundingClientRect(); const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; const hoverMiddleX = (hoverBoundingRect.right - hoverBoundingRect.left) / 2; const clientOffset = monitor.getClientOffset(); if (!clientOffset) return; const hoverClientY = clientOffset.y - hoverBoundingRect.top; const hoverClientX = clientOffset.x - hoverBoundingRect.left; // If hovering in the right half and below middle, make it a child const shouldBeChild = hoverClientX > hoverMiddleX && hoverClientY > hoverMiddleY; moveItem(draggedItem.id, item.id, shouldBeChild); }, collect: (monitor) => ({ isOver: monitor.isOver(), }), }); // Initialize drag and drop refs drag(drop(ref)); // Get child items const childItems = items.filter(i => i.parent === item.id); // Calculate the nesting level const getItemDepth = (itemId) => { let depth = 0; let currentItem = items.find(i => i.id === itemId); while (currentItem && currentItem.parent) { depth++; currentItem = items.find(i => i.id === currentItem.parent); } return depth; }; const depth = getItemDepth(item.id); const style = { marginLeft: `${depth * 20}px`, // 20px indentation per level opacity: isDragging ? 0.5 : 1, cursor: 'move', background: isOver ? '#f0f0f0' : 'white', border: isOver ? '2px dashed #0073aa' : '1px solid #e2e4e7', marginBottom: '8px', transition: 'all 0.2s ease', }; return (
updateItem(datasetKey, item.id, 'label', value)} style={{ flex: 2 }} /> updateItem(datasetKey, item.id, 'value', parseFloat(value))} style={{ flex: 1 }} />
{/* Render child items */} {childItems.map(childItem => ( ))}
); }; const LCPDatasetBuilder = ({ value, onChange }) => { const [isModalOpen, setIsModalOpen] = useState(false); const [datasets, setDatasets] = useState(value || {}); const addNewDataset = () => { const newDatasetName = `Dataset ${Object.keys(datasets).length + 1}`; const updatedDatasets = { ...datasets, [newDatasetName]: [{ id: `dataset-${Date.now()}`, label: newDatasetName, parent: null, value: 0, color: '#000000' }] }; setDatasets(updatedDatasets); onChange(updatedDatasets); }; const addNewItem = (datasetKey) => { const newItem = { id: `item-${Date.now()}`, label: 'New Item', parent: null, value: 0, color: '#000000' }; const updatedDatasets = { ...datasets, [datasetKey]: [...datasets[datasetKey], newItem] }; setDatasets(updatedDatasets); onChange(updatedDatasets); }; const updateItem = (datasetKey, itemId, field, value) => { const updatedDatasets = { ...datasets, [datasetKey]: datasets[datasetKey].map(item => item.id === itemId ? { ...item, [field]: value } : item ) }; setDatasets(updatedDatasets); onChange(updatedDatasets); }; const moveItem = (draggedId, targetId, makeChild) => { const datasetKey = Object.keys(datasets).find(key => datasets[key].some(item => item.id === draggedId) ); if (!datasetKey) return; const items = [...datasets[datasetKey]]; const draggedItem = items.find(item => item.id === draggedId); const targetItem = items.find(item => item.id === targetId); if (!draggedItem || !targetItem) return; // If target is a descendant of dragged item, prevent the move let current = targetItem; while (current.parent) { if (current.parent === draggedId) return; current = items.find(item => item.id === current.parent); } // Update parent reference draggedItem.parent = makeChild ? targetId : targetItem.parent; const updatedDatasets = { ...datasets, [datasetKey]: items }; setDatasets(updatedDatasets); onChange(updatedDatasets); }; return ( <> {isModalOpen && ( setIsModalOpen(false)} style={{ width: '90vw' }} >
{Object.entries(datasets).map(([datasetKey, items]) => (

{datasetKey}

{items .filter(item => !item.parent) // Only render top-level items .map(item => ( )) }
))}
)} ); }; export default LCPDatasetBuilder;