Stubs tests. Updates types for controls.

This commit is contained in:
Steve Ruiz 2021-06-25 11:28:52 +01:00
parent 32922b3f85
commit 85dc3028b4
33 changed files with 1391 additions and 1191 deletions

View file

@ -1,3 +0,0 @@
{
"presets": ["next/babel"]
}

View file

@ -13270,13 +13270,9 @@ Object {
"code": " "code": "
const draw = new Draw({ const draw = new Draw({
points: [ points: [
[0, 0], ...Utils.getPointsBetween([0, 0], [20, 50]),
[0, 50], ...Utils.getPointsBetween([20, 50], [100, 20], 3),
[20, 80], ...Utils.getPointsBetween([100, 20], [100, 100], 10),
[56, 56],
[52, 52],
[80, 20],
[90, 90],
[100, 100], [100, 100],
], ],
}) })

69
__tests__/code.test.ts Normal file
View file

@ -0,0 +1,69 @@
import state from 'state'
import { generateFromCode } from 'state/code/generate'
import { getShapes } from 'utils'
import * as json from './__mocks__/document.json'
jest.useRealTimers()
state.reset()
state.send('MOUNTED').send('LOADED_FROM_FILE', { json: JSON.stringify(json) })
state.send('CLEARED_PAGE')
describe('selection', () => {
it('opens and closes the code panel', () => {
expect(state.data.settings.isCodeOpen).toBe(false)
state.send('TOGGLED_CODE_PANEL_OPEN')
expect(state.data.settings.isCodeOpen).toBe(true)
state.send('TOGGLED_CODE_PANEL_OPEN')
expect(state.data.settings.isCodeOpen).toBe(false)
})
it('saves changes to code', () => {
expect(getShapes(state.data).length).toBe(0)
const code = `// hello world!`
state.send('SAVED_CODE', { code })
expect(state.data.document.code[state.data.currentCodeFileId].code).toBe(
code
)
})
it('generates shapes', async () => {
const code = `
const rectangle = new Rectangle({
name: 'Test Rectangle',
point: [100, 100],
size: [200, 200],
style: {
size: SizeStyle.Medium,
color: ColorStyle.Red,
dash: DashStyle.Dotted,
},
})
`
const { controls, shapes } = await generateFromCode(state.data, code)
state.send('GENERATED_FROM_CODE', { controls, shapes })
expect(getShapes(state.data).length).toBe(1)
})
it('creates a code control', () => {
null
})
it('updates a code control', () => {
null
})
it('updates a code control', () => {
null
})
/* -------------------- Readonly -------------------- */
it('does not saves changes to code when readonly', () => {
null
})
})

24
__tests__/create.test.ts Normal file
View file

@ -0,0 +1,24 @@
import state from 'state'
import * as json from './__mocks__/document.json'
state.reset()
state.send('MOUNTED').send('LOADED_FROM_FILE', { json: JSON.stringify(json) })
state.send('CLEARED_PAGE')
describe('arrow shape', () => {
it('creates a shape', () => {
null
})
it('cancels shape while creating', () => {
null
})
it('removes shape on undo and restores it on redo', () => {
null
})
it('does not create shape when readonly', () => {
null
})
})

View file

@ -0,0 +1,68 @@
import state from 'state'
import * as json from '../__mocks__/document.json'
state.reset()
state.send('MOUNTED').send('LOADED_FROM_FILE', { json: JSON.stringify(json) })
state.send('CLEARED_PAGE')
describe('arrow shape', () => {
it('creates shape', () => {
null
})
it('cancels shape while creating', () => {
null
})
it('moves shape', () => {
null
})
it('rotates shape', () => {
null
})
it('measures bounds', () => {
null
})
it('measures rotated bounds', () => {
null
})
it('transforms single', () => {
null
})
it('transforms in a group', () => {
null
})
/* -------------------- Specific -------------------- */
it('creates compass-aligned shape with shift key', () => {
null
})
it('changes start handle', () => {
null
})
it('changes end handle', () => {
null
})
it('changes bend handle', () => {
null
})
it('resets bend handle when double-pointed', () => {
null
})
/* -------------------- Readonly -------------------- */
it('does not create shape when readonly', () => {
null
})
})

View file

@ -46,3 +46,11 @@ export function idsAreSelected(
ids.every((id) => selectedIds.has(id)) ids.every((id) => selectedIds.has(id))
) )
} }
export async function asyncDelay<T>(fn: () => T): Promise<T> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(fn())
}, 100)
})
}

3
babel.config.js Normal file
View file

@ -0,0 +1,3 @@
module.exports = {
presets: ['next/babel'],
}

View file

