From 0f2537c8ade05c0373fc99317b3fbc2dc064f9df Mon Sep 17 00:00:00 2001 From: Bervianto Leo Pratama Date: Sun, 18 Oct 2020 16:03:23 +0700 Subject: [PATCH 1/4] Migrate the class to function component --- package.json | 7 +- src/ReactMultiCrop/ReactMultiCrop.stories.tsx | 7 +- src/ReactMultiCrop/ReactMultiCrop.tsx | 432 +++++++-------- src/ReactMultiCrop/ReactMultiCrop.types.ts | 12 +- src/ReactMultiCrop/ReactMultiCropForm.tsx | 29 + yarn.lock | 511 +++++++++++++++++- 6 files changed, 739 insertions(+), 259 deletions(-) create mode 100644 src/ReactMultiCrop/ReactMultiCropForm.tsx diff --git a/package.json b/package.json index 1d4826e..d4ce50e 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,8 @@ "homepage": "https://github.com/bervProject/ReactMultiCrop#readme", "peerDependencies": { "@material-ui/core": ">=4.2.1", - "fabric": ">=3.3.2", - "react": ">=16.5.2" + "fabric": ">=4.0", + "react": "^16.9.0" }, "devDependencies": { "@babel/core": "^7.12.3", @@ -46,6 +46,7 @@ "@types/jest": "^26.0.14", "@types/react": "^16.9.53", "@types/react-dom": "^16.9.8", + "@types/redux-form": "^8.3.0", "babel-loader": "^8.1.0", "babel-preset-react-app": "^9.1.2", "cross-env": "^7.0.2", @@ -53,7 +54,9 @@ "identity-obj-proxy": "^3.0.0", "jest": "^26.5.3", "prettier": "^2.1.2", + "ra-data-simple-rest": "^3.9.3", "react": "^16.14.0", + "react-admin": "^3.9.4", "react-dom": "^16.14.0", "rollup": "^2.32.0", "rollup-plugin-peer-deps-external": "^2.2.3", diff --git a/src/ReactMultiCrop/ReactMultiCrop.stories.tsx b/src/ReactMultiCrop/ReactMultiCrop.stories.tsx index d19a0af..05cd962 100644 --- a/src/ReactMultiCrop/ReactMultiCrop.stories.tsx +++ b/src/ReactMultiCrop/ReactMultiCrop.stories.tsx @@ -1,11 +1,8 @@ import React from "react"; -import ReactMultiCrop from "./ReactMultiCrop"; +import ReactMultiCropForm from "./ReactMultiCropForm"; export default { title: "ReactMultiCrop" }; -export const Canvas = () => ; +export const Canvas = () => ; diff --git a/src/ReactMultiCrop/ReactMultiCrop.tsx b/src/ReactMultiCrop/ReactMultiCrop.tsx index de25759..9a147b9 100644 --- a/src/ReactMultiCrop/ReactMultiCrop.tsx +++ b/src/ReactMultiCrop/ReactMultiCrop.tsx @@ -1,127 +1,93 @@ -import React, { Component } from "react"; +import React, { Component, useState, useEffect } from "react"; import { fabric } from "fabric"; +import { useInput } from "react-admin"; import { Button, Grid } from "@material-ui/core"; import { - ReactMultiCropProps, - ReactMultiCropStates, + ReactMultiCropProps } from "./ReactMultiCrop.types"; -export default class ReactMultiCrop extends Component< - ReactMultiCropProps, - ReactMultiCropStates -> { - public static defaultProps: ReactMultiCropProps = { - id: "canvas", - color: "grey", - opacity: 0.5, - strokeColor: "yellow", - strokeDashArray: [5, 5], - strokeWidth: 5, - record: [], - input: { - value: "", - name: "", - onChange: function () {}, - }, - }; +const defaultProps: ReactMultiCropProps = { + id: "canvas", + source: "crop", + color: "grey", + opacity: 0.5, + strokeColor: "yellow", + strokeDashArray: [5, 5], + strokeWidth: 5, + record: [], +}; - state: ReactMultiCropStates = { - canvas: null, - initial: true, - }; - constructor(props: ReactMultiCropProps) { - super(props); - this.handleKeyPress = this.handleKeyPress.bind(this); - this.handleNewShape = this.handleNewShape.bind(this); - this.handleDeleteShape = this.handleDeleteShape.bind(this); - this.handleMultiSelect = this.handleMultiSelect.bind(this); - this.handleDiscardActiveObject = this.handleDiscardActiveObject.bind(this); - } - - componentDidMount(): void { - this.initialCanvas(); - } - - componentDidUpdate(): void { - this.changeImage(); - } +const ReactMultiCrop: React.FC = (props: ReactMultiCropProps) => { + const [canvas, setCanvas] = useState(null); + const [initial, setInitial] = useState(true); + const { + input: { value, name }, + ...anotherProp + } = useInput(props); - changeImage(): void { - const { record } = this.props; - const setImage = this.loadImage.bind(this); - fabric.Image.fromURL(record.image, setImage); - } - - loadImage(img: fabric.Image): void { - const { initial, canvas } = this.state; - if (!canvas) { - return; + function createObject(canvas: fabric.Canvas, coor: any): fabric.Rect { + const { + color, + opacity, + strokeDashArray, + strokeColor, + strokeWidth, + } = props; + let rectangle; + if (typeof coor.rect === "string") { + rectangle = JSON.parse(coor.rect); + } else { + rectangle = coor.rect; } - canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), { - scaleX: canvas.getWidth() / (img.width || 1), - scaleY: canvas.getHeight() / (img.height || 1), + const left = canvas.getWidth() * rectangle.x1; + const top = canvas.getHeight() * rectangle.y1; + const right = canvas.getWidth() * rectangle.x2; + const bottom = canvas.getHeight() * rectangle.y2; + const width = right - left; + const height = bottom - top; + return new fabric.Rect({ + left: left, + top: top, + width: width, + height: height, + fill: color, + opacity: opacity, + data: coor.id, + strokeDashArray: strokeDashArray, + stroke: strokeColor, + strokeWidth: strokeWidth, }); - if (initial) { - this.setState({ initial: false }, this.initialObjects.bind(this)); - } - } - - initialImage(): void { - const { record } = this.props; - const loadImageNow = this.loadImage.bind(this); - fabric.Image.fromURL(record.image, loadImageNow); } - initialObjects(): void { - const { canvas } = this.state; - if (!canvas) { - return; - } - const { record } = this.props; - const setOutput = this.setOutput.bind(this); - const setStateOf = this.setState.bind(this); - const inputObject = record.clippings; - const createObject = this.createObject.bind(this); - if (inputObject !== undefined) { - inputObject.forEach(function (coord: any) { - const rect = createObject(canvas, coord); - canvas.add(rect); - }); - } - canvas.renderAll(); - setStateOf({ canvas }, setOutput); - } - - initialCanvas(): void { - const canvas = new fabric.Canvas(this.props.id); - canvas.uniScaleTransform = true; - const doubleClickEvent = this.doubleClickEvent.bind(this); - const objectModifiedEvent = this.setOutput.bind(this); - canvas.on("mouse:dblclick", doubleClickEvent); - canvas.on("object:modified", objectModifiedEvent); - const initialImg = this.initialImage.bind(this); - this.setState({ canvas }, initialImg); - } - - handleNewShape(): void { - const { canvas } = this.state; + function handleNewShape(): void { if (!canvas) { return; } const coor: any = {}; coor.id = null; coor.rect = { x1: 0, y1: 0, x2: 0.2, y2: 0.2 }; - const rect = this.createObject(canvas, coor); + const rect = createObject(canvas, coor); rect.lockRotation = true; canvas.add(rect); canvas.renderAll(); - this.setState({ canvas }, this.setOutput); + setOutput(); + } + + function handleMultiSelect(): void { + if (!canvas) { + return; + } + canvas.discardActiveObject(); + const sel = new fabric.ActiveSelection(canvas.getObjects(), { + canvas: canvas, + }); + canvas.setActiveObject(sel); + canvas.requestRenderAll(); } - doubleClickEvent(options: any): void { + function doubleClickEvent(options: any): void { if (options.target) { - const { canvas } = this.state; if (!canvas) { return; } @@ -134,22 +100,22 @@ export default class ReactMultiCrop extends Component< attribute.top = top + 5; attribute.width = width * options.target.scaleX; attribute.height = height * options.target.scaleY; - const rect = this.createObjectByAttribute(attribute); + const rect = createObjectByAttribute(attribute); rect.lockRotation = true; canvas.add(rect); canvas.renderAll(); - this.setState({ canvas }, this.setOutput); + setOutput(); } } - createObjectByAttribute(attribute: any): fabric.Rect { + function createObjectByAttribute(attribute: any): fabric.Rect { const { color, opacity, strokeDashArray, strokeColor, strokeWidth, - } = this.props; + } = props; return new fabric.Rect({ left: attribute.left, top: attribute.top, @@ -164,8 +130,7 @@ export default class ReactMultiCrop extends Component< }); } - shapetoStructureData(element: fabric.Object): any { - const { canvas } = this.state; + function shapetoStructureData(element: fabric.Object): any { if (!canvas) { return; } @@ -197,175 +162,184 @@ export default class ReactMultiCrop extends Component< return coord; } - handleDeleteShape(): void { - const { canvas } = this.state; + function handleDeleteShape(): void { if (canvas) { canvas.getActiveObjects().forEach(function (element: fabric.Object) { canvas.remove(element); }); - this.setState({ canvas }, this.setOutput); + setOutput(); + //this.setState({ canvas }, this.setOutput); } } - setOutput(): void { - const { canvas } = this.state; + function setOutput(): void { if (!canvas) { return; } - const shapeToStructureData = this.shapetoStructureData.bind(this); const outputValue: Array = []; const cropcoords = canvas.getObjects(); cropcoords.forEach(function (element: fabric.Object) { - outputValue.push(shapeToStructureData(element)); + outputValue.push(shapetoStructureData(element)); }); // let stringOut = JSON.stringify(outputValue) - this.props.input.onChange(outputValue); - } - - createObject(canvas: fabric.Canvas, coor: any): fabric.Rect { - const { - color, - opacity, - strokeDashArray, - strokeColor, - strokeWidth, - } = this.props; - let rectangle; - if (typeof coor.rect === "string") { - rectangle = JSON.parse(coor.rect); - } else { - rectangle = coor.rect; + if (props.input) { + props.input.onChange(outputValue); } - const left = canvas.getWidth() * rectangle.x1; - const top = canvas.getHeight() * rectangle.y1; - const right = canvas.getWidth() * rectangle.x2; - const bottom = canvas.getHeight() * rectangle.y2; - const width = right - left; - const height = bottom - top; - return new fabric.Rect({ - left: left, - top: top, - width: width, - height: height, - fill: color, - opacity: opacity, - data: coor.id, - strokeDashArray: strokeDashArray, - stroke: strokeColor, - strokeWidth: strokeWidth, - }); } - handleMultiSelect(): void { - const { canvas } = this.state; + + + function handleDiscardActiveObject(): void { if (!canvas) { return; } canvas.discardActiveObject(); - const sel = new fabric.ActiveSelection(canvas.getObjects(), { - canvas: canvas, - }); - canvas.setActiveObject(sel); canvas.requestRenderAll(); } - handleDiscardActiveObject(): void { - const { canvas } = this.state; + function handleKeyPress(event: React.KeyboardEvent): void { + if (event.key === "Delete") { + // Handle Delete + handleDeleteShape(); + } + } + + function changeImage(): void { + const { record } = props; + fabric.Image.fromURL(record.image, loadImage); + } + + function loadImage(img: fabric.Image): void { if (!canvas) { return; } - canvas.discardActiveObject(); - canvas.requestRenderAll(); + canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), { + scaleX: canvas.getWidth() / (img.width || 1), + scaleY: canvas.getHeight() / (img.height || 1), + }); + if (initial) { + setInitial(false); + initialObjects(); + } } - handleKeyPress(event: React.KeyboardEvent): void { - if (event.key === "Delete") { - // Handle Delete - this.handleDeleteShape(); + function initialObjects(): void { + if (!canvas) { + return; } + const { record } = props; + //const setOutput = this.setOutput.bind(this); + //const setStateOf = this.setState.bind(this); + const inputObject = record.clippings; + //const createObject = this.createObject.bind(this); + if (inputObject !== undefined) { + inputObject.forEach(function (coord: any) { + const rect = createObject(canvas, coord); + canvas.add(rect); + }); + } + canvas.renderAll(); + //setCanvas(canvas); + //setStateOf({ canvas }, setOutput); } - render(): JSX.Element { - const { - input: { value, name }, - ...otherProps - } = this.props; + function initialImage(): void { + const { record } = props; + fabric.Image.fromURL(record.image, loadImage); + } - return ( -
-

{name}

+ function initialCanvas(): void { + let newCanvas = new fabric.Canvas(props.id || "canvas"); + newCanvas.uniScaleTransform = true; + newCanvas.on("mouse:dblclick", doubleClickEvent); + newCanvas.on("object:modified", setOutput); + setCanvas(newCanvas); + initialImage(); + } + + useEffect(() => { + initialCanvas(); + }, []); + + return ( +
+

{name}

+ + + + - - - - - - - - - - - - + + + - - - + + + - - -
- ); - } + + +
+ ); + } + +ReactMultiCrop.defaultProps = defaultProps; + +export default ReactMultiCrop; \ No newline at end of file diff --git a/src/ReactMultiCrop/ReactMultiCrop.types.ts b/src/ReactMultiCrop/ReactMultiCrop.types.ts index 6e8c966..2360c2a 100644 --- a/src/ReactMultiCrop/ReactMultiCrop.types.ts +++ b/src/ReactMultiCrop/ReactMultiCrop.types.ts @@ -1,15 +1,11 @@ -export type ReactMultiCropProps = { - id: string; +import { InputProps } from "react-admin"; + +export interface ReactMultiCropProps extends InputProps { + id?: string; color?: string; opacity?: number; strokeColor?: string; strokeDashArray?: Array; strokeWidth?: number; record?: any; - input?: any; -}; - -export type ReactMultiCropStates = { - canvas: fabric.Canvas | null; - initial: boolean; }; diff --git a/src/ReactMultiCrop/ReactMultiCropForm.tsx b/src/ReactMultiCrop/ReactMultiCropForm.tsx new file mode 100644 index 0000000..e76c102 --- /dev/null +++ b/src/ReactMultiCrop/ReactMultiCropForm.tsx @@ -0,0 +1,29 @@ +// in src/App.js +import * as React from "react"; +import { Admin, Resource, Create, SimpleForm, ImageInput, List, Datagrid, TextField } from 'react-admin'; +import simpleRestProvider from 'ra-data-simple-rest'; +import ReactMultiCrop from './ReactMultiCrop'; + +const CreateForm = (props: any) => ( + + + + + + +); + +const ListPost = (props: any) => ( + + + + + +); + +const dataProvider = simpleRestProvider('https://jsonplaceholder.typicode.com'); +const App = () => + +; + +export default App; diff --git a/yarn.lock b/yarn.lock index c5a04c3..971d410 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1175,7 +1175,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.12.1" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740" integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA== @@ -1511,6 +1511,15 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" +"@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^13.0.0" + "@jest/types@^25.5.0": version "25.5.0" resolved "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" @@ -1532,7 +1541,7 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@material-ui/core@^4.11.0": +"@material-ui/core@^4.11.0", "@material-ui/core@^4.3.3": version "4.11.0" resolved "https://registry.npmjs.org/@material-ui/core/-/core-4.11.0.tgz#b69b26e4553c9e53f2bfaf1053e216a0af9be15a" integrity sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g== @@ -1550,7 +1559,14 @@ react-is "^16.8.0" react-transition-group "^4.4.0" -"@material-ui/styles@^4.10.0": +"@material-ui/icons@^4.2.1": + version "4.9.1" + resolved "https://registry.npmjs.org/@material-ui/icons/-/icons-4.9.1.tgz#fdeadf8cb3d89208945b33dbc50c7c616d0bd665" + integrity sha512-GBitL3oBWO0hzBhvA9KxqcowRUsA0qzwKkURyC8nppnC3fw54KPKZ+d4V1Eeg/UnDRSzDaI9nGCdel/eh9AQMg== + dependencies: + "@babel/runtime" "^7.4.4" + +"@material-ui/styles@^4.10.0", "@material-ui/styles@^4.3.3": version "4.10.0" resolved "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz#2406dc23aa358217aa8cc772e6237bd7f0544071" integrity sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q== @@ -1626,6 +1642,50 @@ prop-types "^15.6.1" react-lifecycles-compat "^3.0.4" +"@redux-saga/core@^1.1.3": + version "1.1.3" + resolved "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz#3085097b57a4ea8db5528d58673f20ce0950f6a4" + integrity sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg== + dependencies: + "@babel/runtime" "^7.6.3" + "@redux-saga/deferred" "^1.1.2" + "@redux-saga/delay-p" "^1.1.2" + "@redux-saga/is" "^1.1.2" + "@redux-saga/symbols" "^1.1.2" + "@redux-saga/types" "^1.1.0" + redux "^4.0.4" + typescript-tuple "^2.2.1" + +"@redux-saga/deferred@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.1.2.tgz#59937a0eba71fff289f1310233bc518117a71888" + integrity sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ== + +"@redux-saga/delay-p@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.1.2.tgz#8f515f4b009b05b02a37a7c3d0ca9ddc157bb355" + integrity sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g== + dependencies: + "@redux-saga/symbols" "^1.1.2" + +"@redux-saga/is@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.2.tgz#ae6c8421f58fcba80faf7cadb7d65b303b97e58e" + integrity sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w== + dependencies: + "@redux-saga/symbols" "^1.1.2" + "@redux-saga/types" "^1.1.0" + +"@redux-saga/symbols@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.2.tgz#216a672a487fc256872b8034835afc22a2d0595d" + integrity sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ== + +"@redux-saga/types@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@redux-saga/types/-/types-1.1.0.tgz#0e81ce56b4883b4b2a3001ebe1ab298b84237204" + integrity sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg== + "@rollup/plugin-commonjs@^15.1.0": version "15.1.0" resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.1.0.tgz#1e7d076c4f1b2abf7e65248570e555defc37c238" @@ -1660,6 +1720,11 @@ estree-walker "^1.0.1" picomatch "^2.2.2" +"@sheerun/mutationobserver-shim@^0.3.2": + version "0.3.3" + resolved "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25" + integrity sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw== + "@sinonjs/commons@^1.7.0": version "1.8.1" resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" @@ -2128,6 +2193,17 @@ "@svgr/plugin-svgo" "^5.4.0" loader-utils "^2.0.0" +"@testing-library/dom@^5.6.1": + version "5.6.1" + resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-5.6.1.tgz#705a1cb4a039b877c1e69e916824038e837ab637" + integrity sha512-Y1T2bjtvQMewffn1CJ28kpgnuvPYKsBcZMagEH0ppfEMZPDc8AkkEnTk4smrGZKw0cblNB3lhM2FMnpfLExlHg== + dependencies: + "@babel/runtime" "^7.5.5" + "@sheerun/mutationobserver-shim" "^0.3.2" + aria-query "3.0.0" + pretty-format "^24.8.0" + wait-for-expect "^1.2.0" + "@testing-library/dom@^7.26.0": version "7.26.0" resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-7.26.0.tgz#da4d052dc426a4ccc916303369c6e7552126f680" @@ -2164,6 +2240,14 @@ "@babel/runtime" "^7.11.2" "@testing-library/dom" "^7.26.0" +"@testing-library/react@^8.0.7": + version "8.0.9" + resolved "https://registry.npmjs.org/@testing-library/react/-/react-8.0.9.tgz#1ecd96bc3471b06dd2f9763b6e53a7ace28a54a2" + integrity sha512-I7zd+MW5wk8rQA5VopZgBfxGKUd91jgZ6Vzj2gMqFf2iGGtKwvI5SVTrIJcSFaOXK88T2EUsbsIKugDtoqOcZQ== + dependencies: + "@babel/runtime" "^7.5.5" + "@testing-library/dom" "^5.6.1" + "@types/anymatch@*": version "1.3.1" resolved "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" @@ -2426,6 +2510,14 @@ dependencies: "@types/react" "*" +"@types/redux-form@^8.3.0": + version "8.3.0" + resolved "https://registry.npmjs.org/@types/redux-form/-/redux-form-8.3.0.tgz#d253e0078a4940187b946459e0bb4d6a355018b1" + integrity sha512-LUOpffXkPpY7n9pQvaAy9TifMgQFVqQF0LmJLLiZGWpDmDmvgEbNbQ6h2tSJ7CVNIVo45wPPVdWw5Mi91ZPvfQ== + dependencies: + "@types/react" "*" + redux "^3.6.0 || ^4.0.0" + "@types/resolve@1.17.1": version "1.17.1" resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" @@ -2493,6 +2585,13 @@ resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== +"@types/yargs@^13.0.0": + version "13.0.11" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.11.tgz#def2f0c93e4bdf2c61d7e34899b17e34be28d3b1" + integrity sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ== + dependencies: + "@types/yargs-parser" "*" + "@types/yargs@^15.0.0": version "15.0.9" resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.9.tgz#524cd7998fe810cdb02f26101b699cccd156ff19" @@ -2811,7 +2910,7 @@ ansi-regex@^3.0.0: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= -ansi-regex@^4.1.0: +ansi-regex@^4.0.0, ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== @@ -2826,7 +2925,7 @@ ansi-styles@^2.2.1: resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -2888,6 +2987,14 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +aria-query@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" + integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= + dependencies: + ast-types-flow "0.0.7" + commander "^2.11.0" + aria-query@^4.2.2: version "4.2.2" resolved "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" @@ -3014,6 +3121,11 @@ assign-symbols@^1.0.0: resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +ast-types-flow@0.0.7: + version "0.0.7" + resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + ast-types@^0.13.2: version "0.13.4" resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" @@ -3053,6 +3165,11 @@ atob@^2.1.2: resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +attr-accept@^2.0.0: + version "2.2.2" + resolved "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" + integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== + autoprefixer@^9.7.2: version "9.8.6" resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" @@ -3066,6 +3183,13 @@ autoprefixer@^9.7.2: postcss "^7.0.32" postcss-value-parser "^4.1.0" +autosuggest-highlight@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/autosuggest-highlight/-/autosuggest-highlight-3.1.1.tgz#70bb4f9125fe8a849e85f825f7bb2a1a4806743d" + integrity sha512-MQ6GNIGMMZbeA5FlBLXXgkZEthysCdYNkMV4MahB2/qB/9cwBnVsePUPnIqkMuzjzclTtDa67xln7cgLDu2f/g== + dependencies: + diacritic "0.0.2" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -3993,7 +4117,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@^2.2.5: +classnames@^2.2.5, classnames@~2.2.5: version "2.2.6" resolved "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== @@ -4154,7 +4278,7 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== -commander@^2.19.0, commander@^2.20.0: +commander@^2.11.0, commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -4179,6 +4303,11 @@ component-emitter@^1.2.1: resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +compute-scroll-into-view@^1.0.9: + version "1.0.16" + resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz#5b7bf4f7127ea2c19b750353d7ce6776a90ee088" + integrity sha512-a85LHKY81oQnikatZYA90pufpZ6sQx++BoCxOEMsjpZx+ZnaKGQnCyCehTRr/1p9GBIAHTjcU9k71kSYWloLiQ== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -4194,6 +4323,13 @@ concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" +connected-react-router@^6.5.2: + version "6.8.0" + resolved "https://registry.npmjs.org/connected-react-router/-/connected-react-router-6.8.0.tgz#ddc687b31d498322445d235d660798489fa56cae" + integrity sha512-E64/6krdJM3Ag3MMmh2nKPtMbH15s3JQDuaYJvOVXzu6MbHbDyIvuwLOyhQIuP4Om9zqEfZYiVyflROibSsONg== + dependencies: + prop-types "^15.7.2" + console-browserify@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" @@ -4417,6 +4553,11 @@ css-loader@^3.5.3: schema-utils "^2.7.0" semver "^6.3.0" +css-mediaquery@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" + integrity sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA= + css-select-base-adapter@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" @@ -4567,6 +4708,11 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +date-fns@^1.29.0: + version "1.30.1" + resolved "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" + integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== + debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -4735,6 +4881,11 @@ detect-port@^1.3.0: address "^1.0.1" debug "^2.6.0" +diacritic@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/diacritic/-/diacritic-0.0.2.tgz#fc2a887b5a5bc0a0a854fb614c7c2f209061ee04" + integrity sha1-/CqIe1pbwKCoVPthTHwvIJBh7gQ= + diff-sequences@^25.2.6: version "25.2.6" resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" @@ -4891,6 +5042,16 @@ dotenv@^8.0.0: resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== +downshift@3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/downshift/-/downshift-3.2.7.tgz#0c40d78d1cbc24753c7a622cfc664df1c9480b4a" + integrity sha512-mbUO9ZFhMGtksIeVWRFFjNOPN237VsUqZSEYi0VS0Wj38XNLzpgOBTUcUjdjFeB8KVgmrcRa6GGFkTbACpG6FA== + dependencies: + "@babel/runtime" "^7.1.2" + compute-scroll-into-view "^1.0.9" + prop-types "^15.6.0" + react-is "^16.5.2" + duplexer@^0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" @@ -5219,6 +5380,11 @@ etag@~1.8.1: resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +eventemitter3@^3.0.0: + version "3.1.2" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + events@^3.0.0: version "3.2.0" resolved "https://registry.npmjs.org/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" @@ -5465,6 +5631,13 @@ file-loader@^6.0.0: loader-utils "^2.0.0" schema-utils "^3.0.0" +file-selector@^0.1.12: + version "0.1.13" + resolved "https://registry.npmjs.org/file-selector/-/file-selector-0.1.13.tgz#5efd977ca2bca1700992df1b10e254f4e73d2df4" + integrity sha512-T2efCBY6Ps+jLIWdNQsmzt/UnAjKOEAlsZVdnQztg/BtAZGNL4uX1Jet9cMM8gify/x4CSudreji2HssGBNVIQ== + dependencies: + tslib "^2.0.1" + file-system-cache@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/file-system-cache/-/file-system-cache-1.0.5.tgz#84259b36a2bbb8d3d6eb1021d3132ffe64cfff4f" @@ -5508,6 +5681,18 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +final-form-arrays@^3.0.1: + version "3.0.2" + resolved "https://registry.npmjs.org/final-form-arrays/-/final-form-arrays-3.0.2.tgz#9f3bef778dec61432357744eb6f3abef7e7f3847" + integrity sha512-TfO8aZNz3RrsZCDx8GHMQcyztDNpGxSSi9w4wpSNKlmv2PfFWVVM8P7Yj5tj4n0OWax+x5YwTLhT5BnqSlCi+w== + +final-form@^4.18.5: + version "4.20.1" + resolved "https://registry.npmjs.org/final-form/-/final-form-4.20.1.tgz#525a7f7f27f55c28d8994b157b24d6104fc560e9" + integrity sha512-IIsOK3JRxJrN72OBj7vFWZxtGt3xc1bYwJVPchjVWmDol9DlzMSAOPB+vwe75TUYsw1JaH0fTQnIgwSQZQ9Acg== + dependencies: + "@babel/runtime" "^7.10.0" + finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -5567,6 +5752,13 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + for-in@^0.1.3: version "0.1.8" resolved "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -6073,6 +6265,18 @@ highlight.js@~9.15.0, highlight.js@~9.15.1: resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2" integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw== +history@^4.9.0: + version "4.10.1" + resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -6082,7 +6286,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6310,6 +6514,11 @@ infer-owner@^1.0.3, infer-owner@^1.0.4: resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== +inflection@~1.12.0: + version "1.12.0" + resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY= + inflight@^1.0.4: version "1.0.6" resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -6473,7 +6682,7 @@ is-buffer@^1.0.2, is-buffer@^1.1.5: resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4, is-callable@^1.2.2: +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== @@ -6724,6 +6933,11 @@ is-wsl@^2.1.1, is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -7347,6 +7561,11 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +jsonexport@^2.4.1: + version "2.5.2" + resolved "https://registry.npmjs.org/jsonexport/-/jsonexport-2.5.2.tgz#fafbcdb2cb8e12d0a2a92cda6e0634c8d48005ac" + integrity sha512-4joNLCxxUAmS22GN3GA5os/MYFnq8oqXOKvoCymmcT0MPz/QPZ5eA+Fh5sIPxUji45RKq8DdQ1yoKq91p4E9VA== + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -7596,7 +7815,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19: +lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.5: version "4.17.20" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -7616,7 +7835,7 @@ loglevelnext@^1.0.1: es6-symbol "^3.1.1" object.assign "^4.1.0" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -7881,6 +8100,14 @@ min-indent@^1.0.0: resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== +mini-create-react-context@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040" + integrity sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA== + dependencies: + "@babel/runtime" "^7.5.5" + tiny-warning "^1.0.3" + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -8157,6 +8384,16 @@ node-notifier@^8.0.0: uuid "^8.3.0" which "^2.0.2" +node-polyglot@^2.2.2: + version "2.4.0" + resolved "https://registry.npmjs.org/node-polyglot/-/node-polyglot-2.4.0.tgz#0d2717ed06640d9ff48a2aebe8d13e39ef03518f" + integrity sha512-KRzKwzMWm3wSAjOSop7/WwNyzaMkCe9ddkwXTQsIZEJmvEnqy/bCqLpAVw6xBszKfy4iLdYVA0d83L+cIkYPbA== + dependencies: + for-each "^0.3.3" + has "^1.0.3" + string.prototype.trim "^1.1.2" + warning "^4.0.3" + node-pre-gyp@^0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" @@ -8645,6 +8882,13 @@ path-to-regexp@0.1.7: resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + path-type@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -8850,6 +9094,16 @@ pretty-error@^2.1.1: renderkid "^2.0.1" utila "~0.4" +pretty-format@^24.8.0: + version "24.9.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== + dependencies: + "@jest/types" "^24.9.0" + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + react-is "^16.8.4" + pretty-format@^25.2.1, pretty-format@^25.5.0: version "25.5.0" resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" @@ -8932,7 +9186,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.4" -prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -9038,6 +9292,15 @@ qs@~6.5.2: resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +query-string@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -9048,6 +9311,61 @@ querystring@0.2.0, querystring@^0.2.0: resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= +ra-core@^3.9.4: + version "3.9.4" + resolved "https://registry.npmjs.org/ra-core/-/ra-core-3.9.4.tgz#9151e1f4948e06ed2bbc5efdda207b28ac7f9281" + integrity sha512-nDVoOOGzyQ0WCo+tyI0qRO6iQv+ExkAapGfM4Jc/+ARvzmktuRomkrWdBCx5msIxH6w17/n+s6J1OtscohR15w== + dependencies: + "@testing-library/react" "^8.0.7" + classnames "~2.2.5" + date-fns "^1.29.0" + eventemitter3 "^3.0.0" + inflection "~1.12.0" + lodash "~4.17.5" + prop-types "^15.6.1" + query-string "^5.1.1" + reselect "~3.0.0" + +ra-data-simple-rest@^3.9.3: + version "3.9.3" + resolved "https://registry.npmjs.org/ra-data-simple-rest/-/ra-data-simple-rest-3.9.3.tgz#b81d9cff2d5dd2a50519d2a74dbc5ba2cc7c9799" + integrity sha512-oFVwE1dcCJF7oo4/9VrZg2Kk7N30KW5dKFRENNvqLYEx0RlIpa8q2cST7ivKqdAWzYdKA/dH1h2vDX0v9t1ZDA== + dependencies: + query-string "^5.1.1" + +ra-i18n-polyglot@^3.9.4: + version "3.9.4" + resolved "https://registry.npmjs.org/ra-i18n-polyglot/-/ra-i18n-polyglot-3.9.4.tgz#5c66609e841acc72aa96417931b48fbe9ae23aed" + integrity sha512-2lTDFVvzqnZo/gZXmng2y+NCgcm6hY3W4Sk8zBRP9MwausSi7g3M3E9jepZG4FBZaJYdfKaSrdJjBQesnB5ajg== + dependencies: + node-polyglot "^2.2.2" + ra-core "^3.9.4" + +ra-language-english@^3.9.4: + version "3.9.4" + resolved "https://registry.npmjs.org/ra-language-english/-/ra-language-english-3.9.4.tgz#0b76e663cfceee5af277b1c49f5a36c865017a21" + integrity sha512-D+HJhvLM60LMKCCghslgcks5hpzcoIbD/sfuG0J2VlOiZMl/TcYtFefpETC/9t0cf9lxuApRCDL5YtSaUoA/CQ== + dependencies: + ra-core "^3.9.4" + +ra-ui-materialui@^3.9.4: + version "3.9.4" + resolved "https://registry.npmjs.org/ra-ui-materialui/-/ra-ui-materialui-3.9.4.tgz#c68958492aa25790198d7101117178b034c97da3" + integrity sha512-qx6TcVFwVkqqp9tB4tulgVMH2zhpzJTcTvYZlsIEa17jlBNLM9l1iR7LcVbKZDafKacWD14G6+g9R+y/46qDjg== + dependencies: + autosuggest-highlight "^3.1.1" + classnames "~2.2.5" + connected-react-router "^6.5.2" + css-mediaquery "^0.1.2" + downshift "3.2.7" + inflection "~1.12.0" + jsonexport "^2.4.1" + lodash "~4.17.5" + prop-types "^15.7.0" + query-string "^5.1.1" + react-dropzone "^10.1.7" + react-transition-group "^4.4.1" + ramda@^0.21.0: version "0.21.0" resolved "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" @@ -9101,6 +9419,29 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-admin@^3.9.4: + version "3.9.4" + resolved "https://registry.npmjs.org/react-admin/-/react-admin-3.9.4.tgz#3738ef8ca7fa68140f0555f177aec2d6f0d12151" + integrity sha512-IoORnrjFSwC2I1bM364JgUbg0Moeb8EImuPwKFiNLXWsOTuhsCTLzZW76+7zb+QS5XCvRosGLrkv8mgrXY/HUw== + dependencies: + "@material-ui/core" "^4.3.3" + "@material-ui/icons" "^4.2.1" + "@material-ui/styles" "^4.3.3" + connected-react-router "^6.5.2" + final-form "^4.18.5" + final-form-arrays "^3.0.1" + ra-core "^3.9.4" + ra-i18n-polyglot "^3.9.4" + ra-language-english "^3.9.4" + ra-ui-materialui "^3.9.4" + react-final-form "^6.3.3" + react-final-form-arrays "^3.1.1" + react-redux "^7.1.0" + react-router "^5.1.0" + react-router-dom "^5.1.0" + redux "^3.7.2 || ^4.0.3" + redux-saga "^1.0.0" + react-color@^2.17.0: version "2.18.1" resolved "https://registry.npmjs.org/react-color/-/react-color-2.18.1.tgz#2cda8cc8e06a9e2c52ad391a30ddad31972472f4" @@ -9201,6 +9542,15 @@ react-draggable@^4.0.3: classnames "^2.2.5" prop-types "^15.6.0" +react-dropzone@^10.1.7: + version "10.2.2" + resolved "https://registry.npmjs.org/react-dropzone/-/react-dropzone-10.2.2.tgz#67b4db7459589a42c3b891a82eaf9ade7650b815" + integrity sha512-U5EKckXVt6IrEyhMMsgmHQiWTGLudhajPPG77KFSvgsMqNEHSyGpqWvOMc5+DhEah/vH4E1n+J5weBNLd5VtyA== + dependencies: + attr-accept "^2.0.0" + file-selector "^0.1.12" + prop-types "^15.7.2" + react-error-overlay@^6.0.7: version "6.0.7" resolved "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" @@ -9211,6 +9561,20 @@ react-fast-compare@^3.2.0: resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== +react-final-form-arrays@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/react-final-form-arrays/-/react-final-form-arrays-3.1.2.tgz#391ceee29d866f2128c807b510c6a17ff4dc72cc" + integrity sha512-ds1FUS8s3AnfbvfmBTPnjijS7veKBr6DrWOGQzDI7grE4OosVWOREwd2ZUkz3HPB3wXQcNWsqyDuQDBSMGUr2g== + dependencies: + "@babel/runtime" "^7.4.5" + +react-final-form@^6.3.3: + version "6.5.1" + resolved "https://registry.npmjs.org/react-final-form/-/react-final-form-6.5.1.tgz#baf798129d459c669cfda5ce60a77801ef52badc" + integrity sha512-+Hzd9PqYY1Cv3MnWzw64QOl5BjC5BtSDakx+N7Re49r0FASdFhgpXLFFCJ31fvegq2euP6hz6Ow9K6XM9BSqCA== + dependencies: + "@babel/runtime" "^7.10.0" + react-helmet-async@^1.0.2: version "1.0.7" resolved "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.0.7.tgz#b988fbc3abdc4b704982bb74b9cb4a08fcf062c1" @@ -9229,7 +9593,7 @@ react-hotkeys@2.0.0: dependencies: prop-types "^15.6.1" -react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1: +react-is@^16.12.0, react-is@^16.5.2, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -9260,6 +9624,46 @@ react-popper@^1.3.7: typed-styles "^0.0.7" warning "^4.0.2" +react-redux@^7.1.0: + version "7.2.1" + resolved "https://registry.npmjs.org/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985" + integrity sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg== + dependencies: + "@babel/runtime" "^7.5.5" + hoist-non-react-statics "^3.3.0" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.9.0" + +react-router-dom@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" + integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.0, react-router@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" + integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + react-sizeme@^2.6.7: version "2.6.12" resolved "https://registry.npmjs.org/react-sizeme/-/react-sizeme-2.6.12.tgz#ed207be5476f4a85bf364e92042520499455453e" @@ -9290,7 +9694,7 @@ react-textarea-autosize@^8.1.1: use-composed-ref "^1.0.0" use-latest "^1.0.0" -react-transition-group@^4.4.0: +react-transition-group@^4.4.0, react-transition-group@^4.4.1: version "4.4.1" resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw== @@ -9395,6 +9799,21 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redux-saga@^1.0.0: + version "1.1.3" + resolved "https://registry.npmjs.org/redux-saga/-/redux-saga-1.1.3.tgz#9f3e6aebd3c994bbc0f6901a625f9a42b51d1112" + integrity sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw== + dependencies: + "@redux-saga/core" "^1.1.3" + +"redux@^3.6.0 || ^4.0.0", "redux@^3.7.2 || ^4.0.3", redux@^4.0.4: + version "4.0.5" + resolved "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" + integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + refractor@^2.4.1: version "2.10.1" resolved "https://registry.npmjs.org/refractor/-/refractor-2.10.1.tgz#166c32f114ed16fd96190ad21d5193d3afc7d34e" @@ -9551,6 +9970,11 @@ require-main-filename@^2.0.0: resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +reselect@~3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" + integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -9573,6 +9997,11 @@ resolve-from@^5.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -10194,6 +10623,11 @@ stream-shift@^1.0.0: resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + string-length@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" @@ -10265,6 +10699,14 @@ string.prototype.padstart@^3.0.0: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" +string.prototype.trim@^1.1.2: + version "1.2.2" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.2.tgz#f538d0bacd98fc4297f0bef645226d5aaebf59f3" + integrity sha512-b5yrbl3BXIjHau9Prk7U0RRYcUYdN4wGSVaqoBQS50CCE3KBuYU0TYRNPFCP7aVoNMX87HKThdMRVIP3giclKg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.18.0-next.0" + string.prototype.trimend@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" @@ -10416,6 +10858,11 @@ svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-tree@^3.2.2, symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -10574,7 +11021,12 @@ tiny-emitter@^2.0.0: resolved "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== -tiny-warning@^1.0.2: +tiny-invariant@^1.0.2: + version "1.1.0" + resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" + integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== + +tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== @@ -10805,6 +11257,25 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript-compare@^0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz#7ee40a400a406c2ea0a7e551efd3309021d5f425" + integrity sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA== + dependencies: + typescript-logic "^0.0.0" + +typescript-logic@^0.0.0: + version "0.0.0" + resolved "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz#66ebd82a2548f2b444a43667bec120b496890196" + integrity sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q== + +typescript-tuple@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz#7d9813fb4b355f69ac55032e0363e8bb0f04dad2" + integrity sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q== + dependencies: + typescript-compare "^0.0.2" + typescript@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz#153bbd468ef07725c1df9c77e8b453f8d36abba5" @@ -11027,6 +11498,11 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -11069,6 +11545,11 @@ w3c-xmlserializer@^2.0.0: dependencies: xml-name-validator "^3.0.0" +wait-for-expect@^1.2.0: + version "1.3.0" + resolved "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-1.3.0.tgz#65241ce355425f907f5d127bdb5e72c412ff830c" + integrity sha512-8fJU7jiA96HfGPt+P/UilelSAZfhMBJ52YhKzlmZQvKEZU2EcD1GQ0yqGB6liLdHjYtYAoGVigYwdxr5rktvzA== + walker@^1.0.7, walker@~1.0.5: version "1.0.7" resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" From cf7c6d7f09b3bfb668faac93854e0b2435fd5f2f Mon Sep 17 00:00:00 2001 From: Bervianto Leo Pratama Date: Sun, 18 Oct 2020 16:13:13 +0700 Subject: [PATCH 2/4] Add react-admin peerDependencies --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d4ce50e..c825cbe 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "peerDependencies": { "@material-ui/core": ">=4.2.1", "fabric": ">=4.0", - "react": "^16.9.0" + "react": "^16.9.0", + "react-admin": ">=3.9.0" }, "devDependencies": { "@babel/core": "^7.12.3", @@ -64,4 +65,4 @@ "ts-jest": "^26.4.1", "typescript": "^4.0.3" } -} +} \ No newline at end of file From 03184d0b42bc4e324548a5741e6e36e8ead40923 Mon Sep 17 00:00:00 2001 From: Bervianto Leo Pratama Date: Sun, 18 Oct 2020 17:09:58 +0700 Subject: [PATCH 3/4] Update test, need to convert the test --- package.json | 3 +- src/ReactMultiCrop/ReactMultiCrop.test.tsx | 41 +++------------------- yarn.lock | 10 +----- 3 files changed, 7 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index c825cbe..d45a1a4 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "@types/jest": "^26.0.14", "@types/react": "^16.9.53", "@types/react-dom": "^16.9.8", - "@types/redux-form": "^8.3.0", "babel-loader": "^8.1.0", "babel-preset-react-app": "^9.1.2", "cross-env": "^7.0.2", @@ -65,4 +64,4 @@ "ts-jest": "^26.4.1", "typescript": "^4.0.3" } -} \ No newline at end of file +} diff --git a/src/ReactMultiCrop/ReactMultiCrop.test.tsx b/src/ReactMultiCrop/ReactMultiCrop.test.tsx index dc8b9f1..677b936 100644 --- a/src/ReactMultiCrop/ReactMultiCrop.test.tsx +++ b/src/ReactMultiCrop/ReactMultiCrop.test.tsx @@ -1,45 +1,14 @@ import React from "react"; import { render } from "@testing-library/react"; -import ReactMultiCrop from "./ReactMultiCrop"; -import { ReactMultiCropProps } from "./ReactMultiCrop.types"; +import ReactMultiCropForm from "./ReactMultiCropForm"; describe("Test Component", () => { - let props: ReactMultiCropProps; - beforeEach(() => { - props = { - id: "canvas", - color: "red", - strokeColor: "white", - opacity: 0.8, - strokeDashArray: [5, 5], - strokeWidth: 5, - record: [], - input: { - value: "", - name: "react", - onChange: function () {}, - }, - }; - }); - - const renderComponent = () => render(); - - it("should have primary className with default props", () => { - const { getByTestId } = renderComponent(); - - const testComponent = getByTestId("canvas-wrapper"); - - expect(testComponent).toBeTruthy(); - }); - - it("should have secondary className with theme set as secondary", () => { - props.id = "new-canvas"; - const { getByTestId } = renderComponent(); - - const testComponent = getByTestId("canvas-wrapper"); + const renderComponent = () => render(); - expect(testComponent).toBeTruthy(); + it("it should render correctly", () => { + const component = renderComponent(); + expect(component).toBeTruthy(); }); }); diff --git a/yarn.lock b/yarn.lock index 971d410..b262437 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2510,14 +2510,6 @@ dependencies: "@types/react" "*" -"@types/redux-form@^8.3.0": - version "8.3.0" - resolved "https://registry.npmjs.org/@types/redux-form/-/redux-form-8.3.0.tgz#d253e0078a4940187b946459e0bb4d6a355018b1" - integrity sha512-LUOpffXkPpY7n9pQvaAy9TifMgQFVqQF0LmJLLiZGWpDmDmvgEbNbQ6h2tSJ7CVNIVo45wPPVdWw5Mi91ZPvfQ== - dependencies: - "@types/react" "*" - redux "^3.6.0 || ^4.0.0" - "@types/resolve@1.17.1": version "1.17.1" resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" @@ -9806,7 +9798,7 @@ redux-saga@^1.0.0: dependencies: "@redux-saga/core" "^1.1.3" -"redux@^3.6.0 || ^4.0.0", "redux@^3.7.2 || ^4.0.3", redux@^4.0.4: +"redux@^3.7.2 || ^4.0.3", redux@^4.0.4: version "4.0.5" resolved "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== From 35e924560f6dfdf98fea5056f1fc98a745e35836 Mon Sep 17 00:00:00 2001 From: Bervianto Leo Pratama Date: Sun, 18 Oct 2020 22:50:39 +0700 Subject: [PATCH 4/4] Change to functional callback Still need to find the infinite loop --- .github/workflows/node.js.yml | 35 +- .prettierignore | 4 +- .prettierrc.json | 10 +- .storybook/main.js | 10 +- README.md | 8 +- src/ReactMultiCrop/ReactMultiCrop.stories.tsx | 2 +- src/ReactMultiCrop/ReactMultiCrop.test.tsx | 1 - src/ReactMultiCrop/ReactMultiCrop.tsx | 373 +++++++++--------- src/ReactMultiCrop/ReactMultiCrop.types.ts | 2 +- src/ReactMultiCrop/ReactMultiCropForm.tsx | 25 +- 10 files changed, 251 insertions(+), 219 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 802ebb6..ead95ee 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -5,13 +5,12 @@ name: Node.js CI on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] jobs: build: - runs-on: ubuntu-latest strategy: @@ -19,18 +18,18 @@ jobs: node-version: [12.x, 14.x] steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - run: yarn - - run: yarn build - - run: yarn test - - run: yarn storybook:export - - name: Deploy - if: ${{ github.event_name == 'push' && matrix.node-version == '12.x' }} - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./storybook-static + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: yarn + - run: yarn build + - run: yarn test + - run: yarn storybook:export + - name: Deploy + if: ${{ github.event_name == 'push' && matrix.node-version == '12.x' }} + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./storybook-static diff --git a/.prettierignore b/.prettierignore index d595cc5..1aa8210 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,4 @@ lib -coverage \ No newline at end of file +coverage +build +storybook-static \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json index f0eb61e..0eb1ddc 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -2,5 +2,13 @@ "trailingComma": "es5", "tabWidth": 2, "semi": true, - "singleQuote": false + "singleQuote": false, + "overrides": [ + { + "files": ["*.html", "*.md"], + "options": { + "tabWidth": 4 + } + } + ] } diff --git a/.storybook/main.js b/.storybook/main.js index db67968..fd1e452 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -8,18 +8,18 @@ module.exports = { config.module.rules.push({ test: /\.scss$/, use: ["style-loader", "css-loader", "sass-loader"], - include: path.resolve(__dirname, "../") + include: path.resolve(__dirname, "../"), }); config.module.rules.push({ test: /\.(ts|tsx)$/, loader: require.resolve("babel-loader"), options: { - presets: [["react-app", { flow: false, typescript: true }]] - } + presets: [["react-app", { flow: false, typescript: true }]], + }, }); config.resolve.extensions.push(".ts", ".tsx"); return config; - } -}; \ No newline at end of file + }, +}; diff --git a/README.md b/README.md index b6a66b6..1b83496 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ ReactMultiCrop Used Fabric.js and Integrated with react-admin. Designed for [rea ## Prerequisted and Dependecies -- Please read how to install fabric.js: +- Please read how to install fabric.js: https://www.npmjs.com/package/fabric -- Dependencies: - - Material UI - - fabric.js +- Dependencies: + - Material UI + - fabric.js ## How to Install diff --git a/src/ReactMultiCrop/ReactMultiCrop.stories.tsx b/src/ReactMultiCrop/ReactMultiCrop.stories.tsx index 05cd962..55f39c1 100644 --- a/src/ReactMultiCrop/ReactMultiCrop.stories.tsx +++ b/src/ReactMultiCrop/ReactMultiCrop.stories.tsx @@ -2,7 +2,7 @@ import React from "react"; import ReactMultiCropForm from "./ReactMultiCropForm"; export default { - title: "ReactMultiCrop" + title: "ReactMultiCrop", }; export const Canvas = () => ; diff --git a/src/ReactMultiCrop/ReactMultiCrop.test.tsx b/src/ReactMultiCrop/ReactMultiCrop.test.tsx index 677b936..0bad14e 100644 --- a/src/ReactMultiCrop/ReactMultiCrop.test.tsx +++ b/src/ReactMultiCrop/ReactMultiCrop.test.tsx @@ -4,7 +4,6 @@ import { render } from "@testing-library/react"; import ReactMultiCropForm from "./ReactMultiCropForm"; describe("Test Component", () => { - const renderComponent = () => render(); it("it should render correctly", () => { diff --git a/src/ReactMultiCrop/ReactMultiCrop.tsx b/src/ReactMultiCrop/ReactMultiCrop.tsx index 9a147b9..3797b3b 100644 --- a/src/ReactMultiCrop/ReactMultiCrop.tsx +++ b/src/ReactMultiCrop/ReactMultiCrop.tsx @@ -1,10 +1,13 @@ -import React, { Component, useState, useEffect } from "react"; +import React, { + useState, + useEffect, + useCallback, + FunctionComponent, +} from "react"; import { fabric } from "fabric"; import { useInput } from "react-admin"; import { Button, Grid } from "@material-ui/core"; -import { - ReactMultiCropProps -} from "./ReactMultiCrop.types"; +import { ReactMultiCropProps } from "./ReactMultiCrop.types"; const defaultProps: ReactMultiCropProps = { id: "canvas", @@ -17,64 +20,74 @@ const defaultProps: ReactMultiCropProps = { record: [], }; - -const ReactMultiCrop: React.FC = (props: ReactMultiCropProps) => { +const ReactMultiCrop: FunctionComponent = ( + props: ReactMultiCropProps +) => { const [canvas, setCanvas] = useState(null); const [initial, setInitial] = useState(true); const { input: { value, name }, + isRequired, ...anotherProp } = useInput(props); - function createObject(canvas: fabric.Canvas, coor: any): fabric.Rect { - const { - color, - opacity, - strokeDashArray, - strokeColor, - strokeWidth, - } = props; - let rectangle; - if (typeof coor.rect === "string") { - rectangle = JSON.parse(coor.rect); - } else { - rectangle = coor.rect; - } - const left = canvas.getWidth() * rectangle.x1; - const top = canvas.getHeight() * rectangle.y1; - const right = canvas.getWidth() * rectangle.x2; - const bottom = canvas.getHeight() * rectangle.y2; - const width = right - left; - const height = bottom - top; + function createObjectByAttribute(attribute: any): fabric.Rect { + const { color, opacity, strokeDashArray, strokeColor, strokeWidth } = props; return new fabric.Rect({ - left: left, - top: top, - width: width, - height: height, + left: attribute.left, + top: attribute.top, + width: attribute.width, + height: attribute.height, fill: color, opacity: opacity, - data: coor.id, + data: null, strokeDashArray: strokeDashArray, stroke: strokeColor, strokeWidth: strokeWidth, }); } - function handleNewShape(): void { - if (!canvas) { - return; - } - const coor: any = {}; - coor.id = null; - coor.rect = { x1: 0, y1: 0, x2: 0.2, y2: 0.2 }; - const rect = createObject(canvas, coor); - rect.lockRotation = true; - canvas.add(rect); - canvas.renderAll(); - setOutput(); - } + const createObject = useCallback( + (coor: any): fabric.Rect | null => { + if (!canvas) { + return null; + } + const { + color, + opacity, + strokeDashArray, + strokeColor, + strokeWidth, + } = props; + let rectangle; + if (typeof coor.rect === "string") { + rectangle = JSON.parse(coor.rect); + } else { + rectangle = coor.rect; + } + const left = canvas.getWidth() * rectangle.x1; + const top = canvas.getHeight() * rectangle.y1; + const right = canvas.getWidth() * rectangle.x2; + const bottom = canvas.getHeight() * rectangle.y2; + const width = right - left; + const height = bottom - top; + return new fabric.Rect({ + left: left, + top: top, + width: width, + height: height, + fill: color, + opacity: opacity, + data: coor.id, + strokeDashArray: strokeDashArray, + stroke: strokeColor, + strokeWidth: strokeWidth, + }); + }, + [canvas] + ); - function handleMultiSelect(): void { + const handleMultiSelect = useCallback(() => { if (!canvas) { return; } @@ -84,95 +97,44 @@ const ReactMultiCrop: React.FC = (props: ReactMultiCropProp }); canvas.setActiveObject(sel); canvas.requestRenderAll(); - } + }, [canvas]); - function doubleClickEvent(options: any): void { - if (options.target) { + const shapetoStructureData = useCallback( + (element: fabric.Object): any => { if (!canvas) { return; } - const left = options.target.left; - const top = options.target.top; - const width = options.target.width; - const height = options.target.height; - const attribute: any = {}; - attribute.left = left + 5; - attribute.top = top + 5; - attribute.width = width * options.target.scaleX; - attribute.height = height * options.target.scaleY; - const rect = createObjectByAttribute(attribute); - rect.lockRotation = true; - canvas.add(rect); - canvas.renderAll(); - setOutput(); - } - } - - function createObjectByAttribute(attribute: any): fabric.Rect { - const { - color, - opacity, - strokeDashArray, - strokeColor, - strokeWidth, - } = props; - return new fabric.Rect({ - left: attribute.left, - top: attribute.top, - width: attribute.width, - height: attribute.height, - fill: color, - opacity: opacity, - data: null, - strokeDashArray: strokeDashArray, - stroke: strokeColor, - strokeWidth: strokeWidth, - }); - } - - function shapetoStructureData(element: fabric.Object): any { - if (!canvas) { - return; - } - const coord: any = {}; - coord.id = element.data; - const left = element.left || 0; - const top = element.top || 0; - const width = element.width || 0; - const height = element.height || 0; - const scaleX = element.scaleX || 0; - const scaleY = element.scaleY || 0; - const x1 = left / canvas.getWidth(); - const y1 = top / canvas.getHeight(); - const x2 = (left + width * scaleX) / canvas.getWidth(); - const y2 = (top + height * scaleY) / canvas.getHeight(); - const rectangle = { x1: x1, y1: y1, x2: x2, y2: y2 }; - coord.rect = JSON.stringify(rectangle); - if (canvas.backgroundImage instanceof fabric.Image) { - const imgWidth = canvas.backgroundImage.width || 0; - const imgHeight = canvas.backgroundImage.height || 0; - const x1Px = x1 * imgWidth; - const x2Px = x2 * imgWidth; - const y1Px = y1 * imgHeight; - const y2Px = y2 * imgHeight; - const rectanglePx = { x1: x1Px, y1: y1Px, x2: x2Px, y2: y2Px }; - coord.rectPx = JSON.stringify(rectanglePx); - } - coord.deletedAt = "-1"; - return coord; - } - - function handleDeleteShape(): void { - if (canvas) { - canvas.getActiveObjects().forEach(function (element: fabric.Object) { - canvas.remove(element); - }); - setOutput(); - //this.setState({ canvas }, this.setOutput); - } - } + const coord: any = {}; + coord.id = element.data; + const left = element.left || 0; + const top = element.top || 0; + const width = element.width || 0; + const height = element.height || 0; + const scaleX = element.scaleX || 0; + const scaleY = element.scaleY || 0; + const x1 = left / canvas.getWidth(); + const y1 = top / canvas.getHeight(); + const x2 = (left + width * scaleX) / canvas.getWidth(); + const y2 = (top + height * scaleY) / canvas.getHeight(); + const rectangle = { x1: x1, y1: y1, x2: x2, y2: y2 }; + coord.rect = JSON.stringify(rectangle); + if (canvas.backgroundImage instanceof fabric.Image) { + const imgWidth = canvas.backgroundImage.width || 0; + const imgHeight = canvas.backgroundImage.height || 0; + const x1Px = x1 * imgWidth; + const x2Px = x2 * imgWidth; + const y1Px = y1 * imgHeight; + const y2Px = y2 * imgHeight; + const rectanglePx = { x1: x1Px, y1: y1Px, x2: x2Px, y2: y2Px }; + coord.rectPx = JSON.stringify(rectanglePx); + } + coord.deletedAt = "-1"; + return coord; + }, + [canvas] + ); - function setOutput(): void { + const setOutput = useCallback((): void => { if (!canvas) { return; } @@ -181,85 +143,137 @@ const ReactMultiCrop: React.FC = (props: ReactMultiCropProp cropcoords.forEach(function (element: fabric.Object) { outputValue.push(shapetoStructureData(element)); }); - // let stringOut = JSON.stringify(outputValue) if (props.input) { props.input.onChange(outputValue); } - } - + }, [canvas, shapetoStructureData]); - - function handleDiscardActiveObject(): void { + const handleNewShape = useCallback(() => { if (!canvas) { return; } - canvas.discardActiveObject(); - canvas.requestRenderAll(); - } - - function handleKeyPress(event: React.KeyboardEvent): void { - if (event.key === "Delete") { - // Handle Delete - handleDeleteShape(); + const coor: any = {}; + coor.id = null; + coor.rect = { x1: 0, y1: 0, x2: 0.2, y2: 0.2 }; + const rect = createObject(coor); + if (!rect) { + return; } - } + rect.lockRotation = true; + canvas.add(rect); + canvas.renderAll(); + setOutput(); + }, [canvas, createObject, setOutput]); - function changeImage(): void { - const { record } = props; - fabric.Image.fromURL(record.image, loadImage); - } + const doubleClickEvent = useCallback( + (options: any) => { + if (options.target) { + if (!canvas) { + return; + } + const left = options.target.left; + const top = options.target.top; + const width = options.target.width; + const height = options.target.height; + const attribute: any = {}; + attribute.left = left + 5; + attribute.top = top + 5; + attribute.width = width * options.target.scaleX; + attribute.height = height * options.target.scaleY; + const rect = createObjectByAttribute(attribute); + rect.lockRotation = true; + canvas.add(rect); + canvas.renderAll(); + setOutput(); + } + }, + [canvas, createObjectByAttribute, setOutput] + ); + + const handleDeleteShape = useCallback((): void => { + if (canvas) { + canvas.getActiveObjects().forEach(function (element: fabric.Object) { + canvas.remove(element); + }); + setOutput(); + } + }, [canvas, setOutput]); - function loadImage(img: fabric.Image): void { + const handleDiscardActiveObject = useCallback((): void => { if (!canvas) { return; } - canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), { - scaleX: canvas.getWidth() / (img.width || 1), - scaleY: canvas.getHeight() / (img.height || 1), - }); - if (initial) { - setInitial(false); - initialObjects(); - } - } + canvas.discardActiveObject(); + canvas.requestRenderAll(); + }, [canvas]); + + const handleKeyPress = useCallback( + (event: React.KeyboardEvent): void => { + if (event.key === "Delete") { + // Handle Delete + handleDeleteShape(); + } + }, + [handleDeleteShape] + ); - function initialObjects(): void { + const initialObjects = useCallback((): void => { if (!canvas) { return; } const { record } = props; - //const setOutput = this.setOutput.bind(this); - //const setStateOf = this.setState.bind(this); const inputObject = record.clippings; - //const createObject = this.createObject.bind(this); if (inputObject !== undefined) { inputObject.forEach(function (coord: any) { - const rect = createObject(canvas, coord); + const rect = createObject(coord); + if (!rect) { + return; + } canvas.add(rect); }); } canvas.renderAll(); - //setCanvas(canvas); - //setStateOf({ canvas }, setOutput); - } + }, [canvas, createObject]); + + const loadImage = useCallback( + (img: fabric.Image): void => { + if (!canvas) { + return; + } + canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), { + scaleX: canvas.getWidth() / (img.width || 1), + scaleY: canvas.getHeight() / (img.height || 1), + }); + if (initial) { + setInitial(false); + initialObjects(); + } + }, + [canvas, setInitial, initialObjects] + ); - function initialImage(): void { + const changeImage = useCallback((): void => { const { record } = props; fabric.Image.fromURL(record.image, loadImage); - } + }, [loadImage]); + + const initialImage = useCallback((): void => { + const { record } = props; + fabric.Image.fromURL(record.image, loadImage); + }, [loadImage]); - function initialCanvas(): void { + const initialCanvas = useCallback((): void => { let newCanvas = new fabric.Canvas(props.id || "canvas"); newCanvas.uniScaleTransform = true; newCanvas.on("mouse:dblclick", doubleClickEvent); newCanvas.on("object:modified", setOutput); setCanvas(newCanvas); initialImage(); - } + }, [setCanvas, initialImage]); useEffect(() => { initialCanvas(); - }, []); + }, [initialCanvas, initialImage, loadImage, initialObjects]); return (
@@ -296,8 +310,8 @@ const ReactMultiCrop: React.FC = (props: ReactMultiCropProp onClick={handleNewShape} > {" "} - Add More Shapes - + Add More Shapes + @@ -318,7 +332,7 @@ const ReactMultiCrop: React.FC = (props: ReactMultiCropProp onClick={handleMultiSelect} > {" "} - Select All{" "} + Select All{" "} @@ -329,17 +343,16 @@ const ReactMultiCrop: React.FC = (props: ReactMultiCropProp onClick={handleDiscardActiveObject} > {" "} - Discard Selection - + Discard Selection + - +
); - -} +}; ReactMultiCrop.defaultProps = defaultProps; -export default ReactMultiCrop; \ No newline at end of file +export default ReactMultiCrop; diff --git a/src/ReactMultiCrop/ReactMultiCrop.types.ts b/src/ReactMultiCrop/ReactMultiCrop.types.ts index 2360c2a..a217a23 100644 --- a/src/ReactMultiCrop/ReactMultiCrop.types.ts +++ b/src/ReactMultiCrop/ReactMultiCrop.types.ts @@ -8,4 +8,4 @@ export interface ReactMultiCropProps extends InputProps { strokeDashArray?: Array; strokeWidth?: number; record?: any; -}; +} diff --git a/src/ReactMultiCrop/ReactMultiCropForm.tsx b/src/ReactMultiCrop/ReactMultiCropForm.tsx index e76c102..67d8d1d 100644 --- a/src/ReactMultiCrop/ReactMultiCropForm.tsx +++ b/src/ReactMultiCrop/ReactMultiCropForm.tsx @@ -1,8 +1,17 @@ // in src/App.js import * as React from "react"; -import { Admin, Resource, Create, SimpleForm, ImageInput, List, Datagrid, TextField } from 'react-admin'; -import simpleRestProvider from 'ra-data-simple-rest'; -import ReactMultiCrop from './ReactMultiCrop'; +import { + Admin, + Resource, + Create, + SimpleForm, + ImageInput, + List, + Datagrid, + TextField, +} from "react-admin"; +import simpleRestProvider from "ra-data-simple-rest"; +import ReactMultiCrop from "./ReactMultiCrop"; const CreateForm = (props: any) => ( @@ -21,9 +30,11 @@ const ListPost = (props: any) => ( ); -const dataProvider = simpleRestProvider('https://jsonplaceholder.typicode.com'); -const App = () => - -; +const dataProvider = simpleRestProvider("https://jsonplaceholder.typicode.com"); +const App = () => ( + + + +); export default App;