zustand part 3 (#2878)

* zustand part 3

* clean up

* yarn lock
This commit is contained in:
Kurt Hutten
2024-07-03 09:22:46 +10:00
committed by GitHub
parent c5150468a2
commit 4c6e8633f7
11 changed files with 81 additions and 92 deletions

View File

@ -56,8 +56,7 @@
"vscode-languageserver-protocol": "^3.17.5",
"vscode-uri": "^3.0.8",
"web-vitals": "^3.5.2",
"xstate": "^4.38.2",
"zustand": "^4.5.2"
"xstate": "^4.38.2"
},
"scripts": {
"start": "vite",

View File

@ -1,4 +1,4 @@
import { MouseEventHandler, useEffect, useRef } from 'react'
import { MouseEventHandler, useEffect, useMemo, useRef } from 'react'
import { uuidv4 } from 'lib/utils'
import { useHotKeyListener } from './hooks/useHotKeyListener'
import { Stream } from './components/Stream'
@ -25,7 +25,7 @@ import ModalContainer from 'react-modal-promise'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
import Gizmo from 'components/Gizmo'
import { CoreDumpManager } from 'lib/coredump'
import { useStore } from 'useStore'
import { useAppState } from 'AppState'
export function App() {
useRefreshSettings(paths.FILE + 'SETTINGS')
@ -45,18 +45,19 @@ export function App() {
useHotKeyListener()
const { context } = useModelingContext()
const { setHtmlRef } = useStore((s) => ({
setHtmlRef: s.setHtmlRef,
}))
const { setAppState } = useAppState()
useEffect(() => {
setHtmlRef(ref)
setAppState({ htmlRef: ref })
}, [ref])
const { auth, settings } = useSettingsAuthContext()
const token = auth?.context?.token
const coreDumpManager = new CoreDumpManager(engineCommandManager, ref, token)
const coreDumpManager = useMemo(
() => new CoreDumpManager(engineCommandManager, ref, token),
[]
)
const {
app: { onboardingStatus },

45
src/AppState.tsx Normal file
View File

@ -0,0 +1,45 @@
import { createContext, useContext, useState, ReactNode } from 'react'
/*
This is for a very small handful of global state we need that doesn't fit into
any of the Xstate machines.
Please do not fill this up with junk.
*/
interface AppState {
isStreamReady: boolean
htmlRef: React.RefObject<HTMLDivElement> | null
setAppState: (newAppState: Partial<AppState>) => void
}
const AppStateContext = createContext<AppState>({
htmlRef: null,
isStreamReady: false,
setAppState: () => {},
})
export const useAppState = () => useContext(AppStateContext)
export const AppStateProvider = ({ children }: { children: ReactNode }) => {
const [appState, _setAppState] = useState<AppState>({
htmlRef: null,
isStreamReady: false,
setAppState: () => {},
})
const setAppState = (newAppState: Partial<AppState>) =>
_setAppState({ ...appState, ...newAppState })
return (
<AppStateContext.Provider
value={{
htmlRef: appState.htmlRef,
isStreamReady: appState.isStreamReady,
setAppState,
}}
>
{children}
</AppStateContext.Provider>
)
}

View File

@ -40,7 +40,7 @@ import useHotkeyWrapper from 'lib/hotkeyWrapper'
import toast from 'react-hot-toast'
import { coreDump } from 'lang/wasm'
import { useMemo } from 'react'
import { useStore } from 'useStore'
import { AppStateProvider, useAppState } from 'AppState'
const router = createBrowserRouter([
{
@ -53,7 +53,9 @@ const router = createBrowserRouter([
<SettingsAuthProvider>
<LspProvider>
<KclContextProvider>
<Outlet />
<AppStateProvider>
<Outlet />
</AppStateProvider>
</KclContextProvider>
</LspProvider>
</SettingsAuthProvider>
@ -178,9 +180,7 @@ export const Router = () => {
function CoreDump() {
const { auth } = useSettingsAuthContext()
const token = auth?.context?.token
const { htmlRef } = useStore((s) => ({
htmlRef: s.htmlRef,
}))
const { htmlRef } = useAppState()
const coreDumpManager = useMemo(
() => new CoreDumpManager(engineCommandManager, htmlRef, token),
[]

View File

@ -11,7 +11,7 @@ import { useKclContext } from 'lang/KclProvider'
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
import { useHotkeys } from 'react-hotkeys-hook'
import Tooltip from 'components/Tooltip'
import { useStore } from 'useStore'
import { useAppState } from 'AppState'
export function Toolbar({
className = '',
@ -38,9 +38,8 @@ export function Toolbar({
const toolbarButtonsRef = useRef<HTMLUListElement>(null)
const { overallState } = useNetworkContext()
const { isExecuting } = useKclContext()
const { isStreamReady } = useStore((s) => ({
isStreamReady: s.isStreamReady,
}))
const { isStreamReady } = useAppState()
const disableAllButtons =
(overallState !== NetworkHealthState.Ok &&
overallState !== NetworkHealthState.Weak) ||

View File

@ -6,14 +6,12 @@ import React, { useMemo } from 'react'
import toast from 'react-hot-toast'
import Tooltip from './Tooltip'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useStore } from 'useStore'
import { useAppState } from 'AppState'
export const RefreshButton = ({ children }: React.PropsWithChildren) => {
const { auth } = useSettingsAuthContext()
const token = auth?.context?.token
const { htmlRef } = useStore((s) => ({
htmlRef: s.htmlRef,
}))
const { htmlRef } = useAppState()
const coreDumpManager = useMemo(
() => new CoreDumpManager(engineCommandManager, htmlRef, token),
[]

View File

@ -4,7 +4,7 @@ import { deferExecution } from 'lib/utils'
import { Themes } from 'lib/theme'
import { makeDefaultPlanes, modifyGrid } from 'lang/wasm'
import { useModelingContext } from './useModelingContext'
import { useStore } from 'useStore'
import { useAppState } from 'AppState'
export function useSetupEngineManager(
streamRef: React.RefObject<HTMLDivElement>,
@ -27,9 +27,7 @@ export function useSetupEngineManager(
showScaleGrid: boolean
}
) {
const { setIsStreamReady } = useStore((s) => ({
setIsStreamReady: s.setIsStreamReady,
}))
const { setAppState } = useAppState()
const streamWidth = streamRef?.current?.offsetWidth
const streamHeight = streamRef?.current?.offsetHeight
@ -61,7 +59,7 @@ export function useSetupEngineManager(
type: 'Set context',
data: { mediaStream },
}),
setIsStreamReady,
setIsStreamReady: (isStreamReady) => setAppState({ isStreamReady }),
width: quadWidth,
height: quadHeight,
executeCode: () => {

View File

@ -10,7 +10,7 @@ import { Command, CommandSetConfig, CommandSetSchema } from 'lib/commandTypes'
import { useKclContext } from 'lang/KclProvider'
import { useNetworkContext } from 'hooks/useNetworkContext'
import { NetworkHealthState } from 'hooks/useNetworkStatus'
import { useStore } from 'useStore'
import { useAppState } from 'AppState'
// This might not be necessary, AnyStateMachine from xstate is working
export type AllMachines =
@ -47,9 +47,7 @@ export default function useStateMachineCommands<
const { commandBarSend } = useCommandsContext()
const { overallState } = useNetworkContext()
const { isExecuting } = useKclContext()
const { isStreamReady } = useStore((s) => ({
isStreamReady: s.isStreamReady,
}))
const { isStreamReady } = useAppState()
useEffect(() => {
const disableAllButtons =

View File

@ -1,4 +1,4 @@
import { FormEvent, useEffect } from 'react'
import { FormEvent, useEffect, useRef } from 'react'
import { remove } from '@tauri-apps/plugin-fs'
import {
getNextProjectIndex,
@ -39,6 +39,7 @@ import {
listProjects,
renameProjectDirectory,
} from 'lib/tauri'
import { useAppState } from 'AppState'
// This route only opens in the Tauri desktop context for now,
// as defined in Router.tsx, so we can use the Tauri APIs and types.
@ -64,6 +65,12 @@ const Home = () => {
splitKey: '|',
}
)
const ref = useRef<HTMLDivElement>(null)
const { setAppState } = useAppState()
useEffect(() => {
setAppState({ htmlRef: ref })
}, [ref])
const [state, send, actor] = useMachine(homeMachine, {
context: {
@ -198,7 +205,7 @@ const Home = () => {
}
return (
<div className="relative flex flex-col h-screen overflow-hidden">
<div className="relative flex flex-col h-screen overflow-hidden" ref={ref}>
<AppHeader showToolbar={false} />
<div className="w-full flex flex-col overflow-hidden max-w-5xl px-4 mx-auto mt-24 lg:px-2">
<section>

View File

@ -1,19 +0,0 @@
import { create } from 'zustand'
export interface StoreState {
isStreamReady: boolean
setIsStreamReady: (isStreamReady: boolean) => void
setHtmlRef: (ref: React.RefObject<HTMLDivElement>) => void
htmlRef: React.RefObject<HTMLDivElement> | null
}
export const useStore = create<StoreState>()((set, get) => {
return {
setIsStreamReady: (isStreamReady) => set({ isStreamReady }),
setHtmlRef: (htmlRef) => {
set({ htmlRef })
},
htmlRef: null,
isStreamReady: false,
}
})

View File

@ -7565,16 +7565,7 @@ string-natural-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -7652,14 +7643,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@ -8159,11 +8143,6 @@ use-latest@^1.2.1:
dependencies:
use-isomorphic-layout-effect "^1.1.1"
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"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
use-sync-external-store@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9"
@ -8532,7 +8511,7 @@ workerpool@6.2.1:
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@ -8550,15 +8529,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
@ -8718,10 +8688,3 @@ zip-stream@^6.0.1:
archiver-utils "^5.0.0"
compress-commons "^6.0.2"
readable-stream "^4.0.0"
zustand@^4.5.2:
version "4.5.2"
resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.2.tgz#fddbe7cac1e71d45413b3682cdb47b48034c3848"
integrity sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==
dependencies:
use-sync-external-store "1.2.0"