@ -82,8 +82,11 @@ export default function CodePanel(): JSX.Element {
let error = null let error = null
try { try {
const { shapes, controls } = generateFromCode(state.data, data.code) generateFromCode(state.data, data.code).then(
({ shapes, controls }) => {
state.send('GENERATED_FROM_CODE', { shapes, controls }) state.send('GENERATED_FROM_CODE', { shapes, controls })
}
)
} catch (e) { } catch (e) {
console.error('Got an error!', e) console.error('Got an error!', e)
error = { message: e.message, ...getErrorLineAndColumn(e) } error = { message: e.message, ...getErrorLineAndColumn(e) }

File diff suppressed because it is too large Load diff

View file

@ -50,14 +50,21 @@ function NumberControl({ id, min, max, step, value }: NumberCodeControl) {
) )
} }
function VectorControl({ id, value, isNormalized }: VectorCodeControl) { function VectorControl({
id,
value,
min = -Infinity,
max = Infinity,
step = 0.01,
isNormalized = false,
}: VectorCodeControl) {
return ( return (
<Inputs> <Inputs>
<input <input
type="range" type="range"
min={isNormalized ? -1 : -Infinity} min={isNormalized ? -1 : min}
max={isNormalized ? 1 : Infinity} max={isNormalized ? 1 : max}
step={0.01} step={step}
value={value[0]} value={value[0]}
onChange={(e) => onChange={(e) =>
state.send('CHANGED_CODE_CONTROL', { state.send('CHANGED_CODE_CONTROL', {
@ -67,9 +74,9 @@ function VectorControl({ id, value, isNormalized }: VectorCodeControl) {
/> />
<input <input
type="number" type="number"
min={isNormalized ? -1 : -Infinity} min={isNormalized ? -1 : min}
max={isNormalized ? 1 : Infinity} max={isNormalized ? 1 : max}
step={0.01} step={step}
value={value[0]} value={value[0]}
onChange={(e) => onChange={(e) =>
state.send('CHANGED_CODE_CONTROL', { state.send('CHANGED_CODE_CONTROL', {
@ -79,9 +86,9 @@ function VectorControl({ id, value, isNormalized }: VectorCodeControl) {
/> />
<input <input
type="range" type="range"
min={isNormalized ? -1 : -Infinity} min={isNormalized ? -1 : min}
max={isNormalized ? 1 : Infinity} max={isNormalized ? 1 : max}
step={0.01} step={step}
value={value[1]} value={value[1]}
onChange={(e) => onChange={(e) =>
state.send('CHANGED_CODE_CONTROL', { state.send('CHANGED_CODE_CONTROL', {
@ -91,9 +98,9 @@ function VectorControl({ id, value, isNormalized }: VectorCodeControl) {
/> />
<input <input
type="number" type="number"
min={isNormalized ? -1 : -Infinity} min={isNormalized ? -1 : min}
max={isNormalized ? 1 : Infinity} max={isNormalized ? 1 : max}
step={0.01} step={step}
value={value[1]} value={value[1]}
onChange={(e) => onChange={(e) =>
state.send('CHANGED_CODE_CONTROL', { state.send('CHANGED_CODE_CONTROL', {

View file

@ -17,7 +17,12 @@ export default function ControlPanel(): JSX.Element {
const isOpen = useSelector((s) => Object.keys(s.data.codeControls).length > 0) const isOpen = useSelector((s) => Object.keys(s.data.codeControls).length > 0)
return ( return (
<Panel.Root data-bp-desktop ref={rContainer} isOpen={isOpen}> <Panel.Root
data-bp-desktop
ref={rContainer}
isOpen={isOpen}
variant="controls"
>
{isOpen ? ( {isOpen ? (
<Panel.Layout> <Panel.Layout>
<Panel.Header> <Panel.Header>

View file

@ -7,6 +7,7 @@ import StylePanel from './style-panel/style-panel'
import styled from 'styles' import styled from 'styles'
import PagePanel from './page-panel/page-panel' import PagePanel from './page-panel/page-panel'
import CodePanel from './code-panel/code-panel' import CodePanel from './code-panel/code-panel'
import ControlsPanel from './controls-panel/controls-panel'
export default function Editor(): JSX.Element { export default function Editor(): JSX.Element {
useKeyboardEvents() useKeyboardEvents()
@ -16,6 +17,7 @@ export default function Editor(): JSX.Element {
<Layout> <Layout>
<CodePanel /> <CodePanel />
<PagePanel /> <PagePanel />
<ControlsPanel />
<Spacer /> <Spacer />
<StylePanel /> <StylePanel />
<Canvas /> <Canvas />

View file

@ -18,6 +18,10 @@ export const Root = styled('div', {
}, },
variant: { variant: {
code: {}, code: {},
controls: {
position: 'absolute',
right: 156,
},
}, },
isOpen: { isOpen: {
true: {}, true: {},

View file

@ -1,9 +1,7 @@
module.exports = { module.exports = {
roots: ['<rootDir>'],
testEnvironment: 'jsdom', testEnvironment: 'jsdom',
moduleFileExtensions: ['ts', 'tsx', 'mjs', 'js', 'json', 'jsx'], testPathIgnorePatterns: ['node_modules', '.next'],
testPathIgnorePatterns: ['<rootDir>[/\\\\](node_modules|.next)[/\\\\]'], transformIgnorePatterns: ['node_modules/(?!(sucrase|browser-fs-access)/)'],
transformIgnorePatterns: ['node_modules/(?!(browser-fs-access)/)'],
transform: { transform: {
'^.+\\.(ts|tsx|mjs)$': 'babel-jest', '^.+\\.(ts|tsx|mjs)$': 'babel-jest',
}, },

View file

@ -8,12 +8,12 @@
"dev": "next dev", "dev": "next dev",
"format": "prettier --write .", "format": "prettier --write .",
"lint": "eslint . --ext ts --ext tsx --ext js", "lint": "eslint . --ext ts --ext tsx --ext js",
"scripts": "node scripts/type-gen && yarn format", "scripts": "node scripts/type-gen && prettier --write './components/code-panel/types-import.ts'",
"start": "next start", "start": "next start",
"test-all": "yarn lint && yarn type-check && yarn test", "test-all": "yarn lint && yarn type-check && yarn test",
"test:update": "jest --updateSnapshot", "test:update": "jest --updateSnapshot",
"test:watch": "jest --watchAll", "test:watch": "jest --watchAll",
"test": "jest", "test": "jest --watchAll=false",
"type-check": "tsc --pretty --noEmit" "type-check": "tsc --pretty --noEmit"
}, },
"husky": { "husky": {
@ -53,7 +53,7 @@
"idb-keyval": "^5.0.6", "idb-keyval": "^5.0.6",
"ismobilejs": "^1.1.1", "ismobilejs": "^1.1.1",
"monaco-editor": "^0.25.2", "monaco-editor": "^0.25.2",
"next": "latest", "next": "^11.0.1",
"next-auth": "^3.27.0", "next-auth": "^3.27.0",
"next-pwa": "^5.2.21", "next-pwa": "^5.2.21",
"perfect-freehand": "^0.4.9", "perfect-freehand": "^0.4.9",
@ -66,8 +66,7 @@
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@testing-library/react": "^11.2.5", "@babel/core": "^7.14.6",
"@testing-library/user-event": "^13.1.9",
"@types/jest": "^26.0.23", "@types/jest": "^26.0.23",
"@types/node": "^14.14.25", "@types/node": "^14.14.25",
"@types/react": "^17.0.1", "@types/react": "^17.0.1",
@ -80,7 +79,8 @@
"eslint-plugin-react": "^7.19.0", "eslint-plugin-react": "^7.19.0",
"husky": "^4.2.3", "husky": "^4.2.3",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"jest": "^27.0.4", "jest": "^27.0.5",
"jest-esm-transformer": "^1.0.0",
"jest-watch-typeahead": "^0.6.1", "jest-watch-typeahead": "^0.6.1",
"lint-staged": "^10.0.10", "lint-staged": "^10.0.10",
"prettier": "^2.3.1", "prettier": "^2.3.1",

View file

@ -1,52 +1,36 @@
// @ts-check // @ts-check
/* /*
Type gen script This script will generate TypeScript content for the code editor. It inlines
the content of several files into one large string which can be passed to the
Monaco editor as an extraLib.
This script will generate TypeScript declarations for the code editor. It reads Important notes:
the global types, as well as all of the code classes, and writes them into a
single file as a string. This string is fed into the Monaco editor as an extraLib. - Files must include the "Start Copy Here" comment indicated below.
- This comment must be placed BELOW any import statements.
Run the script with `yarn scripts`.
*/ */
const fs = require('fs/promises') const fs = require('fs/promises')
const root = process.cwd()
async function inlineFileContents(path) {
console.log(`📄 Inlining contents of ${path}`)
const text = await fs.readFile(`${root}${path}`, 'utf-8')
return text
.match(
/\/\* ----------------- Start Copy Here ---------------- \*\/(.|\n)*$/g
)[0]
.replaceAll('/* ----------------- Start Copy Here ---------------- */', '')
.replaceAll('export default', '')
.replaceAll('export ', '')
}
async function copyTypesToFile() { async function copyTypesToFile() {
const types = await fs.readFile(__dirname + '/../types.ts', 'utf8') console.log('⚙️ Generating types-import.ts')
const codeIndex = await fs.readFile(
__dirname + '/../state/code/index.ts',
'utf8'
)
const codeDot = await fs.readFile(__dirname + '/../state/code/dot.ts', 'utf8')
const codeEllipse = await fs.readFile(
__dirname + '/../state/code/ellipse.ts',
'utf8'
)
const codeLine = await fs.readFile(
__dirname + '/../state/code/line.ts',
'utf8'
)
const codePolyline = await fs.readFile(
__dirname + '/../state/code/polyline.ts',
'utf8'
)
const codeRay = await fs.readFile(__dirname + '/../state/code/ray.ts', 'utf8')
const codeArrow = await fs.readFile(
__dirname + '/../state/code/arrow.ts',
'utf8'
)
const codeDraw = await fs.readFile(
__dirname + '/../state/code/draw.ts',
'utf8'
)
const codeRectangle = await fs.readFile(
__dirname + '/../state/code/rectangle.ts',
'utf8'
)
const codeVector = await fs.readFile(__dirname + '/../utils/vec.ts', 'utf8')
const codeUtils = await fs.readFile(
__dirname + '/../state/code/utils.ts',
'utf8'
)
const content = const content =
` `
@ -59,28 +43,42 @@ export default {` +
name: "types.ts", name: "types.ts",
content: \` content: \`
${types}
${codeIndex.match(/export default(.|\n)*$/g)[0]} ${await inlineFileContents('/types.ts')}
${codeDot.match(/\/\*\*(.|\n)*$/g)[0]}
${codeEllipse.match(/\/\*\*(.|\n)*$/g)[0]} ${await inlineFileContents('/utils/vec.ts')}
${codeLine.match(/\/\*\*(.|\n)*$/g)[0]}
${codePolyline.match(/\/\*\*(.|\n)*$/g)[0]} ${await inlineFileContents('/state/code/utils.ts')}
${codeRay.match(/\/\*\*(.|\n)*$/g)[0]}
${codeRectangle.match(/\/\*\*(.|\n)*$/g)[0]} ${await inlineFileContents('/state/code/index.ts')}
${codeArrow.match(/\/\*\*(.|\n)*$/g)[0]}
${codeDraw.match(/\/\*\*(.|\n)*$/g)[0]} ${await inlineFileContents('/state/code/dot.ts')}
${codeUtils.match(/\/\*\*(.|\n)*$/g)[0]}
${codeVector} ${await inlineFileContents('/state/code/ellipse.ts')}
\`
}` ${await inlineFileContents('/state/code/line.ts')}
.replaceAll('export default', '')
.replaceAll('export ', '') ${await inlineFileContents('/state/code/polyline.ts')}
${await inlineFileContents('/state/code/ray.ts')}
${await inlineFileContents('/state/code/arrow.ts')}
${await inlineFileContents('/state/code/draw.ts')}
${await inlineFileContents('/state/code/rectangle.ts')}
${await inlineFileContents('/state/code/control.ts')}
declare const controls: {[key:string]: any} = {}
\`}`
await fs.writeFile( await fs.writeFile(
__dirname + '/../components/code-panel/types-import.ts', __dirname + '/../components/code-panel/types-import.ts',
content content
) )
console.log('✅ Process complete')
} }
// Kickoff // Kickoff

View file

@ -5,9 +5,8 @@ import { defaultStyle } from 'state/shape-styles'
import { getShapeUtils } from 'state/shape-utils' import { getShapeUtils } from 'state/shape-utils'
import Vec from 'utils/vec' import Vec from 'utils/vec'
/** /* ----------------- Start Copy Here ---------------- */
* ## Draw
*/
export default class Arrow extends CodeShape<ArrowShape> { export default class Arrow extends CodeShape<ArrowShape> {
constructor( constructor(
props = {} as ShapeProps<ArrowShape> & { start: number[]; end: number[] } props = {} as ShapeProps<ArrowShape> & { start: number[]; end: number[] }

View file

@ -10,6 +10,8 @@ export const controls: Record<string, any> = {}
export const codeControls = new Set<CodeControl>([]) export const codeControls = new Set<CodeControl>([])
/* ----------------- Start Copy Here ---------------- */
export class Control<T extends CodeControl> { export class Control<T extends CodeControl> {
control: T control: T
@ -29,14 +31,25 @@ export class Control<T extends CodeControl> {
codeControls.delete(this.control) codeControls.delete(this.control)
delete controls[this.control.label] delete controls[this.control.label]
} }
get value(): T['value'] {
return this.control.value
}
set value(value: T['value']) {
this.control.value = value
}
} }
type ControlProps<T extends CodeControl> = Omit<Partial<T>, 'id' | 'type'>
export class NumberControl extends Control<NumberCodeControl> { export class NumberControl extends Control<NumberCodeControl> {
constructor(options: Omit<NumberCodeControl, 'id' | 'type'>) { constructor(options: ControlProps<NumberCodeControl>) {
const { value = 0, step = 1 } = options const { label = 'Number', value = 0, step = 1 } = options
super({ super({
type: ControlType.Number, type: ControlType.Number,
...options, ...options,
label,
value, value,
step, step,
}) })
@ -44,11 +57,12 @@ export class NumberControl extends Control<NumberCodeControl> {
} }
export class VectorControl extends Control<VectorCodeControl> { export class VectorControl extends Control<VectorCodeControl> {
constructor(options: Omit<VectorCodeControl, 'id' | 'type'>) { constructor(options: ControlProps<VectorCodeControl>) {
const { value = [0, 0], isNormalized = false } = options const { label = 'Vector', value = [0, 0], isNormalized = false } = options
super({ super({
type: ControlType.Vector, type: ControlType.Vector,
...options, ...options,
label,
value, value,
isNormalized, isNormalized,
}) })

View file

@ -3,9 +3,8 @@ import { uniqueId } from 'utils'
import { DotShape, ShapeProps, ShapeType } from 'types' import { DotShape, ShapeProps, ShapeType } from 'types'
import { defaultStyle } from 'state/shape-styles' import { defaultStyle } from 'state/shape-styles'
/** /* ----------------- Start Copy Here ---------------- */
* ## Dot
*/
export default class Dot extends CodeShape<DotShape> { export default class Dot extends CodeShape<DotShape> {
constructor(props = {} as ShapeProps<DotShape>) { constructor(props = {} as ShapeProps<DotShape>) {
super({ super({

View file

@ -3,9 +3,8 @@ import { uniqueId } from 'utils'
import { DrawShape, ShapeProps, ShapeType } from 'types' import { DrawShape, ShapeProps, ShapeType } from 'types'
import { defaultStyle } from 'state/shape-styles' import { defaultStyle } from 'state/shape-styles'
/** /* ----------------- Start Copy Here ---------------- */
* ## Draw
*/
export default class Draw extends CodeShape<DrawShape> { export default class Draw extends CodeShape<DrawShape> {
constructor(props = {} as ShapeProps<DrawShape>) { constructor(props = {} as ShapeProps<DrawShape>) {
super({ super({
@ -13,8 +12,8 @@ export default class Draw extends CodeShape<DrawShape> {
seed: Math.random(), seed: Math.random(),
type: ShapeType.Draw, type: ShapeType.Draw,
isGenerated: false, isGenerated: false,
parentId: (window as any).currentPageId,
name: 'Draw', name: 'Draw',
parentId: 'page1',
childIndex: 0, childIndex: 0,
point: [0, 0], point: [0, 0],
points: [], points: [],

View file

@ -3,9 +3,8 @@ import { uniqueId } from 'utils'
import { EllipseShape, ShapeProps, ShapeType } from 'types' import { EllipseShape, ShapeProps, ShapeType } from 'types'
import { defaultStyle } from 'state/shape-styles' import { defaultStyle } from 'state/shape-styles'
/** /* ----------------- Start Copy Here ---------------- */
* ## Ellipse
*/
export default class Ellipse extends CodeShape<EllipseShape> { export default class Ellipse extends CodeShape<EllipseShape> {
constructor(props = {} as ShapeProps<EllipseShape>) { constructor(props = {} as ShapeProps<EllipseShape>) {
super({ super({

View file

@ -44,13 +44,13 @@ const baseScope = {
* collected shapes as an array. * collected shapes as an array.
* @param code * @param code
*/ */
export function generateFromCode( export async function generateFromCode(
data: Data, data: Data,
code: string code: string
): { ): Promise<{
shapes: Shape[] shapes: Shape[]
controls: CodeControl[] controls: CodeControl[]
} { }> {
codeControls.clear() codeControls.clear()
codeShapes.clear() codeShapes.clear()
;(window as any).isUpdatingCode = false ;(window as any).isUpdatingCode = false
@ -59,7 +59,9 @@ export function generateFromCode(
const { currentPageId } = data const { currentPageId } = data
const scope = { ...baseScope, controls, currentPageId } const scope = { ...baseScope, controls, currentPageId }
const transformed = transform(code, { transforms: ['typescript'] }).code const transformed = transform(code, {
transforms: ['typescript'],
}).code
new Function(...Object.keys(scope), `${transformed}`)(...Object.values(scope)) new Function(...Object.keys(scope), `${transformed}`)(...Object.values(scope))
@ -87,34 +89,50 @@ export function generateFromCode(
* collected shapes as an array. * collected shapes as an array.
* @param code * @param code
*/ */
export function updateFromCode( export async function updateFromCode(
data: Data, data: Data,
code: string code: string
): { ): Promise<{
shapes: Shape[] shapes: Shape[]
} { }> {
codeShapes.clear() codeShapes.clear()
;(window as any).isUpdatingCode = true ;(window as any).isUpdatingCode = true
;(window as any).currentPageId = data.currentPageId ;(window as any).currentPageId = data.currentPageId
const { currentPageId } = data const { currentPageId } = data
const scope = { const newControls = Object.fromEntries(
...baseScope, Object.entries(data.codeControls).map(([_, control]) => [
currentPageId,
controls: Object.fromEntries(
Object.entries(controls).map(([_, control]) => [
control.label, control.label,
control.value, control.value,
]) ])
), )
const scope = {
...baseScope,
currentPageId,
controls: newControls,
} }
new Function(...Object.keys(scope), `${code}`)(...Object.values(scope)) const startingChildIndex =
getShapes(data)
.filter((shape) => shape.parentId === data.currentPageId)
.sort((a, b) => a.childIndex - b.childIndex)[0]?.childIndex || 1
const generatedShapes = Array.from(codeShapes.values()).map( const transformed = transform(code, {
(instance) => instance.shape transforms: ['typescript'],
) }).code
new Function(...Object.keys(scope), `${transformed}`)(...Object.values(scope))
const generatedShapes = Array.from(codeShapes.values())
.sort((a, b) => a.shape.childIndex - b.shape.childIndex)
.map((instance, i) => ({
...instance.shape,
isGenerated: true,
parentId: getPage(data).id,
childIndex: startingChildIndex + i,
}))
return { shapes: generatedShapes } return { shapes: generatedShapes }
} }

View file

@ -21,6 +21,9 @@ function getOrderedShapes() {
* A base class for code shapes. Note that creating a shape adds it to the * A base class for code shapes. Note that creating a shape adds it to the
* shape map, while deleting it removes it from the collected shapes set * shape map, while deleting it removes it from the collected shapes set
*/ */
/* ----------------- Start Copy Here ---------------- */
export default class CodeShape<T extends Shape> { export default class CodeShape<T extends Shape> {
private _shape: Mutable<T> private _shape: Mutable<T>
private utils: ShapeUtility<T> private utils: ShapeUtility<T>

View file

@ -3,9 +3,8 @@ import { uniqueId } from 'utils'
import { LineShape, ShapeProps, ShapeType } from 'types' import { LineShape, ShapeProps, ShapeType } from 'types'
import { defaultStyle } from 'state/shape-styles' import { defaultStyle } from 'state/shape-styles'
/** /* ----------------- Start Copy Here ---------------- */
* ## Line
*/
export default class Line extends CodeShape<LineShape> { export default class Line extends CodeShape<LineShape> {
constructor(props = {} as ShapeProps<LineShape>) { constructor(props = {} as ShapeProps<LineShape>) {
super({ super({

View file

@ -3,9 +3,8 @@ import { uniqueId } from 'utils'
import { PolylineShape, ShapeProps, ShapeType } from 'types' import { PolylineShape, ShapeProps, ShapeType } from 'types'
import { defaultStyle } from 'state/shape-styles' import { defaultStyle } from 'state/shape-styles'
/** /* ----------------- Start Copy Here ---------------- */
* ## Polyline
*/
export default class Polyline extends CodeShape<PolylineShape> { export default class Polyline extends CodeShape<PolylineShape> {
constructor(props = {} as ShapeProps<PolylineShape>) { constructor(props = {} as ShapeProps<PolylineShape>) {
super({ super({
@ -22,8 +21,11 @@ export default class Polyline extends CodeShape<PolylineShape> {
isAspectRatioLocked: false, isAspectRatioLocked: false,
isLocked: false, isLocked: false,
isHidden: false, isHidden: false,
style: defaultStyle,
...props, ...props,
style: {
...defaultStyle,
...props.style,
},
}) })
} }

View file

@ -3,9 +3,8 @@ import { uniqueId } from 'utils'
import { RayShape, ShapeProps, ShapeType } from 'types' import { RayShape, ShapeProps, ShapeType } from 'types'
import { defaultStyle } from 'state/shape-styles' import { defaultStyle } from 'state/shape-styles'
/** /* ----------------- Start Copy Here ---------------- */
* ## Ray
*/
export default class Ray extends CodeShape<RayShape> { export default class Ray extends CodeShape<RayShape> {
constructor(props = {} as ShapeProps<RayShape>) { constructor(props = {} as ShapeProps<RayShape>) {
super({ super({

View file

@ -3,9 +3,8 @@ import { uniqueId } from 'utils'
import { RectangleShape, ShapeProps, ShapeType } from 'types' import { RectangleShape, ShapeProps, ShapeType } from 'types'
import { defaultStyle } from 'state/shape-styles' import { defaultStyle } from 'state/shape-styles'
/** /* ----------------- Start Copy Here ---------------- */
* ## Rectangle
*/
export default class Rectangle extends CodeShape<RectangleShape> { export default class Rectangle extends CodeShape<RectangleShape> {
constructor(props = {} as ShapeProps<RectangleShape>) { constructor(props = {} as ShapeProps<RectangleShape>) {
super({ super({
@ -24,7 +23,10 @@ export default class Rectangle extends CodeShape<RectangleShape> {
isLocked: false, isLocked: false,
isHidden: false, isHidden: false,
...props, ...props,
style: { ...defaultStyle, ...props.style }, style: {
...defaultStyle,
...props.style,
},
}) })
} }

View file

@ -1,9 +1,8 @@
import { Bounds } from 'types' import { Bounds } from 'types'
import vec from 'utils/vec' import vec from 'utils/vec'
/** /* ----------------- Start Copy Here ---------------- */
* ## Utils
*/
export default class Utils { export default class Utils {
/** /**
* Linear interpolation betwen two numbers. * Linear interpolation betwen two numbers.

View file

@ -1,3 +1,5 @@
/* ----------------- Start Copy Here ---------------- */
export interface VectorOptions { export interface VectorOptions {
x: number x: number
y: number y: number
@ -8,9 +10,6 @@ export interface Point {
y: number y: number
} }
/**
* ## Vector
*/
export default class Vector { export default class Vector {
x = 0 x = 0
y = 0 y = 0

View file

@ -268,11 +268,11 @@ const state = createState({
do: ['setCodeControls', 'setGeneratedShapes'], do: ['setCodeControls', 'setGeneratedShapes'],
}, },
UNDO: { UNDO: {
unless: 'isInSession', unless: ['isReadOnly', 'isInSession'],
do: 'undo', do: 'undo',
}, },
REDO: { REDO: {
unless: 'isInSession', unless: ['isReadOnly', 'isInSession'],
do: 'redo', do: 'redo',
}, },
SAVED: { SAVED: {
@ -1763,12 +1763,10 @@ const state = createState({
setSelectedIds(data, []) setSelectedIds(data, [])
try { try {
const { shapes } = updateFromCode( updateFromCode(
data, data,
data.document.code[data.currentCodeFileId].code data.document.code[data.currentCodeFileId].code
) ).then(({ shapes }) => commands.generate(data, shapes))
commands.generate(data, shapes)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} }

View file

@ -57,6 +57,8 @@ export interface PageState {
} }
} }
/* ----------------- Start Copy Here ---------------- */
export enum ShapeType { export enum ShapeType {
Dot = 'dot', Dot = 'dot',
Ellipse = 'ellipse', Ellipse = 'ellipse',
@ -383,17 +385,20 @@ export interface BaseCodeControl {
export interface NumberCodeControl extends BaseCodeControl { export interface NumberCodeControl extends BaseCodeControl {
type: ControlType.Number type: ControlType.Number
value: number
min?: number min?: number
max?: number max?: number
value: number step?: number
step: number
format?: (value: number) => number format?: (value: number) => number
} }
export interface VectorCodeControl extends BaseCodeControl { export interface VectorCodeControl extends BaseCodeControl {
type: ControlType.Vector type: ControlType.Vector
value: number[] value: number[]
isNormalized: boolean min?: number
max?: number
step?: number
isNormalized?: boolean
format?: (value: number[]) => number[] format?: (value: number[]) => number[]
} }

View file

@ -1,5 +1,7 @@
// A big collection of vector utilities. Collected into a class to improve logging / packaging. // A big collection of vector utilities. Collected into a class to improve logging / packaging.
/* ----------------- Start Copy Here ---------------- */
export default class Vec { export default class Vec {
/** /**
* Clamp a value into a range. * Clamp a value into a range.

106
yarn.lock
View file

@ -21,7 +21,7 @@
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.7.tgz#7b047d7a3a89a67d2258dc61f604f098f1bc7e08" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.7.tgz#7b047d7a3a89a67d2258dc61f604f098f1bc7e08"
integrity sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw== integrity sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==
"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.7.2", "@babel/core@^7.7.5": "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.14.6", "@babel/core@^7.4.4", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
version "7.14.6" version "7.14.6"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.6.tgz#e0814ec1a950032ff16c13a2721de39a8416fcab" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.6.tgz#e0814ec1a950032ff16c13a2721de39a8416fcab"
integrity sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA== integrity sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==
@ -637,7 +637,7 @@
"@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5"
babel-plugin-dynamic-import-node "^2.3.3" babel-plugin-dynamic-import-node "^2.3.3"
"@babel/plugin-transform-modules-commonjs@^7.14.5": "@babel/plugin-transform-modules-commonjs@^7.14.5", "@babel/plugin-transform-modules-commonjs@^7.4.4":
version "7.14.5" version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz#7aaee0ea98283de94da98b28f8c35701429dad97" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.5.tgz#7aaee0ea98283de94da98b28f8c35701429dad97"
integrity sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A== integrity sha512-en8GfBtgnydoao2PS+87mKyw62k02k7kJ9ltbKe0fXTHrQmG6QZZflYuGI1VVG7sVpx4E1n7KBpNlPb8m78J+A==
@ -1238,25 +1238,25 @@
require_optional "^1.0.1" require_optional "^1.0.1"
typeorm "^0.2.30" typeorm "^0.2.30"
"@next/env@11.0.0": "@next/env@11.0.1":
version "11.0.0" version "11.0.1"
resolved "https://registry.yarnpkg.com/@next/env/-/env-11.0.0.tgz#bdd306a45e88ba3e4e7a36aa91806f6486bb61d0" resolved "https://registry.yarnpkg.com/@next/env/-/env-11.0.1.tgz#6dc96ac76f1663ab747340e907e8933f190cc8fd"
integrity sha512-VKpmDvTYeCpEQjREg3J4pCmVs/QjEzoLmkM8shGFK6e9AmFd0G9QXOL8HGA8qKhy/XmNb7dHeMqrcMiBua4OgA== integrity sha512-yZfKh2U6R9tEYyNUrs2V3SBvCMufkJ07xMH5uWy8wqcl5gAXoEw6A/1LDqwX3j7pUutF9d1ZxpdGDA3Uag+aQQ==
"@next/eslint-plugin-next@11.0.0": "@next/eslint-plugin-next@11.0.0":
version "11.0.0" version "11.0.0"
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-11.0.0.tgz#e6fb93a00bdaba371904f2b2698b184e6278d369" resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-11.0.0.tgz#e6fb93a00bdaba371904f2b2698b184e6278d369"
integrity sha512-fPZ0904yY1box6bRpR9rJqIkNxJdvzzxH7doXS+cdjyBAdptMR7wj3mcx1hEikBHzWduU8BOXBvRg2hWc09YDQ== integrity sha512-fPZ0904yY1box6bRpR9rJqIkNxJdvzzxH7doXS+cdjyBAdptMR7wj3mcx1hEikBHzWduU8BOXBvRg2hWc09YDQ==
"@next/polyfill-module@11.0.0": "@next/polyfill-module@11.0.1":
version "11.0.0" version "11.0.1"
resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-11.0.0.tgz#cb2f46b323bbe7f8a337ccd80fb82314d4039403" resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-11.0.1.tgz#ca2a110c1c44672cbcff6c2b983f0c0549d87291"
integrity sha512-gydtFzRqsT549U8+sY8382I/f4HFcelD8gdUGnAofQJa/jEU1jkxmjCHC8tmEiyeMLidl7iDZgchfSCpmMzzUg== integrity sha512-Cjs7rrKCg4CF4Jhri8PCKlBXhszTfOQNl9AjzdNy4K5jXFyxyoSzuX2rK4IuoyE+yGp5A3XJCBEmOQ4xbUp9Mg==
"@next/react-dev-overlay@11.0.0": "@next/react-dev-overlay@11.0.1":
version "11.0.0" version "11.0.1"
resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-11.0.0.tgz#6befb4d00d952551db1b3909023074eb5778ac5d" resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-11.0.1.tgz#3c481e83347255abd466dcf7e59ac8a79a0d7fd6"
integrity sha512-q+Wp+eStEMThe77zxdeJ/nbuODkHR6P+/dfUqYXZSqbLf6x5c5xwLBauwwVbkCYFZpAlDuL8Jk8QSAH1OsqC2w== integrity sha512-lvUjMVpLsgzADs9Q8wtC5LNqvfdN+M0BDMSrqr04EDWAyyX0vURHC9hkvLbyEYWyh+WW32pwjKBXdkMnJhoqMg==
dependencies: dependencies:
"@babel/code-frame" "7.12.11" "@babel/code-frame" "7.12.11"
anser "1.4.9" anser "1.4.9"
@ -1270,10 +1270,10 @@
stacktrace-parser "0.1.10" stacktrace-parser "0.1.10"
strip-ansi "6.0.0" strip-ansi "6.0.0"
"@next/react-refresh-utils@11.0.0": "@next/react-refresh-utils@11.0.1":
version "11.0.0" version "11.0.1"
resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-11.0.0.tgz#cb671723c50b904eaa44b4b45c0845476ecd8825" resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-11.0.1.tgz#a7509f22b6f70c13101a26573afd295295f1c020"
integrity sha512-hi5eY+KBn4QGtUv7VL2OptdM33fI2hxhd7+omOFmAK+S0hDWhg1uqHqqGJk0W1IfqlWEzzL10WvTJDPRAtDugQ== integrity sha512-K347DM6Z7gBSE+TfUaTTceWvbj0B6iNAsFZXbFZOlfg3uyz2sbKpzPYYFocCc27yjLaS8OfR8DEdS2mZXi8Saw==
"@nodelib/fs.scandir@2.1.5": "@nodelib/fs.scandir@2.1.5":
version "2.1.5" version "2.1.5"
@ -1932,45 +1932,11 @@
ejs "^2.6.1" ejs "^2.6.1"
magic-string "^0.25.0" magic-string "^0.25.0"
"@testing-library/dom@^7.28.1":
version "7.31.2"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.31.2.tgz#df361db38f5212b88555068ab8119f5d841a8c4a"
integrity sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/runtime" "^7.12.5"
"@types/aria-query" "^4.2.0"
aria-query "^4.2.2"
chalk "^4.1.0"
dom-accessibility-api "^0.5.6"
lz-string "^1.4.4"
pretty-format "^26.6.2"
"@testing-library/react@^11.2.5":
version "11.2.7"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.7.tgz#b29e2e95c6765c815786c0bc1d5aed9cb2bf7818"
integrity sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==
dependencies:
"@babel/runtime" "^7.12.5"
"@testing-library/dom" "^7.28.1"
"@testing-library/user-event@^13.1.9":
version "13.1.9"
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-13.1.9.tgz#29e49a42659ac3c1023565ff56819e0153a82e99"
integrity sha512-NZr0zL2TMOs2qk+dNlqrAdbaRW5dAmYwd1yuQ4r7HpkVEOj0MWuUjDWwKhcLd/atdBy8ZSMHSKp+kXSQe47ezg==
dependencies:
"@babel/runtime" "^7.12.5"
"@tootallnate/once@1": "@tootallnate/once@1":
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
"@types/aria-query@^4.2.0":
version "4.2.1"
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.1.tgz#78b5433344e2f92e8b306c06a5622c50c245bf6b"
integrity sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14":
version "7.1.14" version "7.1.14"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402"
@ -3422,11 +3388,6 @@ doctrine@^3.0.0:
dependencies: dependencies:
esutils "^2.0.2" esutils "^2.0.2"
dom-accessibility-api@^0.5.6:
version "0.5.6"
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz#3f5d43b52c7a3bd68b5fb63fa47b4e4c1fdf65a9"
integrity sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==
domain-browser@4.19.0: domain-browser@4.19.0:
version "4.19.0" version "4.19.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1"
@ -4906,6 +4867,14 @@ jest-environment-node@^27.0.5:
jest-mock "^27.0.3" jest-mock "^27.0.3"
jest-util "^27.0.2" jest-util "^27.0.2"
jest-esm-transformer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/jest-esm-transformer/-/jest-esm-transformer-1.0.0.tgz#b6c58f496aa48194f96361a52f5c578fd2209726"
integrity sha512-FoPgeMMwy1/CEsc8tBI41i83CEO3x85RJuZi5iAMmWoARXhfgk6Jd7y+4d+z+HCkTKNVDvSWKGRhwjzU9PUbrw==
dependencies:
"@babel/core" "^7.4.4"
"@babel/plugin-transform-modules-commonjs" "^7.4.4"
jest-get-type@^26.3.0: jest-get-type@^26.3.0:
version "26.3.0" version "26.3.0"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0"
@ -5210,7 +5179,7 @@ jest-worker@^27.0.2:
merge-stream "^2.0.0" merge-stream "^2.0.0"
supports-color "^8.0.0" supports-color "^8.0.0"
jest@^27.0.4: jest@^27.0.5:
version "27.0.5" version "27.0.5"
resolved "https://registry.yarnpkg.com/jest/-/jest-27.0.5.tgz#141825e105514a834cc8d6e44670509e8d74c5f2" resolved "https://registry.yarnpkg.com/jest/-/jest-27.0.5.tgz#141825e105514a834cc8d6e44670509e8d74c5f2"
integrity sha512-4NlVMS29gE+JOZvgmSAsz3eOjkSsHqjTajlIsah/4MVSmKvf3zFP/TvgcLoWe2UVHiE9KF741sReqhF0p4mqbQ== integrity sha512-4NlVMS29gE+JOZvgmSAsz3eOjkSsHqjTajlIsah/4MVSmKvf3zFP/TvgcLoWe2UVHiE9KF741sReqhF0p4mqbQ==
@ -5626,11 +5595,6 @@ lru_map@^0.3.3:
resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=
lz-string@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=
magic-string@^0.25.0, magic-string@^0.25.7: magic-string@^0.25.0, magic-string@^0.25.7:
version "0.25.7" version "0.25.7"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
@ -5814,17 +5778,17 @@ next-pwa@^5.2.21:
workbox-webpack-plugin "^6.1.5" workbox-webpack-plugin "^6.1.5"
workbox-window "^6.1.5" workbox-window "^6.1.5"
next@latest: next@^11.0.1:
version "11.0.0" version "11.0.1"
resolved "https://registry.yarnpkg.com/next/-/next-11.0.0.tgz#866b833f192f5a94ddb3267d5cc0f4b0ce405ac7" resolved "https://registry.yarnpkg.com/next/-/next-11.0.1.tgz#b8e3914d153aaf7143cb98c09bcd3c8230eeb17a"
integrity sha512-1OA0ccCTwVtdLats/1v7ReiBVx+Akya0UVhHo9IBr8ZkpDI3/SGNcaruJBp5agy8ROF97VDKkZamoUXxRB9NUA== integrity sha512-yR7be7asNbvpVNpi6xxEg28wZ7Gqmj1nOt0sABH9qORmF3+pms2KZ7Cng33oK5nqPIzEEFJD0pp2PCe3/ueMIg==
dependencies: dependencies:
"@babel/runtime" "7.12.5" "@babel/runtime" "7.12.5"
"@hapi/accept" "5.0.2" "@hapi/accept" "5.0.2"
"@next/env" "11.0.0" "@next/env" "11.0.1"
"@next/polyfill-module" "11.0.0" "@next/polyfill-module" "11.0.1"
"@next/react-dev-overlay" "11.0.0" "@next/react-dev-overlay" "11.0.1"
"@next/react-refresh-utils" "11.0.0" "@next/react-refresh-utils" "11.0.1"
assert "2.0.0" assert "2.0.0"
ast-types "0.13.2" ast-types "0.13.2"
browserify-zlib "0.2.0" browserify-zlib "0.2.0"