Added Dataset Builder
This commit is contained in:
@ -1 +1 @@
|
|||||||
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '79dffd7b201fcf20bc7c');
|
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'c6994dab2419d48d7900');
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -5,6 +5,7 @@ import { __ } from '@wordpress/i18n';
|
|||||||
import { SelectControl, TextareaControl, Button, TextControl } from '@wordpress/components';
|
import { SelectControl, TextareaControl, Button, TextControl } from '@wordpress/components';
|
||||||
import { useState, useEffect } from '@wordpress/element';
|
import { useState, useEffect } from '@wordpress/element';
|
||||||
import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';
|
import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';
|
||||||
|
import LCPDatasetBuilder from './LCPDatasetBuilder';
|
||||||
|
|
||||||
const DEFAULT_COLORS = [
|
const DEFAULT_COLORS = [
|
||||||
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF',
|
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF',
|
||||||
@ -43,6 +44,7 @@ const LCPDataSelector = ({ value, onChange, dataSource, onDataSourceChange }) =>
|
|||||||
{ label: __('Manual JSON', 'lcp'), value: 'manual_json' },
|
{ label: __('Manual JSON', 'lcp'), value: 'manual_json' },
|
||||||
{ label: __('CSV Upload', 'lcp'), value: 'csv_upload' },
|
{ label: __('CSV Upload', 'lcp'), value: 'csv_upload' },
|
||||||
{ label: __('CSV URL', 'lcp'), value: 'csv_url' },
|
{ label: __('CSV URL', 'lcp'), value: 'csv_url' },
|
||||||
|
{ label: __('Dataset Builder', 'lcp'), value: 'dataset_builder' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const validateJsonData = (jsonString) => {
|
const validateJsonData = (jsonString) => {
|
||||||
@ -170,6 +172,15 @@ const LCPDataSelector = ({ value, onChange, dataSource, onDataSourceChange }) =>
|
|||||||
onChange={onDataSourceChange}
|
onChange={onDataSourceChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{dataSource === 'dataset_builder' && (
|
||||||
|
<LCPDatasetBuilder
|
||||||
|
value={value}
|
||||||
|
onChange={(newValue) => {
|
||||||
|
onChange(newValue);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{dataSource === 'manual_json' && (
|
{dataSource === 'manual_json' && (
|
||||||
<TextareaControl
|
<TextareaControl
|
||||||
label={__('JSON Data', 'lcp')}
|
label={__('JSON Data', 'lcp')}
|
||||||
|
|||||||
285
components/LCPDatasetBuilder.js
Normal file
285
components/LCPDatasetBuilder.js
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
marginLeft: item.parent ? '20px' : '0',
|
||||||
|
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 (
|
||||||
|
<div>
|
||||||
|
<div ref={ref} style={style}>
|
||||||
|
<Card>
|
||||||
|
<CardBody>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<TextControl
|
||||||
|
placeholder={__('Label', 'lcp')}
|
||||||
|
value={item.label}
|
||||||
|
onChange={(value) => updateItem(datasetKey, item.id, 'label', value)}
|
||||||
|
style={{ flex: 2 }}
|
||||||
|
/>
|
||||||
|
<TextControl
|
||||||
|
type="number"
|
||||||
|
placeholder={__('Value', 'lcp')}
|
||||||
|
value={item.value}
|
||||||
|
onChange={(value) => updateItem(datasetKey, item.id, 'value', parseFloat(value))}
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
/>
|
||||||
|
<div style={{ position: 'relative' }}>
|
||||||
|
<Button
|
||||||
|
onClick={() => setShowColorPicker(true)}
|
||||||
|
style={{
|
||||||
|
backgroundColor: item.color,
|
||||||
|
width: '30px',
|
||||||
|
height: '30px',
|
||||||
|
borderRadius: '50%',
|
||||||
|
padding: 0,
|
||||||
|
border: '1px solid #ddd'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{showColorPicker && (
|
||||||
|
<Popover
|
||||||
|
onClose={() => setShowColorPicker(false)}
|
||||||
|
position="bottom center"
|
||||||
|
>
|
||||||
|
<div style={{ padding: '10px' }}>
|
||||||
|
<ColorPicker
|
||||||
|
color={item.color}
|
||||||
|
onChange={(value) => updateItem(datasetKey, item.id, 'color', value)}
|
||||||
|
enableAlpha={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
{/* Render child items */}
|
||||||
|
{childItems.map(childItem => (
|
||||||
|
<DatasetItem
|
||||||
|
key={childItem.id}
|
||||||
|
item={childItem}
|
||||||
|
datasetKey={datasetKey}
|
||||||
|
moveItem={moveItem}
|
||||||
|
updateItem={updateItem}
|
||||||
|
items={items}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setIsModalOpen(true);
|
||||||
|
if (Object.keys(datasets).length === 0) {
|
||||||
|
addNewDataset();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{__('Open Dataset Builder', 'lcp')}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{isModalOpen && (
|
||||||
|
<Modal
|
||||||
|
title={__('Dataset Builder', 'lcp')}
|
||||||
|
onRequestClose={() => setIsModalOpen(false)}
|
||||||
|
style={{ width: '90vw' }}
|
||||||
|
>
|
||||||
|
<DndProvider backend={HTML5Backend}>
|
||||||
|
<div style={{ padding: '20px' }}>
|
||||||
|
{Object.entries(datasets).map(([datasetKey, items]) => (
|
||||||
|
<div key={datasetKey} style={{ marginBottom: '20px' }}>
|
||||||
|
<h3>{datasetKey}</h3>
|
||||||
|
<div>
|
||||||
|
{items
|
||||||
|
.filter(item => !item.parent) // Only render top-level items
|
||||||
|
.map(item => (
|
||||||
|
<DatasetItem
|
||||||
|
key={item.id}
|
||||||
|
item={item}
|
||||||
|
datasetKey={datasetKey}
|
||||||
|
moveItem={moveItem}
|
||||||
|
updateItem={updateItem}
|
||||||
|
items={items}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
onClick={() => addNewItem(datasetKey)}
|
||||||
|
style={{ marginTop: '10px' }}
|
||||||
|
>
|
||||||
|
{__('Add Item', 'lcp')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
onClick={addNewDataset}
|
||||||
|
style={{ marginTop: '20px' }}
|
||||||
|
>
|
||||||
|
{__('Add New Dataset', 'lcp')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DndProvider>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LCPDatasetBuilder;
|
||||||
135
package-lock.json
generated
135
package-lock.json
generated
@ -2,5 +2,138 @@
|
|||||||
"name": "lcp-data-blocks",
|
"name": "lcp-data-blocks",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {}
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"react-dnd": "^16.0.1",
|
||||||
|
"react-dnd-html5-backend": "^16.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/runtime": {
|
||||||
|
"version": "7.26.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
|
||||||
|
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"regenerator-runtime": "^0.14.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-dnd/asap": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@react-dnd/invariant": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@react-dnd/shallowequal": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/dnd-core": {
|
||||||
|
"version": "16.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz",
|
||||||
|
"integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-dnd/asap": "^5.0.1",
|
||||||
|
"@react-dnd/invariant": "^4.0.1",
|
||||||
|
"redux": "^4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fast-deep-equal": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/hoist-non-react-statics": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"react-is": "^16.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react": {
|
||||||
|
"version": "19.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
|
||||||
|
"integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-dnd": {
|
||||||
|
"version": "16.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz",
|
||||||
|
"integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-dnd/invariant": "^4.0.1",
|
||||||
|
"@react-dnd/shallowequal": "^4.0.1",
|
||||||
|
"dnd-core": "^16.0.1",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"hoist-non-react-statics": "^3.3.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/hoist-non-react-statics": ">= 3.3.1",
|
||||||
|
"@types/node": ">= 12",
|
||||||
|
"@types/react": ">= 16",
|
||||||
|
"react": ">= 16.14"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/hoist-non-react-statics": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-dnd-html5-backend": {
|
||||||
|
"version": "16.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz",
|
||||||
|
"integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dnd-core": "^16.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/redux": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/regenerator-runtime": {
|
||||||
|
"version": "0.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||||
|
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
package.json
Normal file
6
package.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"react-dnd": "^16.0.1",
|
||||||
|
"react-dnd-html5-backend": "^16.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user