Implement "floating windows" style UI (#224)

* Basic transparent pane styling

* HTML and static asset cleanup

* Convert to collapsibles

* Polish up DebugPanel

* Add hotkey support, remove allotment

* Remove allotment css dependency

* Merge in from main

* Add a different resizable package

* Fix tsc errors introduced by merge

* Stream has to have at least z-index of 0

* App header has to be above stream z-index

* Applied z-index to the wrong element

* Scrollable logs, disable UI while dragging

* Fix test errors from importing CSS Modules in Jest

* Persist open panes configuration

* Style tweaks and fix camera step in onboarding

* Kurt review, make click-drag handler declarative
This commit is contained in:
Frank Noirot
2023-08-06 21:29:26 -04:00
committed by GitHub
parent 4c5178ea5c
commit 391f4ba206
21 changed files with 619 additions and 258 deletions

View File

@ -7,38 +7,15 @@
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
content="An open-source CAD modeling tool from the future by KittyCAD."
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="/manifest.json" />
<!--
Notice the use of in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>KittyCAD Modeling App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

View File

@ -6,6 +6,7 @@ const config: Config = {
transform: {
'^.+\\.(ts|tsx)?$': 'ts-jest',
'^.+\\.(js|jsx)$': 'babel-jest',
'^.+\\.css$': ["jest-transform-css", { modules: true, generateScopedName: "[path]_[name]_[local]" }],
},
transformIgnorePatterns: ['//node_modules/(?!(allotment|@tauri-apps/api)/)'],
moduleNameMapper: {

View File

@ -19,10 +19,10 @@
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@uiw/react-codemirror": "^4.15.1",
"allotment": "^1.17.0",
"crypto-js": "^4.1.1",
"formik": "^2.4.3",
"http-server": "^14.1.1",
"re-resizable": "^6.9.9",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
@ -80,6 +80,7 @@
]
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.22.9",
"@tauri-apps/cli": "^1.3.1",
"@types/crypto-js": "^4.1.1",
@ -98,6 +99,7 @@
"isomorphic-fetch": "^3.0.0",
"jest": "^29.6.1",
"jest-environment-jsdom": "^29.6.1",
"jest-transform-css": "^6.0.1",
"postcss": "^8.4.19",
"prettier": "^2.8.0",
"setimmediate": "^1.0.5",

BIN
public/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
public/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,6 +1,6 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "KCMA",
"name": "KittyCAD Modeling App",
"icons": [
{
"src": "favicon.ico",

View File

@ -1,6 +1,12 @@
import { useRef, useEffect, useMemo } from 'react'
import { Allotment } from 'allotment'
import {
useRef,
useEffect,
useMemo,
useCallback,
MouseEventHandler,
} from 'react'
import { DebugPanel } from './components/DebugPanel'
import { v4 as uuidv4 } from 'uuid'
import { asyncLexer } from './lang/tokeniser'
import { abstractSyntaxTree } from './lang/abstractSyntaxTree'
import { _executor, ExtrudeGroup, SketchGroup } from './lang/executor'
@ -12,18 +18,27 @@ import {
lineHighlightField,
addLineHighlight,
} from './editor/highlightextension'
import { Selections, useStore } from './useStore'
import { PaneType, Selections, useStore } from './useStore'
import { Logs, KCLErrors } from './components/Logs'
import { PanelHeader } from './components/PanelHeader'
import { CollapsiblePanel } from './components/CollapsiblePanel'
import { MemoryPanel } from './components/MemoryPanel'
import { useHotKeyListener } from './hooks/useHotKeyListener'
import { Stream } from './components/Stream'
import ModalContainer from 'react-modal-promise'
import { EngineCommandManager } from './lang/std/engineConnection'
import { isOverlap } from './lib/utils'
import {
EngineCommand,
EngineCommandManager,
} from './lang/std/engineConnection'
import { isOverlap, throttle } from './lib/utils'
import { AppHeader } from './components/AppHeader'
import { isTauri } from './lib/isTauri'
import { KCLError, kclErrToDiagnostic } from './lang/errors'
import { Resizable } from 're-resizable'
import {
faCode,
faCodeCommit,
faSquareRootVariable,
} from '@fortawesome/free-solid-svg-icons'
import { useHotkeys } from 'react-hotkeys-hook'
export function App() {
const cam = useRef()
@ -52,10 +67,17 @@ export function App() {
setMediaStream,
setIsStreamReady,
isStreamReady,
isMouseDownInStream,
fileId,
cmdId,
setCmdId,
token,
formatCode,
debugPanel,
theme,
openPanes,
setOpenPanes,
onboardingStatus,
} = useStore((s) => ({
editorView: s.editorView,
setEditorView: s.setEditorView,
@ -82,12 +104,36 @@ export function App() {
setMediaStream: s.setMediaStream,
isStreamReady: s.isStreamReady,
setIsStreamReady: s.setIsStreamReady,
isMouseDownInStream: s.isMouseDownInStream,
fileId: s.fileId,
cmdId: s.cmdId,
setCmdId: s.setCmdId,
token: s.token,
formatCode: s.formatCode,
debugPanel: s.debugPanel,
addKCLError: s.addKCLError,
theme: s.theme,
openPanes: s.openPanes,
setOpenPanes: s.setOpenPanes,
onboardingStatus: s.onboardingStatus,
}))
// Pane toggling keyboard shortcuts
const togglePane = useCallback(
(newPane: PaneType) =>
openPanes.includes(newPane)
? setOpenPanes(openPanes.filter((p) => p !== newPane))
: setOpenPanes([...openPanes, newPane]),
[openPanes, setOpenPanes]
)
useHotkeys('shift + c', () => togglePane('code'))
useHotkeys('shift + v', () => togglePane('variables'))
useHotkeys('shift + l', () => togglePane('logs'))
useHotkeys('shift + e', () => togglePane('kclErrors'))
useHotkeys('shift + d', () => togglePane('debug'))
const paneOpacity = onboardingStatus === 'camera' ? 'opacity-20' : ''
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
const onChange = (value: string, viewUpdate: ViewUpdate) => {
setCode(value)
@ -270,14 +316,75 @@ export function App() {
asyncWrap()
}, [code, isStreamReady])
const debounceSocketSend = throttle<EngineCommand>((message) => {
engineCommandManager?.sendSceneCommand(message)
}, 16)
const handleMouseMove = useCallback<MouseEventHandler<HTMLDivElement>>(
({ clientX, clientY, ctrlKey, currentTarget }) => {
if (!cmdId) return
if (!isMouseDownInStream) return
const { left, top } = currentTarget.getBoundingClientRect()
const x = clientX - left
const y = clientY - top
const interaction = ctrlKey ? 'pan' : 'rotate'
const newCmdId = uuidv4()
setCmdId(newCmdId)
debounceSocketSend({
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_move',
interaction,
window: { x, y },
},
cmd_id: newCmdId,
file_id: fileId,
})
},
[debounceSocketSend, isMouseDownInStream, cmdId, fileId, setCmdId]
)
return (
<div className="h-screen">
<AppHeader />
<div
className="h-screen relative flex flex-col"
onMouseMove={handleMouseMove}
>
<AppHeader
className={
paneOpacity + (isMouseDownInStream ? ' pointer-events-none' : '')
}
/>
<ModalContainer />
<Allotment snap={true}>
<Allotment vertical defaultSizes={[400, 1, 1, 200]} minSize={20}>
<div className="h-full flex flex-col items-start">
<PanelHeader title="Editor" />
<Resizable
className={
'z-10 my-5 ml-5 pr-1 flex flex-col flex-grow overflow-hidden' +
(isMouseDownInStream || onboardingStatus === 'camera'
? ' pointer-events-none '
: ' ') +
paneOpacity
}
defaultSize={{
width: '400px',
height: 'auto',
}}
minWidth={200}
maxWidth={600}
minHeight={'auto'}
maxHeight={'auto'}
handleClasses={{
right:
'hover:bg-liquid-30/40 dark:hover:bg-liquid-10/40 bg-transparent transition-colors duration-100 transition-ease-out delay-100',
}}
>
<CollapsiblePanel
title="Code"
icon={faCode}
className="open:!mb-2"
open={openPanes.includes('code')}
>
<div className="px-2 py-1">
<button
// disabled={!shouldFormat}
onClick={formatCode}
@ -285,10 +392,8 @@ export function App() {
>
format
</button>
<div
className="bg-red h-full w-full overflow-auto"
id="code-mirror-override"
>
</div>
<div id="code-mirror-override">
<CodeMirror
className="h-full"
value={code}
@ -306,16 +411,38 @@ export function App() {
onCreateEditor={(_editorView) => setEditorView(_editorView)}
/>
</div>
</div>
<MemoryPanel />
<Logs />
<KCLErrors />
</Allotment>
<Allotment vertical defaultSizes={[40, 400]} minSize={20}>
<Stream />
</Allotment>
{debugPanel && <DebugPanel />}
</Allotment>
</CollapsiblePanel>
<section className="flex flex-col mt-auto">
<MemoryPanel
theme={theme}
open={openPanes.includes('variables')}
title="Variables"
icon={faSquareRootVariable}
/>
<Logs
theme={theme}
open={openPanes.includes('logs')}
title="Logs"
icon={faCodeCommit}
/>
<KCLErrors
theme={theme}
open={openPanes.includes('kclErrors')}
title="KCL Errors"
iconClassNames={{ icon: 'group-open:text-destroy-30' }}
/>
</section>
</Resizable>
<Stream className="absolute inset-0 z-0" />
{debugPanel && (
<DebugPanel
title="Debug"
className={
paneOpacity + (isMouseDownInStream ? ' pointer-events-none' : '')
}
open={openPanes.includes('debug')}
/>
)}
</div>
)
}

View File

@ -5,15 +5,25 @@ import UserSidebarMenu from './UserSidebarMenu'
interface AppHeaderProps extends React.PropsWithChildren {
showToolbar?: boolean
className?: string
}
export const AppHeader = ({ showToolbar = true, children }: AppHeaderProps) => {
export const AppHeader = ({
showToolbar = true,
children,
className = '',
}: AppHeaderProps) => {
const { user } = useStore((s) => ({
user: s.user,
}))
return (
<header className="py-1 px-5 bg-chalkboard-10 dark:bg-chalkboard-100 border-b dark:border-b-2 border-chalkboard-30 dark:border-chalkboard-70 flex justify-between items-center">
<header
className={
'overlaid-panes z-10 py-1 px-5 bg-chalkboard-10/50 dark:bg-chalkboard-100/50 border-b dark:border-b-2 border-chalkboard-30 dark:border-chalkboard-90 flex justify-between items-center ' +
className
}
>
<Link to="/">
<img
src="/kitt-arcade-winking.svg"

View File

@ -0,0 +1,52 @@
.panel {
@apply relative overflow-auto z-0;
@apply bg-chalkboard-20/40;
}
:global(.dark) .panel {
@apply bg-chalkboard-110/50;
}
.header {
@apply sticky top-0 z-10 cursor-pointer;
@apply flex items-center gap-2 w-full p-2;
@apply font-mono text-xs font-bold select-none text-chalkboard-90;
@apply bg-chalkboard-20;
}
.header:not(:last-of-type) {
@apply border-b;
}
:global(.dark) .header {
@apply bg-chalkboard-110 border-b-chalkboard-90 text-chalkboard-30;
}
:global(.dark) .header:not(:last-of-type) {
@apply border-b-2;
}
.panel:first-of-type .header {
@apply rounded-t;
}
.panel:last-of-type .header {
@apply rounded-b;
}
.panel[open] .header {
@apply rounded-t rounded-b-none;
}
.panel[open] {
@apply flex-grow max-h-full h-48 my-1 rounded;
}
.panel[open] + .panel[open],
.panel[open]:first-of-type {
@apply mt-0;
}
.panel[open]:last-of-type {
@apply mb-0;
}

View File

@ -0,0 +1,57 @@
import { IconDefinition } from '@fortawesome/free-solid-svg-icons'
import { ActionIcon } from './ActionIcon'
import styles from './CollapsiblePanel.module.css'
export interface CollapsiblePanelProps
extends React.PropsWithChildren,
React.HTMLAttributes<HTMLDetailsElement> {
title: string
icon?: IconDefinition
open?: boolean
iconClassNames?: {
bg?: string
icon?: string
}
}
export const PanelHeader = ({
title,
icon,
iconClassNames,
}: CollapsiblePanelProps) => {
return (
<summary className={styles.header}>
<ActionIcon
icon={icon}
bgClassName={
'bg-chalkboard-30 dark:bg-chalkboard-90 group-open:bg-chalkboard-80 rounded ' +
(iconClassNames?.bg || '')
}
iconClassName={
'text-chalkboard-90 dark:text-chalkboard-40 group-open:text-liquid-10 ' +
(iconClassNames?.icon || '')
}
/>
{title}
</summary>
)
}
export const CollapsiblePanel = ({
title,
icon,
children,
className,
iconClassNames,
...props
}: CollapsiblePanelProps) => {
return (
<details
{...props}
className={styles.panel + ' group ' + (className || '')}
>
<PanelHeader title={title} icon={icon} iconClassNames={iconClassNames} />
{children}
</details>
)
}

View File

@ -1,4 +1,4 @@
import { PanelHeader } from '../components/PanelHeader'
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
import { useStore } from '../useStore'
import { v4 as uuidv4 } from 'uuid'
import { EngineCommand } from '../lang/std/engineConnection'
@ -11,7 +11,7 @@ type SketchModeCmd = Extract<
{ type: 'default_camera_enable_sketch_mode' }
>
export const DebugPanel = () => {
export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => {
const { engineCommandManager } = useStore((s) => ({
engineCommandManager: s.engineCommandManager,
}))
@ -25,15 +25,30 @@ export const DebugPanel = () => {
})
if (!sketchModeCmd) return null
return (
<div>
<PanelHeader title="Debug" />
<Xyz onChange={setSketchModeCmd} pointKey="origin" data={sketchModeCmd} />
<Xyz onChange={setSketchModeCmd} pointKey="x_axis" data={sketchModeCmd} />
<Xyz onChange={setSketchModeCmd} pointKey="y_axis" data={sketchModeCmd} />
<CollapsiblePanel
{...props}
className={'!absolute !h-auto bottom-5 right-5 ' + className}
>
<section className="p-4 flex flex-col gap-4">
<Xyz
onChange={setSketchModeCmd}
pointKey="origin"
data={sketchModeCmd}
/>
<Xyz
onChange={setSketchModeCmd}
pointKey="x_axis"
data={sketchModeCmd}
/>
<Xyz
onChange={setSketchModeCmd}
pointKey="y_axis"
data={sketchModeCmd}
/>
<div className="flex">
<div className="pr-4">distance_to_plane</div>
<input
className="w-16"
className="w-16 dark:bg-chalkboard-90"
type="number"
value={sketchModeCmd.distance_to_plane}
onChange={({ target }) => {
@ -77,7 +92,8 @@ export const DebugPanel = () => {
>
Send sketch mode command
</ActionButton>
</div>
</section>
</CollapsiblePanel>
)
}
@ -99,7 +115,7 @@ const Xyz = ({
<div key={axis} className="flex">
<div className="w-4">{axis}</div>
<input
className="w-16"
className="w-16 dark:bg-chalkboard-90"
type="number"
value={val}
onChange={({ target }) => {

View File

@ -1,14 +1,17 @@
import ReactJson from 'react-json-view'
import { useEffect } from 'react'
import { useStore } from '../useStore'
import { PanelHeader } from './PanelHeader'
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
const ReactJsonTypeHack = ReactJson as any
export const Logs = () => {
const { logs, resetLogs } = useStore(({ logs, resetLogs }) => ({
interface LogPanelProps extends CollapsiblePanelProps {
theme?: 'light' | 'dark'
}
export const Logs = ({ theme = 'light', ...props }: LogPanelProps) => {
const { logs } = useStore(({ logs }) => ({
logs,
resetLogs,
}))
useEffect(() => {
const element = document.querySelector('.console-tile')
@ -17,10 +20,9 @@ export const Logs = () => {
}
}, [logs])
return (
<div>
<PanelHeader title="Logs" />
<div className="h-full relative">
<div className="absolute inset-0 flex flex-col items-start">
<CollapsiblePanel {...props}>
<div className="relative w-full">
<div className="absolute inset-0 flex flex-col">
<ReactJsonTypeHack
src={logs}
collapsed={1}
@ -32,14 +34,15 @@ export const Logs = () => {
indentWidth={2}
quotesOnKeys={false}
name={false}
theme={theme === 'light' ? 'rjv-default' : 'monokai'}
/>
</div>
</div>
</div>
</CollapsiblePanel>
)
}
export const KCLErrors = () => {
export const KCLErrors = ({ theme = 'light', ...props }: LogPanelProps) => {
const { kclErrors } = useStore(({ kclErrors }) => ({
kclErrors,
}))
@ -50,10 +53,9 @@ export const KCLErrors = () => {
}
}, [kclErrors])
return (
<div>
<PanelHeader title="KCL Errors" />
<CollapsiblePanel {...props}>
<div className="h-full relative">
<div className="absolute inset-0 flex flex-col items-start">
<div className="absolute inset-0 flex flex-col">
<ReactJsonTypeHack
src={kclErrors}
collapsed={1}
@ -65,9 +67,10 @@ export const KCLErrors = () => {
indentWidth={2}
quotesOnKeys={false}
name={false}
theme={theme === 'light' ? 'rjv-default' : 'monokai'}
/>
</div>
</div>
</div>
</CollapsiblePanel>
)
}

View File

@ -1,10 +1,17 @@
import ReactJson from 'react-json-view'
import { PanelHeader } from './PanelHeader'
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
import { useStore } from '../useStore'
import { useMemo } from 'react'
import { ProgramMemory } from '../lang/executor'
export const MemoryPanel = () => {
interface MemoryPanelProps extends CollapsiblePanelProps {
theme?: 'light' | 'dark'
}
export const MemoryPanel = ({
theme = 'light',
...props
}: MemoryPanelProps) => {
const { programMemory } = useStore((s) => ({
programMemory: s.programMemory,
}))
@ -13,11 +20,10 @@ export const MemoryPanel = () => {
[programMemory]
)
return (
<div className="h-full">
<PanelHeader title="Variables" />
<CollapsiblePanel {...props}>
<div className="h-full relative">
<div className="absolute inset-0 flex flex-col items-start">
<div className=" overflow-auto h-full console-tile w-full">
<div className=" h-full console-tile w-full">
<ReactJson
src={ProcessedMemory}
collapsed={1}
@ -28,11 +34,12 @@ export const MemoryPanel = () => {
indentWidth={2}
quotesOnKeys={false}
name={false}
theme={theme === 'light' ? 'rjv-default' : 'monokai'}
/>
</div>
</div>
</div>
</div>
</CollapsiblePanel>
)
}

View File

@ -1,7 +0,0 @@
export const PanelHeader = ({ title }: { title: string }) => {
return (
<div className="font-mono text-[11px] bg-chalkboard-20 dark:bg-chalkboard-110 dark:border-b-2 dark:border-b-chalkboard-90 w-full pl-4 h-[20px] flex items-center">
<span className="pt-1">{title}</span>
</div>
)
}

View File

@ -1,16 +1,24 @@
import { MouseEventHandler, useEffect, useRef } from 'react'
import { PanelHeader } from '../components/PanelHeader'
import { v4 as uuidv4 } from 'uuid'
import { useStore } from '../useStore'
import { throttle } from '../lib/utils'
import { EngineCommand } from '../lang/std/engineConnection'
export const Stream = () => {
export const Stream = ({ className = '' }) => {
const videoRef = useRef<HTMLVideoElement>(null)
const cmdId = useRef('')
const { mediaStream, engineCommandManager } = useStore((s) => ({
const {
mediaStream,
engineCommandManager,
setIsMouseDownInStream,
fileId,
setFileId,
setCmdId,
} = useStore((s) => ({
mediaStream: s.mediaStream,
engineCommandManager: s.engineCommandManager,
isMouseDownInStream: s.isMouseDownInStream,
setIsMouseDownInStream: s.setIsMouseDownInStream,
fileId: s.fileId,
setFileId: s.setFileId,
setCmdId: s.setCmdId,
}))
useEffect(() => {
@ -22,36 +30,8 @@ export const Stream = () => {
if (!videoRef.current) return
if (!mediaStream) return
videoRef.current.srcObject = mediaStream
}, [mediaStream, engineCommandManager])
const file_id = uuidv4()
const debounceSocketSend = throttle<EngineCommand>((message) => {
engineCommandManager?.sendSceneCommand(message)
}, 16)
const handleMouseMove: MouseEventHandler<HTMLVideoElement> = ({
clientX,
clientY,
ctrlKey,
}) => {
if (!videoRef.current) return
if (!cmdId.current) return
const { left, top } = videoRef.current.getBoundingClientRect()
const x = clientX - left
const y = clientY - top
const interaction = ctrlKey ? 'pan' : 'rotate'
debounceSocketSend({
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_move',
interaction,
window: { x, y },
},
cmd_id: uuidv4(),
file_id: file_id,
})
}
setFileId(uuidv4())
}, [mediaStream, engineCommandManager, setFileId])
const handleMouseDown: MouseEventHandler<HTMLVideoElement> = ({
clientX,
@ -65,7 +45,7 @@ export const Stream = () => {
console.log('click', x, y)
const newId = uuidv4()
cmdId.current = newId
setCmdId(newId)
const interaction = ctrlKey ? 'pan' : 'rotate'
@ -77,9 +57,12 @@ export const Stream = () => {
window: { x, y },
},
cmd_id: newId,
file_id,
file_id: fileId,
})
setIsMouseDownInStream(true)
}
const handleMouseUp: MouseEventHandler<HTMLVideoElement> = ({
clientX,
clientY,
@ -90,9 +73,8 @@ export const Stream = () => {
const x = clientX - left
const y = clientY - top
if (cmdId.current == null) {
return
}
const newCmdId = uuidv4()
setCmdId(newCmdId)
const interaction = ctrlKey ? 'pan' : 'rotate'
@ -103,26 +85,27 @@ export const Stream = () => {
interaction,
window: { x, y },
},
cmd_id: uuidv4(),
file_id: file_id,
cmd_id: newCmdId,
file_id: fileId,
})
cmdId.current = ''
setCmdId('')
setIsMouseDownInStream(false)
}
return (
<div id="stream">
<PanelHeader title="Stream" />
<div id="stream" className={className}>
<video
ref={videoRef}
muted
autoPlay
controls={false}
onMouseMove={handleMouseMove}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
onMouseLeave={handleMouseUp}
onContextMenu={(e) => e.preventDefault()}
onContextMenuCapture={(e) => e.preventDefault()}
className="w-full h-full"
/>
</div>
)

View File

@ -55,9 +55,9 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
Menu
</ActionButton>
)}
<Popover.Overlay className="fixed z-20 inset-0 bg-chalkboard-110/50" />
<Popover.Overlay className="fixed z-40 inset-0 bg-chalkboard-110/50" />
<Popover.Panel className="fixed inset-0 left-auto z-30 w-64 bg-chalkboard-10 dark:bg-chalkboard-100 border border-liquid-100 shadow-md rounded-l-lg">
<Popover.Panel className="fixed inset-0 left-auto z-50 w-64 bg-chalkboard-10 dark:bg-chalkboard-100 border border-liquid-100 shadow-md rounded-l-lg">
{user && (
<div className="flex items-center gap-4 px-4 py-3 bg-liquid-100">
{user.image && !imageLoadFailed && (

View File

@ -1,4 +1,3 @@
@import '../node_modules/allotment/dist/style.css';
@import './colors.css';
@tailwind base;
@ -13,12 +12,32 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@apply text-chalkboard-110 bg-chalkboard-10;
scrollbar-width: thin;
scrollbar-color: var(--color-chalkboard-20) var(--color-chalkboard-40);
}
body.dark {
scrollbar-color: var(--color-chalkboard-70) var(--color-chalkboard-90);
@apply bg-chalkboard-100 text-chalkboard-10;
}
::-webkit-scrollbar {
@apply w-2 rounded-sm;
@apply bg-chalkboard-20;
}
::-webkit-scrollbar-thumb {
@apply bg-chalkboard-40 rounded-sm;
}
.dark ::-webkit-scrollbar {
@apply bg-chalkboard-90;
}
.dark ::-webkit-scrollbar-thumb {
@apply bg-chalkboard-70;
}
button {
@apply border border-chalkboard-100 m-0.5 px-3 rounded text-xs;
}
@ -45,6 +64,18 @@ code {
monospace;
}
#code-mirror-override .cm-editor {
@apply bg-transparent;
}
#code-mirror-override .cm-gutters {
@apply bg-chalkboard-10/50;
}
.dark #code-mirror-override .cm-gutters {
@apply bg-chalkboard-110/50;
}
#code-mirror-override .cm-focused .cm-cursor {
width: 0px;
}
@ -59,3 +90,7 @@ code {
transparent 100%
);
}
.react-json-view {
@apply bg-transparent !important;
}

View File

@ -4,6 +4,7 @@ import reportWebVitals from './reportWebVitals'
import { Toaster } from 'react-hot-toast'
import { useStore } from './useStore'
import { Router } from './Router'
import { HotkeysProvider } from 'react-hotkeys-hook'
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
function setThemeClass(state: Partial<{ theme: string }>) {
@ -18,7 +19,7 @@ setThemeClass({ theme })
useStore.subscribe(setThemeClass)
root.render(
<>
<HotkeysProvider>
<Router />
<Toaster
position="bottom-center"
@ -27,7 +28,7 @@ root.render(
'bg-chalkboard-10 dark:bg-chalkboard-90 text-chalkboard-110 dark:text-chalkboard-10',
}}
/>
</>
</HotkeysProvider>
)
// If you want to start measuring performance in your app, pass a function

View File

@ -1,19 +1,23 @@
import { faArrowRight, faXmark } from '@fortawesome/free-solid-svg-icons'
import { ActionButton } from '../../components/ActionButton'
import { useDismiss, useNextClick } from '.'
import { useBackdropHighlight } from '../../hooks/useBackdropHighlight'
import { useStore } from '../../useStore'
const Units = () => {
const { isMouseDownInStream } = useStore((s) => ({
isMouseDownInStream: s.isMouseDownInStream,
}))
const dismiss = useDismiss()
const next = useNextClick('sketching')
const clipPath = useBackdropHighlight('stream')
return (
<div className="fixed grid justify-center items-end inset-0 z-50 pointer-events-none">
<div
className="fixed grid justify-center items-end inset-0 bg-chalkboard-110/50 dark:bg-chalkboard-110/80 z-50"
style={{ clipPath }}
className={
'max-w-2xl flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(isMouseDownInStream ? '' : ' pointer-events-auto')
}
>
<div className="max-w-2xl flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded">
<h1 className="text-2xl font-bold">Camera</h1>
<p className="mt-6">
Moving the camera is easy. Just click and drag anywhere in the scene

View File

@ -108,6 +108,8 @@ interface DefaultDir {
dir: string
}
export type PaneType = 'code' | 'variables' | 'debug' | 'kclErrors' | 'logs'
// TODO: import real OpenAPI User type from schema
export interface User {
company?: string
@ -175,6 +177,12 @@ export interface StoreState {
setMediaStream: (mediaStream: MediaStream) => void
isStreamReady: boolean
setIsStreamReady: (isStreamReady: boolean) => void
isMouseDownInStream: boolean
setIsMouseDownInStream: (isMouseDownInStream: boolean) => void
cmdId?: string
setCmdId: (cmdId: string) => void
fileId: string
setFileId: (fileId: string) => void
// tauri specific app settings
defaultDir: DefaultDir
@ -191,6 +199,8 @@ export interface StoreState {
setOnboardingStatus: (status: string) => void
theme: 'light' | 'dark'
setTheme: (theme: 'light' | 'dark') => void
openPanes: PaneType[]
setOpenPanes: (panes: PaneType[]) => void
homeMenuItems: {
name: string
path: string
@ -352,6 +362,15 @@ export const useStore = create<StoreState>()(
setMediaStream: (mediaStream) => set({ mediaStream }),
isStreamReady: false,
setIsStreamReady: (isStreamReady) => set({ isStreamReady }),
isMouseDownInStream: false,
setIsMouseDownInStream: (isMouseDownInStream) => {
set({ isMouseDownInStream })
},
// For stream event handling
cmdId: undefined,
setCmdId: (cmdId) => set({ cmdId }),
fileId: '',
setFileId: (fileId) => set({ fileId }),
// tauri specific app settings
defaultDir: {
@ -374,6 +393,8 @@ export const useStore = create<StoreState>()(
? 'dark'
: 'light',
setTheme: (theme) => set({ theme }),
openPanes: ['code'],
setOpenPanes: (openPanes) => set({ openPanes }),
showHomeMenu: true,
setHomeShowMenu: (showHomeMenu) => set({ showHomeMenu }),
homeMenuItems: [],
@ -400,6 +421,7 @@ export const useStore = create<StoreState>()(
'debugPanel',
'onboardingStatus',
'theme',
'openPanes',
].includes(key)
)
),

161
yarn.lock
View File

@ -77,7 +77,7 @@
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/helper-annotate-as-pure@^7.22.5":
"@babel/helper-annotate-as-pure@^7.18.6", "@babel/helper-annotate-as-pure@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882"
integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==
@ -102,7 +102,7 @@
lru-cache "^5.1.1"
semver "^6.3.1"
"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.22.5", "@babel/helper-create-class-features-plugin@^7.22.6", "@babel/helper-create-class-features-plugin@^7.22.9":
"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0", "@babel/helper-create-class-features-plugin@^7.22.5", "@babel/helper-create-class-features-plugin@^7.22.6", "@babel/helper-create-class-features-plugin@^7.22.9":
version "7.22.9"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz#c36ea240bb3348f942f08b0fbe28d6d979fab236"
integrity sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==
@ -353,6 +353,16 @@
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703"
integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==
"@babel/plugin-proposal-private-property-in-object@^7.21.11":
version "7.21.11"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz#69d597086b6760c4126525cfa154f34631ff272c"
integrity sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.18.6"
"@babel/helper-create-class-features-plugin" "^7.21.0"
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
"@babel/plugin-proposal-unicode-property-regex@^7.4.4":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e"
@ -2356,18 +2366,6 @@ ajv@^6.12.4:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
allotment@^1.17.0:
version "1.19.2"
resolved "https://registry.yarnpkg.com/allotment/-/allotment-1.19.2.tgz#6026a944678958c961dafcfefe9a768af4d6610e"
integrity sha512-RiiCLa4AQATPsQDXvleyvdRzSsd2J7naLuY+eK1sn1zeXBKMdsCwWuICZ+ZCeDCrJXjVV+q/mHfB2LT7PEYmTw==
dependencies:
classnames "^2.3.0"
eventemitter3 "^5.0.0"
lodash.clamp "^4.0.0"
lodash.debounce "^4.0.0"
lodash.isequal "^4.5.0"
use-resize-observer "^9.0.0"
ansi-escapes@^4.2.1:
version "4.3.2"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
@ -2872,11 +2870,6 @@ cjs-module-lexer@^1.0.0:
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107"
integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==
classnames@^2.3.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
client-only@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
@ -2950,6 +2943,11 @@ commander@^4.0.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
common-tags@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6"
integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -3010,7 +3008,7 @@ cross-fetch@^3.1.5:
dependencies:
node-fetch "^2.6.12"
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
cross-spawn@7.0.3, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@ -3650,11 +3648,6 @@ eventemitter3@^4.0.0:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
eventemitter3@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
execa@^5.0.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
@ -3899,6 +3892,13 @@ functions-have-names@^1.2.2, functions-have-names@^1.2.3:
resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
generic-names@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-4.0.0.tgz#0bd8a2fd23fe8ea16cbd0a279acd69c06933d9a3"
integrity sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==
dependencies:
loader-utils "^3.2.0"
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
@ -4172,6 +4172,16 @@ iconv-lite@0.6.3:
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
integrity sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==
icss-utils@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
ignore@^5.2.0:
version "5.2.4"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
@ -4789,6 +4799,17 @@ jest-snapshot@^29.6.2:
pretty-format "^29.6.2"
semver "^7.5.3"
jest-transform-css@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/jest-transform-css/-/jest-transform-css-6.0.1.tgz#95c579c98945734439c1f243b9843d5f477a9c60"
integrity sha512-i78Pi2MW6vcdsUFSRx1kPbjbEIO0pBWwh1Y+PcDrLwTv/6e5p7fzsV/gxFW/SYMHS8DUvMdRVTwVCkA/y+t0iQ==
dependencies:
common-tags "1.8.2"
cross-spawn "7.0.3"
postcss-load-config "4.0.1"
postcss-modules "4.3.1"
style-inject "0.3.0"
jest-util@^29.0.0, jest-util@^29.6.2:
version "29.6.2"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d"
@ -4991,6 +5012,11 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
loader-utils@^3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.1.tgz#4fb104b599daafd82ef3e1a41fb9265f87e1f576"
integrity sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
@ -5010,17 +5036,17 @@ lodash-es@^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"
integrity sha512-HvzRFWjtcguTW7yd8NJBshuNaCa8aqNFtnswdT7f/cMd/1YKy5Zzoq4W/Oxvnx9l7aeY258uSdDfM793+eLsVg==
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
lodash.curry@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
integrity sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==
lodash.debounce@^4.0.0, lodash.debounce@^4.0.8:
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
@ -5030,11 +5056,6 @@ lodash.flow@^3.3.0:
resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
integrity sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
lodash.memoize@4.x:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@ -5524,7 +5545,7 @@ postcss-js@^4.0.1:
dependencies:
camelcase-css "^2.0.1"
postcss-load-config@^4.0.1:
postcss-load-config@4.0.1, postcss-load-config@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.1.tgz#152383f481c2758274404e4962743191d73875bd"
integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==
@ -5532,6 +5553,48 @@ postcss-load-config@^4.0.1:
lilconfig "^2.0.5"
yaml "^2.1.1"
postcss-modules-extract-imports@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==
postcss-modules-local-by-default@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524"
integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==
dependencies:
icss-utils "^5.0.0"
postcss-selector-parser "^6.0.2"
postcss-value-parser "^4.1.0"
postcss-modules-scope@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06"
integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==
dependencies:
postcss-selector-parser "^6.0.4"
postcss-modules-values@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
dependencies:
icss-utils "^5.0.0"
postcss-modules@4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-4.3.1.tgz#517c06c09eab07d133ae0effca2c510abba18048"
integrity sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==
dependencies:
generic-names "^4.0.0"
icss-replace-symbols "^1.1.0"
lodash.camelcase "^4.3.0"
postcss-modules-extract-imports "^3.0.0"
postcss-modules-local-by-default "^4.0.0"
postcss-modules-scope "^3.0.0"
postcss-modules-values "^4.0.0"
string-hash "^1.1.1"
postcss-nested@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c"
@ -5539,7 +5602,7 @@ postcss-nested@^6.0.1:
dependencies:
postcss-selector-parser "^6.0.11"
postcss-selector-parser@^6.0.11:
postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
version "6.0.13"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b"
integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==
@ -5547,7 +5610,7 @@ postcss-selector-parser@^6.0.11:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@ -5650,6 +5713,11 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
re-resizable@^6.9.9:
version "6.9.9"
resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216"
integrity sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA==
react-base16-styling@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c"
@ -6075,6 +6143,11 @@ stop-iteration-iterator@^1.0.0:
dependencies:
internal-slot "^1.0.4"
string-hash@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==
string-length@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
@ -6172,6 +6245,11 @@ strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
style-inject@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/style-inject/-/style-inject-0.3.0.tgz#d21c477affec91811cc82355832a700d22bf8dd3"
integrity sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==
style-mod@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.0.3.tgz#136c4abc905f82a866a18b39df4dc08ec762b1ad"
@ -6581,13 +6659,6 @@ use-latest@^1.2.1:
dependencies:
use-isomorphic-layout-effect "^1.1.1"
use-resize-observer@^9.0.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/use-resize-observer/-/use-resize-observer-9.1.0.tgz#14735235cf3268569c1ea468f8a90c5789fc5c6c"
integrity sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==
dependencies:
"@juggle/resize-observer" "^3.3.1"
use-sync-external-store@1.2.0, use-sync-external-store@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"