Hide popups on clicking outside of them

Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
Egor Savkin 2023-08-23 12:58:13 +08:00
parent 894c1d2e14
commit 0fe665c0ba
4 changed files with 23 additions and 221 deletions

230
package-lock.json generated
View File

@ -12,6 +12,7 @@
"@babel/core": "^7.22.8", "@babel/core": "^7.22.8",
"@babel/preset-env": "^7.22.7", "@babel/preset-env": "^7.22.7",
"@babel/preset-react": "^7.22.5", "@babel/preset-react": "^7.22.5",
"@uidotdev/usehooks": "^2.1.1",
"axios": "^1.4.0", "axios": "^1.4.0",
"babel-loader": "^9.1.3", "babel-loader": "^9.1.3",
"babel-preset-minify": "^0.5.2", "babel-preset-minify": "^0.5.2",
@ -21,7 +22,6 @@
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",
"react-bootstrap": "^2.8.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"webpack": "^5.88.1", "webpack": "^5.88.1",
@ -1924,77 +1924,12 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"dev": true, "dev": true,
"peer": true,
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/popperjs" "url": "https://opencollective.com/popperjs"
} }
}, },
"node_modules/@react-aria/ssr": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.8.0.tgz",
"integrity": "sha512-Y54xs483rglN5DxbwfCPHxnkvZ+gZ0LbSYmR72LyWPGft8hN/lrl1VRS1EW2SMjnkEWlj+Km2mwvA3kEHDUA0A==",
"dev": true,
"dependencies": {
"@swc/helpers": "^0.5.0"
},
"engines": {
"node": ">= 12"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
}
},
"node_modules/@restart/hooks": {
"version": "0.4.11",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.11.tgz",
"integrity": "sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw==",
"dev": true,
"dependencies": {
"dequal": "^2.0.3"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@restart/ui": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz",
"integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.21.0",
"@popperjs/core": "^2.11.6",
"@react-aria/ssr": "^3.5.0",
"@restart/hooks": "^0.4.9",
"@types/warning": "^3.0.0",
"dequal": "^2.0.3",
"dom-helpers": "^5.2.0",
"uncontrollable": "^8.0.1",
"warning": "^4.0.3"
},
"peerDependencies": {
"react": ">=16.14.0",
"react-dom": ">=16.14.0"
}
},
"node_modules/@restart/ui/node_modules/uncontrollable": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz",
"integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==",
"dev": true,
"peerDependencies": {
"react": ">=16.14.0"
}
},
"node_modules/@swc/helpers": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
"integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
"dev": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@types/eslint": { "node_modules/@types/eslint": {
"version": "8.44.0", "version": "8.44.0",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.0.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.0.tgz",
@ -2072,26 +2007,24 @@
"redux": "^4.0.0" "redux": "^4.0.0"
} }
}, },
"node_modules/@types/react-transition-group": {
"version": "4.4.8",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.8.tgz",
"integrity": "sha512-QmQ22q+Pb+HQSn04NL3HtrqHwYMf4h3QKArOy5F8U5nEVMaihBs3SR10WiOM1iwPz5jIo8x/u11al+iEGZZrvg==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/scheduler": { "node_modules/@types/scheduler": {
"version": "0.16.3", "version": "0.16.3",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
"dev": true "dev": true
}, },
"node_modules/@types/warning": { "node_modules/@uidotdev/usehooks": {
"version": "3.0.2", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.2.tgz", "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.1.1.tgz",
"integrity": "sha512-S/2+OjBIcBl8Kur23YLe0hG1e7J5m2bHfB4UuMNoLZjIFhQWhTf1FeS+WFoXHUC6QsCEfk4pftj4J1KIKC1glA==", "integrity": "sha512-sVJ1jXU62Edh22dREEa3mHcHnH2MUgokuzLw9guNS30ADCkdhYASNZxg2V8iB83iwY5H+jSeSxjqGaFvsRrNBQ==",
"dev": true "dev": true,
"engines": {
"node": ">=16"
},
"peerDependencies": {
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
}
}, },
"node_modules/@webassemblyjs/ast": { "node_modules/@webassemblyjs/ast": {
"version": "1.11.6", "version": "1.11.6",
@ -2866,12 +2799,6 @@
"node": ">=6.0" "node": ">=6.0"
} }
}, },
"node_modules/classnames": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==",
"dev": true
},
"node_modules/clone-deep": { "node_modules/clone-deep": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@ -3017,25 +2944,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.454", "version": "1.4.454",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.454.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.454.tgz",
@ -3500,15 +3408,6 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"dev": true,
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/is-binary-path": { "node_modules/is-binary-path": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@ -3982,25 +3881,6 @@
"react-is": "^16.13.1" "react-is": "^16.13.1"
} }
}, },
"node_modules/prop-types-extra": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
"integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
"dev": true,
"dependencies": {
"react-is": "^16.3.2",
"warning": "^4.0.0"
},
"peerDependencies": {
"react": ">=0.14.0"
}
},
"node_modules/prop-types-extra/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==",
"dev": true
},
"node_modules/prop-types/node_modules/react-is": { "node_modules/prop-types/node_modules/react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -4068,36 +3948,6 @@
"react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0"
} }
}, },
"node_modules/react-bootstrap": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.9.1.tgz",
"integrity": "sha512-ezgmh/ARCYp18LbZEqPp0ppvy+ytCmycDORqc8vXSKYV3cer4VH7OReV8uMOoKXmYzivJTxgzGHalGrHamryHA==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.22.5",
"@restart/hooks": "^0.4.9",
"@restart/ui": "^1.6.6",
"@types/react-transition-group": "^4.4.6",
"classnames": "^2.3.2",
"dom-helpers": "^5.2.1",
"invariant": "^2.2.4",
"prop-types": "^15.8.1",
"prop-types-extra": "^1.1.0",
"react-transition-group": "^4.4.5",
"uncontrollable": "^7.2.1",
"warning": "^4.0.3"
},
"peerDependencies": {
"@types/react": ">=16.14.8",
"react": ">=16.14.0",
"react-dom": ">=16.14.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "18.2.0", "version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
@ -4117,12 +3967,6 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true "dev": true
}, },
"node_modules/react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
"dev": true
},
"node_modules/react-redux": { "node_modules/react-redux": {
"version": "7.2.9", "version": "7.2.9",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz",
@ -4148,22 +3992,6 @@
} }
} }
}, },
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": ">=16.6.0",
"react-dom": ">=16.6.0"
}
},
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@ -4597,27 +4425,6 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
"dev": true
},
"node_modules/uncontrollable": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
"integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.6.3",
"@types/react": ">=16.9.11",
"invariant": "^2.2.4",
"react-lifecycles-compat": "^3.0.4"
},
"peerDependencies": {
"react": ">=15.0.0"
}
},
"node_modules/unicode-canonical-property-names-ecmascript": { "node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
@ -4715,15 +4522,6 @@
"uuid": "dist/bin/uuid" "uuid": "dist/bin/uuid"
} }
}, },
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"dev": true,
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/watchpack": { "node_modules/watchpack": {
"version": "2.4.0", "version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",

