diff --git a/package.json b/package.json index 80d7f5360..a52fc8373 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^1.7.13", - "@kittycad/lib": "^0.0.22", + "@kittycad/lib": "^0.0.24", "@react-hook/resize-observer": "^1.2.6", "@tauri-apps/api": "^1.3.0", "@testing-library/jest-dom": "^5.14.1", @@ -21,12 +21,14 @@ "@uiw/react-codemirror": "^4.15.1", "allotment": "^1.17.0", "crypto-js": "^4.1.1", + "formik": "^2.4.3", "http-server": "^14.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hot-toast": "^2.4.1", "react-hotkeys-hook": "^4.4.1", "react-json-view": "^1.21.3", + "react-modal": "^3.16.1", "react-modal-promise": "^1.0.2", "react-router-dom": "^6.14.2", "sketch-helpers": "^0.0.4", @@ -82,7 +84,9 @@ "@tauri-apps/cli": "^1.3.1", "@types/crypto-js": "^4.1.1", "@types/isomorphic-fetch": "^0.0.36", + "@types/react-modal": "^3.16.0", "@types/uuid": "^9.0.1", + "@types/wicg-file-system-access": "^2020.9.6", "@types/ws": "^8.5.5", "@vitejs/plugin-react": "^4.0.3", "autoprefixer": "^10.4.13", diff --git a/src/Toolbar.tsx b/src/Toolbar.tsx index e9018454a..d5450e227 100644 --- a/src/Toolbar.tsx +++ b/src/Toolbar.tsx @@ -11,6 +11,7 @@ import { SetAngleLength } from './components/Toolbar/setAngleLength' import { ConvertToVariable } from './components/Toolbar/ConvertVariable' import { SetAbsDistance } from './components/Toolbar/SetAbsDistance' import { SetAngleBetween } from './components/Toolbar/SetAngleBetween' +import { ExportButton } from './components/ExportButton' export const Toolbar = () => { const { @@ -31,6 +32,7 @@ export const Toolbar = () => { return (
+ {guiMode.mode === 'default' && ( + +
+

Export your design

+
+

+ +

+

+ +

+ + {(type === 'gltf' || type === 'ply' || type === 'stl') && ( + <> +

+ {' '} + +

+

+ +

+ + )} + +
+ +
+
+
+ + Close + +
+
+
+ + ) +} diff --git a/src/lang/std/engineConnection.ts b/src/lang/std/engineConnection.ts index a6a512e4e..0c79e79b3 100644 --- a/src/lang/std/engineConnection.ts +++ b/src/lang/std/engineConnection.ts @@ -2,6 +2,7 @@ import { SourceRange } from '../executor' import { Selections } from '../../useStore' import { VITE_KC_API_WS_MODELING_URL } from '../../env' import { Models } from '@kittycad/lib' +import { exportSave } from '../../lib/exportSave' interface ResultCommand { type: 'result' @@ -65,6 +66,10 @@ export class EngineCommandManager { }) this.socket = new WebSocket(VITE_KC_API_WS_MODELING_URL, []) + + // Change binary type from "blob" to "arraybuffer" + this.socket.binaryType = 'arraybuffer' + this.pc = new RTCPeerConnection() this.pc.createDataChannel('unreliable_modeling_cmds') this.socket.addEventListener('open', (event) => { @@ -87,15 +92,13 @@ export class EngineCommandManager { this?.socket?.addEventListener('message', (event) => { if (!this.socket || !this.pc) return - //console.log('Message from server ', event.data); - if (event.data instanceof Blob) { - const reader = new FileReader() - - reader.onload = () => { - //console.log("Result: " + reader.result); - } - - reader.readAsText(event.data) + // console.log('Message from server ', event.data); + if (event.data instanceof ArrayBuffer) { + // If the data is an ArrayBuffer, it's the result of an export command, + // because in all other cases we send JSON strings. But in the case of + // export we send a binary blob. + // Pass this to our export function. + exportSave(event.data) } else if ( typeof event.data === 'string' && event.data.toLocaleLowerCase().startsWith('error') @@ -211,6 +214,7 @@ export class EngineCommandManager { } else if (message.type === 'click') { this.onClickCallback(message) } else { + console.log('received message', message) } } }) @@ -272,6 +276,7 @@ export class EngineCommandManager { this.lossyDataChannel.send(JSON.stringify(command)) return } + console.log('sending command', command) this.socket?.send(JSON.stringify(command)) } sendModellingCommand({ diff --git a/src/lib/browserSaveFile.ts b/src/lib/browserSaveFile.ts new file mode 100644 index 000000000..54c0666e6 --- /dev/null +++ b/src/lib/browserSaveFile.ts @@ -0,0 +1,53 @@ +/// The method below uses the File System Access API when it's supported and +// else falls back to the classic approach. In both cases the function saves +// the file, but in case of where the File System Access API is supported, the +// user will get a file save dialog where they can choose where the file should be saved. +export const browserSaveFile = async (blob: Blob, suggestedName: string) => { + // Feature detection. The API needs to be supported + // and the app not run in an iframe. + const supportsFileSystemAccess = + 'showSaveFilePicker' in window && + (() => { + try { + return window.self === window.top + } catch { + return false + } + })() + // If the File System Access API is supported… + if (supportsFileSystemAccess && window.showSaveFilePicker) { + try { + // Show the file save dialog. + const handle = await window.showSaveFilePicker({ + suggestedName, + }) + // Write the blob to the file. + const writable = await handle.createWritable() + await writable.write(blob) + await writable.close() + return + } catch (err: any) { + // Fail silently if the user has simply canceled the dialog. + if (err.name !== 'AbortError') { + console.error(err.name, err.message) + return + } + } + } + // Fallback if the File System Access API is not supported… + // Create the blob URL. + const blobURL = URL.createObjectURL(blob) + // Create the `` element and append it invisibly. + const a = document.createElement('a') + a.href = blobURL + a.download = suggestedName + a.style.display = 'none' + document.body.append(a) + // Programmatically click the element. + a.click() + // Revoke the blob URL and remove the element. + setTimeout(() => { + URL.revokeObjectURL(blobURL) + a.remove() + }, 1000) +} diff --git a/src/lib/exportSave.ts b/src/lib/exportSave.ts new file mode 100644 index 000000000..c54462a9b --- /dev/null +++ b/src/lib/exportSave.ts @@ -0,0 +1,44 @@ +import { isTauri } from './isTauri' +import { deserialize_files } from '../wasm-lib/pkg/wasm_lib' +import { browserSaveFile } from './browserSaveFile' +import { save } from '@tauri-apps/api/dialog' +import { writeBinaryFile } from '@tauri-apps/api/fs' + +// Saves files locally from an export call. +export async function exportSave(data: ArrayBuffer) { + // This converts the ArrayBuffer to a Rust equivalent Vec. + let uintArray = new Uint8Array(data) + try { + const files: { contents: number[]; name: string }[] = + deserialize_files(uintArray) + for (const file of files) { + if (isTauri()) { + // Open a dialog to save the file. + const filePath = await save({ + defaultPath: file.name, + }) + + if (filePath === null) { + // The user canceled the save. + // Return early. + return + } + + // Write the file. + await writeBinaryFile(filePath, uintArray) + } else { + // Download the file to the user's computer. + // Now we need to download the files to the user's downloads folder. + // Or the destination they choose. + // Iterate over the files. + // Create a new blob. + const blob = new Blob([new Uint8Array(file.contents)]) + // Save the file. + browserSaveFile(blob, file.name) + } + } + } catch (e) { + // TODO: do something real with the error. + console.log(e) + } +} diff --git a/src/wasm-lib/Cargo.lock b/src/wasm-lib/Cargo.lock index 4e837f7cf..91c677149 100644 --- a/src/wasm-lib/Cargo.lock +++ b/src/wasm-lib/Cargo.lock @@ -11,6 +11,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bumpalo" version = "3.12.0" @@ -241,6 +250,7 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" name = "wasm-lib" version = "0.1.0" dependencies = [ + "bincode", "lazy_static", "regex", "serde", diff --git a/src/wasm-lib/Cargo.toml b/src/wasm-lib/Cargo.toml index a90c91da5..239b6f5c0 100644 --- a/src/wasm-lib/Cargo.toml +++ b/src/wasm-lib/Cargo.toml @@ -8,9 +8,10 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] +bincode = "1.3.3" lazy_static = "1.4.0" regex = "1.7.1" serde = {version = "1.0.152", features = ["derive"] } +serde-wasm-bindgen = "0.3.1" serde_json = "1.0.93" wasm-bindgen = "0.2.78" -serde-wasm-bindgen = "0.3.1" diff --git a/src/wasm-lib/src/export.rs b/src/wasm-lib/src/export.rs new file mode 100644 index 000000000..59fde44d6 --- /dev/null +++ b/src/wasm-lib/src/export.rs @@ -0,0 +1,18 @@ +//! Functions for exported files from the server. + +use serde::{Deserialize, Serialize}; +use wasm_bindgen::prelude::*; + +/// A file that has been exported from the server. +#[derive(Debug, Deserialize, Serialize)] +pub struct File { + pub name: String, + pub contents: Vec, +} + +#[wasm_bindgen] +pub fn deserialize_files(data: Vec) -> Result { + let files: Vec = bincode::deserialize(&data)?; + + Ok(serde_wasm_bindgen::to_value(&files)?) +} diff --git a/src/wasm-lib/src/lib.rs b/src/wasm-lib/src/lib.rs index 80ce05a7e..18771a250 100644 --- a/src/wasm-lib/src/lib.rs +++ b/src/wasm-lib/src/lib.rs @@ -1,3 +1,4 @@ mod abstract_syntax_tree; +mod export; mod recast; mod tokeniser; diff --git a/src/wasm-lib/src/recast.rs b/src/wasm-lib/src/recast.rs index a305556d2..539ae0749 100644 --- a/src/wasm-lib/src/recast.rs +++ b/src/wasm-lib/src/recast.rs @@ -240,8 +240,7 @@ fn recast_pipe_expression(expression: PipeExpression) -> String { let mut maybe_line_break = "\n".to_string(); let mut str = recast_value(statement.clone(), indentation.clone(), true); let non_code_meta = expression.non_code_meta.clone(); - if let Some(non_code_meta_value) = non_code_meta.none_code_nodes.get(&index) - { + if let Some(non_code_meta_value) = non_code_meta.none_code_nodes.get(&index) { if non_code_meta_value.value != " " { str += non_code_meta_value.value.as_str(); indentation = "".to_string(); @@ -325,10 +324,8 @@ pub fn recast(ast: Program, indentation: String, is_with_block: bool) -> String // determine the value of startString let last_white_space_or_comment = if index > 0 { - let tmp = if let Some(non_code_node) = ast - .non_code_meta - .none_code_nodes - .get(&(index - 1)) + let tmp = if let Some(non_code_node) = + ast.non_code_meta.none_code_nodes.get(&(index - 1)) { non_code_node.value.clone() } else { diff --git a/tsconfig.json b/tsconfig.json index 54d2ba16d..2c05a2996 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "types": ["vite/client"], + "types": ["vite/client", "@types/wicg-file-system-access"], "target": "esnext", "lib": [ "dom", diff --git a/yarn.lock b/yarn.lock index bab847a25..738146784 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1710,10 +1710,10 @@ resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60" integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA== -"@kittycad/lib@^0.0.22": - version "0.0.22" - resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.22.tgz#3d9b063c6cfe6593cdf7b61d3ffb5c1251262401" - integrity sha512-H9AS3/8Ag2fJRZqNNkbOjy/08kEqeOxWEWsmQIzJ/dNGYRD0B7Fm+UM6T8eSEkPP2+KKrIhoHMYEfGd9KjY1uQ== +"@kittycad/lib@^0.0.24": + version "0.0.24" + resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.24.tgz#afc2f0baf8b742344e86332a60e89e85804b4b30" + integrity sha512-RT3EThq0s7DQFT9+8HQ9yRgIb5+Q2xwYFYl/aNel5DdkfAya3WGlwhjv2YOtMXsy981JVpabo0HXD3tLfm/9QA== dependencies: node-fetch "3.3.2" openapi-types "^12.0.0" @@ -2113,6 +2113,13 @@ dependencies: "@types/react" "*" +"@types/react-modal@^3.16.0": + version "3.16.0" + resolved "https://registry.yarnpkg.com/@types/react-modal/-/react-modal-3.16.0.tgz#b8d6be10de894139a2ea9f4a2505b1b5d02023df" + integrity sha512-iphdqXAyUfByLbxJn5j6d+yh93dbMgshqGP0IuBeaKbZXx0aO+OXsvEkt6QctRdxjeM9/bR+Gp3h9F9djVWTQQ== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@^18.0.0": version "18.2.18" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.18.tgz#c8b233919eef1bdc294f6f34b37f9727ad677516" @@ -2154,6 +2161,11 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.2.tgz#ede1d1b1e451548d44919dc226253e32a6952c4b" integrity sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ== +"@types/wicg-file-system-access@^2020.9.6": + version "2020.9.6" + resolved "https://registry.yarnpkg.com/@types/wicg-file-system-access/-/wicg-file-system-access-2020.9.6.tgz#da34476b1e29451c8b7aa1a6db86b185647cd970" + integrity sha512-6hogE75Hl2Ov/jgp8ZhDaGmIF/q3J07GtXf8nCJCwKTHq7971po5+DId7grft09zG7plBwpF6ZU0yx9Du4/e1A== + "@types/ws@^8.5.5": version "8.5.5" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" @@ -3116,6 +3128,11 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + deepmerge@^4.2.2: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" @@ -3198,9 +3215,9 @@ domexception@^4.0.0: webidl-conversions "^7.0.0" electron-to-chromium@^1.4.477: - version "1.4.478" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.478.tgz#687198cfcef9b854a79a229feaa6cd8961206290" - integrity sha512-qjTA8djMXd+ruoODDFGnRCRBpID+AAfYWCyGtYTNhsuwxI19s8q19gbjKTwRS5z/LyVf5wICaIiPQGLekmbJbA== + version "1.4.480" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.480.tgz#40e32849ca50bc23ce29c1516c5adb3fddac919d" + integrity sha512-IXTgg+bITkQv/FLP9FjX6f9KFCs5hQWeh5uNSKxB9mqYj/JXhHDbu+ekS43LVvbkL3eW6/oZy4+r9Om6lan1Uw== emittery@^0.13.1: version "0.13.1" @@ -3653,6 +3670,11 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +exenv@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw== + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -3822,6 +3844,19 @@ formdata-polyfill@^4.0.10: dependencies: fetch-blob "^3.1.2" +formik@^2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.3.tgz#6020e85eb3e3e8415b3b19d6f4f65793ab754b24" + integrity sha512-2Dy79Szw3zlXmZiokUdKsn+n1ow4G8hRrC/n92cOWHNTWXCRpQXlyvz6HcjW7aSQZrldytvDOavYjhfmDnUq8Q== + dependencies: + deepmerge "^2.1.1" + hoist-non-react-statics "^3.3.0" + lodash "^4.17.21" + lodash-es "^4.17.21" + react-fast-compare "^2.0.1" + tiny-warning "^1.0.2" + tslib "^2.0.0" + fraction.js@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" @@ -4056,6 +4091,13 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hoist-non-react-statics@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + html-encoding-sniffer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" @@ -4963,6 +5005,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + lodash.clamp@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash.clamp/-/lodash.clamp-4.0.3.tgz#5c24bedeeeef0753560dc2b4cb4671f90a6ddfaa" @@ -5557,7 +5604,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.8.1: +prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -5621,6 +5668,11 @@ react-dom@^18.2.0: loose-envify "^1.1.0" scheduler "^0.23.0" +react-fast-compare@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" + integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== + react-hot-toast@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994" @@ -5633,7 +5685,7 @@ react-hotkeys-hook@^4.4.1: resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-4.4.1.tgz#1f7a7a1c9c21d4fa3280bf340fcca8fd77d81994" integrity sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw== -react-is@^16.13.1: +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -5658,7 +5710,7 @@ react-json-view@^1.21.3: react-lifecycles-compat "^3.0.4" react-textarea-autosize "^8.3.2" -react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== @@ -5668,6 +5720,16 @@ react-modal-promise@^1.0.2: resolved "https://registry.yarnpkg.com/react-modal-promise/-/react-modal-promise-1.0.2.tgz#122620b7f19eec73683affadfa77c543d88edc40" integrity sha512-dqT618ROhG8qh1+O6EZkia5ELw3zaZWGpMX2YfEH4bgwYENPuFonqKw1W70LFx3K/SCZvVBcD6UYEI12yzYXzg== +react-modal@^3.16.1: + version "3.16.1" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.1.tgz#34018528fc206561b1a5467fc3beeaddafb39b2b" + integrity sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg== + dependencies: + exenv "^1.2.0" + prop-types "^15.7.2" + react-lifecycles-compat "^3.0.0" + warning "^4.0.3" + react-refresh@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" @@ -6234,6 +6296,11 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" +tiny-warning@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -6336,6 +6403,11 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== + tslib@~2.4: version "2.4.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" @@ -6575,9 +6647,9 @@ vite-tsconfig-paths@^4.2.0: tsconfck "^2.1.0" vite@^4.4.3: - version "4.4.7" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.7.tgz#71b8a37abaf8d50561aca084dbb77fa342824154" - integrity sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw== + version "4.4.8" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.8.tgz#31e4a438f8748695c68bd57ffd262ba93540fdf7" + integrity sha512-LONawOUUjxQridNWGQlNizfKH89qPigK36XhMI7COMGztz8KNY0JHim7/xDd71CZwGT4HtSRgI7Hy+RlhG0Gvg== dependencies: esbuild "^0.18.10" postcss "^8.4.26" @@ -6604,6 +6676,13 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" +warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + wasm-pack@^0.12.1: version "0.12.1" resolved "https://registry.yarnpkg.com/wasm-pack/-/wasm-pack-0.12.1.tgz#974c1fbbf5b65c9e135e0d1fba3a97de1a21a489"