mirror of
https://github.com/responsively-org/responsively-app
synced 2024-09-21 06:41:55 +00:00
Merge pull request #270 from kvnam/issue-112/responsive-mode
Issue 112 - Responsive mode added
This commit is contained in:
commit
70f0bee910
10 changed files with 270 additions and 32 deletions
|
@ -37,6 +37,7 @@
|
||||||
"jsx-a11y/anchor-is-valid": "off",
|
"jsx-a11y/anchor-is-valid": "off",
|
||||||
"no-console": "off",
|
"no-console": "off",
|
||||||
"no-use-before-define": "off",
|
"no-use-before-define": "off",
|
||||||
|
"no-underscore-dangle": "off",
|
||||||
"no-multi-assign": "off",
|
"no-multi-assign": "off",
|
||||||
"promise/param-names": "error",
|
"promise/param-names": "error",
|
||||||
"promise/always-return": "error",
|
"promise/always-return": "error",
|
||||||
|
|
|
@ -87,6 +87,7 @@ export default function AddDevice(props) {
|
||||||
const [capabilities, setCapabilities] = useState({
|
const [capabilities, setCapabilities] = useState({
|
||||||
[CAPABILITIES.mobile]: false,
|
[CAPABILITIES.mobile]: false,
|
||||||
[CAPABILITIES.touch]: true,
|
[CAPABILITIES.touch]: true,
|
||||||
|
[CAPABILITIES.responsive]: false,
|
||||||
});
|
});
|
||||||
const [deviceType, setDeviceType] = useState(DEVICE_TYPE.phone);
|
const [deviceType, setDeviceType] = useState(DEVICE_TYPE.phone);
|
||||||
const [os, setOS] = useState(OS.android);
|
const [os, setOS] = useState(OS.android);
|
||||||
|
@ -368,6 +369,23 @@ export default function AddDevice(props) {
|
||||||
label="Touchscreen"
|
label="Touchscreen"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<CustomCheckbox
|
||||||
|
checked={capabilities[CAPABILITIES.responsive]}
|
||||||
|
onChange={e =>
|
||||||
|
setCapabilities({
|
||||||
|
...capabilities,
|
||||||
|
[CAPABILITIES.responsive]: e.target.checked,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
value="Responsive"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Responsive"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<TextField
|
<TextField
|
||||||
|
|
|
@ -3,15 +3,20 @@ import React, {useState, useCallback} from 'react';
|
||||||
import WebViewContainer from '../../containers/WebViewContainer';
|
import WebViewContainer from '../../containers/WebViewContainer';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import Spinner from '../Spinner';
|
import Spinner from '../Spinner';
|
||||||
import TickAnimation from '../icons/TickAnimation';
|
import {CAPABILITIES} from '../../constants/devices';
|
||||||
|
|
||||||
import styles from './style.module.css';
|
import styles from './style.module.css';
|
||||||
import {getDeviceIcon} from '../../utils/iconUtils';
|
import {getDeviceIcon} from '../../utils/iconUtils';
|
||||||
|
|
||||||
function Renderer(props) {
|
function Renderer(props) {
|
||||||
|
const { device, hidden, transmitNavigatorStatus } = props;
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [isFlip, setFlip] = useState(false);
|
const [isFlip, setFlip] = useState(false);
|
||||||
let dimension = [props.device.width, 'x', props.device.height];
|
const [finalDimensions, setFinalDimensions] = useState({
|
||||||
|
width: device.width,
|
||||||
|
height: device.height
|
||||||
|
});
|
||||||
|
const dimension = [finalDimensions.width, 'x', finalDimensions.height];
|
||||||
|
|
||||||
const sendFlipStatus = useCallback(
|
const sendFlipStatus = useCallback(
|
||||||
status => {
|
status => {
|
||||||
|
@ -21,10 +26,10 @@ function Renderer(props) {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.container, {[styles.hidden]: props.hidden})}>
|
<div className={cx(styles.container, {[styles.hidden]: hidden})}>
|
||||||
<div className={styles.titleContainer}>
|
<div className={styles.titleContainer}>
|
||||||
{getDeviceIcon(props.device.type)}
|
{getDeviceIcon(device.type)}
|
||||||
<span className={cx(styles.deviceTitle)}>{props.device.name}</span>
|
<span className={cx(styles.deviceTitle)}>{device.name}</span>
|
||||||
<div className={cx(styles.deviceSize)}>
|
<div className={cx(styles.deviceSize)}>
|
||||||
{isFlip ? dimension.reverse().join('') : dimension.join('')}
|
{isFlip ? dimension.reverse().join('') : dimension.join('')}
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,10 +43,11 @@ function Renderer(props) {
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(styles.deviceWrapper)}>
|
<div className={cx(styles.deviceWrapper)}>
|
||||||
<WebViewContainer
|
<WebViewContainer
|
||||||
device={props.device}
|
device={device}
|
||||||
sendFlipStatus={sendFlipStatus}
|
sendFlipStatus={sendFlipStatus}
|
||||||
transmitNavigatorStatus={props.transmitNavigatorStatus}
|
transmitNavigatorStatus={transmitNavigatorStatus}
|
||||||
onLoadingStateChange={setLoading}
|
onLoadingStateChange={setLoading}
|
||||||
|
updateResponsiveDimensions={setFinalDimensions}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React, {Component, createRef} from 'react';
|
import React, {Component, createRef} from 'react';
|
||||||
import {ipcRenderer, remote} from 'electron';
|
import { remote } from 'electron';
|
||||||
|
import cx from 'classnames';
|
||||||
|
import { Resizable } from 're-resizable';
|
||||||
|
import {Tooltip} from '@material-ui/core';
|
||||||
|
import debounce from 'lodash.debounce';
|
||||||
import pubsub from 'pubsub.js';
|
import pubsub from 'pubsub.js';
|
||||||
import BugIcon from '../icons/Bug';
|
import BugIcon from '../icons/Bug';
|
||||||
import ScreenshotIcon from '../icons/Screenshot';
|
import ScreenshotIcon from '../icons/Screenshot';
|
||||||
import DeviceRotateIcon from '../icons/DeviceRotate';
|
import DeviceRotateIcon from '../icons/DeviceRotate';
|
||||||
import cx from 'classnames';
|
|
||||||
import {iconsColor} from '../../constants/colors';
|
import {iconsColor} from '../../constants/colors';
|
||||||
import {
|
import {
|
||||||
SCROLL_DOWN,
|
SCROLL_DOWN,
|
||||||
|
@ -28,7 +31,6 @@ import styles from './style.module.css';
|
||||||
import commonStyles from '../common.styles.css';
|
import commonStyles from '../common.styles.css';
|
||||||
import UnplugIcon from '../icons/Unplug';
|
import UnplugIcon from '../icons/Unplug';
|
||||||
import {captureFullPage} from './screenshotUtil';
|
import {captureFullPage} from './screenshotUtil';
|
||||||
import {Tooltip} from '@material-ui/core';
|
|
||||||
import {
|
import {
|
||||||
DEVTOOLS_MODES,
|
DEVTOOLS_MODES,
|
||||||
INDIVIDUAL_LAYOUT,
|
INDIVIDUAL_LAYOUT,
|
||||||
|
@ -63,6 +65,11 @@ class WebView extends Component {
|
||||||
isUnplugged: false,
|
isUnplugged: false,
|
||||||
errorCode: null,
|
errorCode: null,
|
||||||
errorDesc: null,
|
errorDesc: null,
|
||||||
|
deviceDimensions : {
|
||||||
|
width: this.props.device.width,
|
||||||
|
height: this.props.device.height
|
||||||
|
},
|
||||||
|
temporaryDims: null,
|
||||||
address: this.props.browser.address,
|
address: this.props.browser.address,
|
||||||
};
|
};
|
||||||
this.subscriptions = [];
|
this.subscriptions = [];
|
||||||
|
@ -401,7 +408,8 @@ class WebView extends Component {
|
||||||
return;
|
return;
|
||||||
case MESSAGE_TYPES.toggleEventMirroring:
|
case MESSAGE_TYPES.toggleEventMirroring:
|
||||||
this._unPlug();
|
this._unPlug();
|
||||||
return;
|
break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -517,17 +525,92 @@ class WebView extends Component {
|
||||||
return this.props.device.capabilities.indexOf(CAPABILITIES.mobile) > -1;
|
return this.props.device.capabilities.indexOf(CAPABILITIES.mobile) > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setResizeDimensions = (event, direction, ref, delta) => {
|
||||||
|
const { temporaryDims } = this.state;
|
||||||
|
const { updateResponsiveDimensions } = this.props;
|
||||||
|
if(!temporaryDims) return;
|
||||||
|
const updatedDeviceDims = {
|
||||||
|
width: temporaryDims.width + delta.width,
|
||||||
|
height: temporaryDims.height + delta.height
|
||||||
|
};
|
||||||
|
this.setState({
|
||||||
|
deviceDimensions: updatedDeviceDims
|
||||||
|
}, () => {
|
||||||
|
updateResponsiveDimensions(this.state.deviceDimensions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_getWebViewTag = (deviceStyles) => {
|
||||||
|
const {device : { id, useragent, capabilities }, browser : { address } } = this.props;
|
||||||
|
const { deviceDimensions } = this.state;
|
||||||
|
|
||||||
|
if(capabilities.includes(CAPABILITIES.responsive)){
|
||||||
|
const responsiveStyle = {
|
||||||
|
width: deviceDimensions.width,
|
||||||
|
height: deviceDimensions.height
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Resizable
|
||||||
|
className={cx(styles.resizableView)}
|
||||||
|
size={{width: responsiveStyle.width, height: responsiveStyle.height}}
|
||||||
|
onResizeStart={() => {
|
||||||
|
const updatedTempDims = {
|
||||||
|
width: deviceDimensions.width,
|
||||||
|
height: deviceDimensions.height
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
temporaryDims: updatedTempDims
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onResize={debounce(this._setResizeDimensions, 25, { maxWait: 50 })}
|
||||||
|
onResizeStop={() =>{
|
||||||
|
this.setState({
|
||||||
|
temporaryDims: null
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
handleComponent={
|
||||||
|
{
|
||||||
|
right: <div className={cx(styles.iconWrapper, styles.iconWrapperE)} {...this.props}><div className={styles.iconHolder} /></div>,
|
||||||
|
bottom : <div className={cx(styles.iconWrapper, styles.iconWrapperS)} {...this.props}><div className={styles.iconHolder} /></div>,
|
||||||
|
bottomRight : <div className={cx(styles.iconWrapper, styles.iconWrapperSE)} {...this.props}><div className={styles.iconHolder} /></div>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<webview
|
||||||
|
ref={this.webviewRef}
|
||||||
|
preload="./preload.js"
|
||||||
|
className={cx(styles.device)}
|
||||||
|
src={address || 'about:blank'}
|
||||||
|
useragent={useragent}
|
||||||
|
style={responsiveStyle}
|
||||||
|
/>
|
||||||
|
</Resizable>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<webview
|
||||||
|
ref={this.webviewRef}
|
||||||
|
preload="./preload.js"
|
||||||
|
className={cx(styles.device)}
|
||||||
|
src={address || 'about:blank'}
|
||||||
|
useragent={useragent}
|
||||||
|
style={deviceStyles}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {device, browser} = this.props;
|
const { browser : { zoomLevel, previewer } } = this.props;
|
||||||
|
const { isTilted, deviceDimensions, errorCode, errorDesc, screenshotInProgress } = this.state;
|
||||||
const deviceStyles = {
|
const deviceStyles = {
|
||||||
width:
|
width:
|
||||||
this.isMobile && this.state.isTilted ? device.height : device.width,
|
this.isMobile && isTilted ? deviceDimensions.height : deviceDimensions.width,
|
||||||
height:
|
height:
|
||||||
this.isMobile && this.state.isTilted ? device.width : device.height,
|
this.isMobile && isTilted ? deviceDimensions.width : deviceDimensions.height,
|
||||||
transform: `scale(${browser.zoomLevel})`,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let shouldMaximize = browser.previewer.layout !== INDIVIDUAL_LAYOUT;
|
const shouldMaximize = previewer.layout !== INDIVIDUAL_LAYOUT;
|
||||||
const IconFocus = () => {
|
const IconFocus = () => {
|
||||||
if (shouldMaximize)
|
if (shouldMaximize)
|
||||||
return <Focus height={30} padding={6} color={iconsColor} />;
|
return <Focus height={30} padding={6} color={iconsColor} />;
|
||||||
|
@ -536,7 +619,10 @@ class WebView extends Component {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx(styles.webViewContainer)}
|
className={cx(styles.webViewContainer)}
|
||||||
style={{height: deviceStyles.height * browser.zoomLevel + 40}} //Hack, ref below TODO
|
style={{
|
||||||
|
width: deviceStyles.width * zoomLevel,
|
||||||
|
height: deviceStyles.height * zoomLevel + 40
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className={cx(styles.webViewToolbar)}>
|
<div className={cx(styles.webViewToolbar)}>
|
||||||
<div className={cx(styles.webViewToolbarLeft)}>
|
<div className={cx(styles.webViewToolbarLeft)}>
|
||||||
|
@ -621,33 +707,26 @@ class WebView extends Component {
|
||||||
[styles.devToolsActive]: this._isDevToolsOpen(),
|
[styles.devToolsActive]: this._isDevToolsOpen(),
|
||||||
})}
|
})}
|
||||||
style={{
|
style={{
|
||||||
width: deviceStyles.width * browser.zoomLevel + 6,
|
width: deviceStyles.width,
|
||||||
height: deviceStyles.height * browser.zoomLevel + 6, //TODO why is this height not getting set?
|
transform: `scale(${zoomLevel})`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cx(styles.deviceOverlay, {
|
className={cx(styles.deviceOverlay, {
|
||||||
[styles.overlayEnabled]: this.state.screenshotInProgress,
|
[styles.overlayEnabled]: screenshotInProgress,
|
||||||
})}
|
})}
|
||||||
style={deviceStyles}
|
style={deviceStyles}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={cx(styles.deviceOverlay, {
|
className={cx(styles.deviceOverlay, {
|
||||||
[styles.overlayEnabled]: this.state.errorCode,
|
[styles.overlayEnabled]: errorCode,
|
||||||
})}
|
})}
|
||||||
style={deviceStyles}
|
style={deviceStyles}
|
||||||
>
|
>
|
||||||
<p>ERROR: {this.state.errorCode}</p>
|
<p>ERROR: {errorCode}</p>
|
||||||
<p className={cx(styles.errorDesc)}>{this.state.errorDesc}</p>
|
<p className={cx(styles.errorDesc)}>{errorDesc}</p>
|
||||||
</div>
|
</div>
|
||||||
<webview
|
{this._getWebViewTag(deviceStyles)}
|
||||||
ref={this.webviewRef}
|
|
||||||
preload="./preload.js"
|
|
||||||
className={cx(styles.device)}
|
|
||||||
src={this.state.address || 'about:blank'}
|
|
||||||
useragent={device.useragent}
|
|
||||||
style={deviceStyles}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
.webViewToolbar {
|
.webViewToolbar {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +31,8 @@
|
||||||
|
|
||||||
.deviceContainer {
|
.deviceContainer {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display:inline-flex;
|
||||||
|
transform-origin: top left;
|
||||||
border: 3px solid #687cee00;
|
border: 3px solid #687cee00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,3 +63,95 @@
|
||||||
.errorDesc {
|
.errorDesc {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.iconWrapper{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: absolute;
|
||||||
|
background-position: center;
|
||||||
|
height: '100%';
|
||||||
|
width: '100%';
|
||||||
|
padding: 0;
|
||||||
|
background-color: #3b3b3b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrapper:hover{
|
||||||
|
background-color: #575757;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrapperS{
|
||||||
|
width: 100%;
|
||||||
|
height: 15px;
|
||||||
|
bottom: -10px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.iconWrapperE{
|
||||||
|
width: 15px;
|
||||||
|
height: 100%;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
top: 0;
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
.iconWrapperSE {
|
||||||
|
right: -5px;
|
||||||
|
bottom: -5px;
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconHolder{
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
height: 7px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconHolder::before, .iconHolder::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 15px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrapperE .iconHolder{
|
||||||
|
right: 1px;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrapperS .iconHolder{
|
||||||
|
bottom : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrapperSE .iconHolder{
|
||||||
|
right: 3px;
|
||||||
|
top: 2px;
|
||||||
|
height: 6px;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconHolder::before{
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconHolder::after{
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrapperSE .iconHolder::before{
|
||||||
|
left: -2px;
|
||||||
|
width: 11px;
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrapperSE .iconHolder::after{
|
||||||
|
bottom: 0;
|
||||||
|
width: 7px;
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resizableView{
|
||||||
|
margin: 0 1rem;
|
||||||
|
}
|
|
@ -1301,6 +1301,35 @@ export default {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: '34',
|
||||||
|
type: 'emulated-device',
|
||||||
|
device: {
|
||||||
|
'show-by-default': true,
|
||||||
|
title: 'Responsive Mode',
|
||||||
|
screen: {
|
||||||
|
horizontal: {
|
||||||
|
width: 500,
|
||||||
|
height: 790,
|
||||||
|
},
|
||||||
|
'device-pixel-ratio': 2,
|
||||||
|
vertical: {
|
||||||
|
width: 790,
|
||||||
|
height: 500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
capabilities: ['responsive'],
|
||||||
|
'user-agent': '',
|
||||||
|
type: 'notebook',
|
||||||
|
modes: [
|
||||||
|
{
|
||||||
|
title: 'default',
|
||||||
|
orientation: 'horizontal',
|
||||||
|
insets: {left: 0, top: 0, right: 0, bottom: 0},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
dependencies: ['emulation'],
|
dependencies: ['emulation'],
|
||||||
scripts: [],
|
scripts: [],
|
||||||
|
|
|
@ -19,6 +19,7 @@ export const DEVICE_TYPE: {[key: string]: DeviceType} = {
|
||||||
export const CAPABILITIES: {[key: string]: Capability} = {
|
export const CAPABILITIES: {[key: string]: Capability} = {
|
||||||
mobile: 'mobile',
|
mobile: 'mobile',
|
||||||
touch: 'touch',
|
touch: 'touch',
|
||||||
|
responsive: 'responsive',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SOURCE: {[key: string]: Source} = {
|
export const SOURCE: {[key: string]: Source} = {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
/* eslint-disable import/first */
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {remote} from 'electron';
|
import {remote} from 'electron';
|
||||||
import {render} from 'react-dom';
|
import {render} from 'react-dom';
|
||||||
|
|
|
@ -280,6 +280,7 @@
|
||||||
"flwww": "^2.0.10",
|
"flwww": "^2.0.10",
|
||||||
"history": "^4.7.2",
|
"history": "^4.7.2",
|
||||||
"jimp": "^0.12.1",
|
"jimp": "^0.12.1",
|
||||||
|
"lodash.debounce": "^4.0.8",
|
||||||
"merge-img": "^2.1.3",
|
"merge-img": "^2.1.3",
|
||||||
"mousetrap": "^1.6.5",
|
"mousetrap": "^1.6.5",
|
||||||
"promise-worker": "^2.0.1",
|
"promise-worker": "^2.0.1",
|
||||||
|
|
|
@ -9991,6 +9991,11 @@ locate-path@^5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-locate "^4.1.0"
|
p-locate "^4.1.0"
|
||||||
|
|
||||||
|
lodash.debounce@^4.0.8:
|
||||||
|
version "4.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||||
|
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
|
||||||
|
|
||||||
lodash.escape@^4.0.1:
|
lodash.escape@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98"
|
resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98"
|
||||||
|
|
Loading…
Reference in a new issue