View File

@ -29,7 +29,7 @@
"webpack": "^5.88.1", "webpack": "^5.88.1",
"webpack-cli": "^5.1.4", "webpack-cli": "^5.1.4",
"json-logic-js": "^2.0.2", "json-logic-js": "^2.0.2",
"react-bootstrap": "^2.8.0" "@uidotdev/usehooks": "^2.1.1"
}, },
"babel": { "babel": {
"presets": [ "presets": [

View File

@ -1290,7 +1290,8 @@ class OrderForm extends React.PureComponent {
className="btn btn-outline-primary w-100 m-0 mb-2 mb-sm-0 me-sm-2" className="btn btn-outline-primary w-100 m-0 mb-2 mb-sm-0 me-sm-2"
style={{'cursor': 'pointer', 'fontWeight': '700'}} style={{'cursor': 'pointer', 'fontWeight': '700'}}
defaultValue="Show JSON" defaultValue="Show JSON"
onClick={onClickShow} /> onClick={onClickShow}
readOnly={true} />
<input className="btn btn-primary w-100 m-0 ms-sm-2" type="submit" value={`${isProcessing ? 'Processing ...' : 'Request quote'}`} /> <input className="btn btn-primary w-100 m-0 ms-sm-2" type="submit" value={`${isProcessing ? 'Processing ...' : 'Request quote'}`} />
</div> </div>

View File

@ -3,6 +3,7 @@
import React, {Component} from "react"; import React, {Component} from "react";
import jsonLogic from 'json-logic-js'; import jsonLogic from 'json-logic-js';
import {useState} from 'react'; import {useState} from 'react';
import {useClickAway} from "@uidotdev/usehooks";
// https://stackoverflow.com/a/70511311 // https://stackoverflow.com/a/70511311
const trueTypeOf = (obj) => Object.prototype.toString.call(obj).slice(8, -1).toLowerCase(); const trueTypeOf = (obj) => Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
@ -239,7 +240,7 @@ const componentsList = {
}; };
export default function ProcessOptions({options, data, target, id}) { export function ProcessOptions({options, data, target, id}) {
let options_t = trueTypeOf(options); let options_t = trueTypeOf(options);
if (options_t === "array") { if (options_t === "array") {
@ -269,6 +270,7 @@ export default function ProcessOptions({options, data, target, id}) {
export function CustomizeButton({options, data, target, id, big}) { export function CustomizeButton({options, data, target, id, big}) {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const ref = useClickAway(() => setShow(false));
let div_classes = "overlayVariant border rounded " + (big ? "overlay-bigcard" : "overlay-smallcard") let div_classes = "overlayVariant border rounded " + (big ? "overlay-bigcard" : "overlay-smallcard")
const handleClick = (event) => { const handleClick = (event) => {
@ -276,7 +278,7 @@ export function CustomizeButton({options, data, target, id, big}) {
}; };
return ( return (
<div> <div ref={ref}>
<img className="alert-info" src={show ? "/images/shop/icon-close.svg" : "/images/shop/icon-customize.svg"} <img className="alert-info" src={show ? "/images/shop/icon-close.svg" : "/images/shop/icon-customize.svg"}
onClick={handleClick}/> onClick={handleClick}/>
<div style={{'display': show ? 'flex' : 'none'}} className={div_classes}> <div style={{'display': show ? 'flex' : 'none'}} className={div_classes}>
@ -295,6 +297,7 @@ export function CustomizeButton({options, data, target, id, big}) {
export function CustomizeData({id, data}) { export function CustomizeData({id, data}) {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const [position, setPosition] = useState({x: 0, y: 0}); const [position, setPosition] = useState({x: 0, y: 0});
const ref = useClickAway(() => setShow(false));
const handleClick = (event) => { const handleClick = (event) => {
setPosition({x: event.clientX, y: event.clientY}); setPosition({x: event.clientX, y: event.clientY});
@ -316,7 +319,7 @@ export function CustomizeData({id, data}) {
} }
return ( return (
<div> <div ref={ref}>
<img className="alert-info" src={show ? "/images/shop/icon-close.svg" : "/images/shop/icon-customize.svg"} <img className="alert-info" src={show ? "/images/shop/icon-close.svg" : "/images/shop/icon-customize.svg"}
style={{'marginLeft': '10px'}} style={{'marginLeft': '10px'}}
onClick={handleClick}/> onClick={handleClick}/>