Skip to content

Hot Refresh Support #1148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions fission/src/Synthesis.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import Scene from "@/components/Scene.tsx"
import { AnimatePresence } from "framer-motion"
import { ReactElement, useCallback, useEffect, useRef, useState } from "react"
import { ModalControlProvider, useModalManager } from "@/ui/ModalContext"
import { PanelControlProvider, usePanelManager } from "@/ui/PanelContext"
import { useTheme } from "@/ui/ThemeContext"
import { ModalControlProvider } from "@/ui/ModalContext"
import { useModalManager } from "@/ui/helpers/UseModalManager.tsx"
import { PanelControlProvider } from "@/ui/PanelContext"
import { usePanelManager } from "@/ui/helpers/UsePanelManager.tsx"
import { useTheme } from "@/ui/helpers/UseThemeHelpers.tsx"
import { ToastContainer, ToastProvider } from "@/ui/ToastContext"
import {
TOOLTIP_DURATION,
Expand Down
3 changes: 2 additions & 1 deletion fission/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ReactDOM from "react-dom/client"
import { Theme, ThemeProvider } from "@/ui/ThemeContext"
import { ThemeProvider } from "@/ui/ThemeContext"
import { Theme } from "@/ui/helpers/UseThemeHelpers"
import Synthesis from "./Synthesis"
import "./index.css"
import APS from "./aps/APS"
Expand Down
2 changes: 1 addition & 1 deletion fission/src/systems/scene/SceneRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import GizmoSceneObject from "./GizmoSceneObject"
import { EdgeDetectionMode, EffectComposer, EffectPass, RenderPass, SMAAEffect } from "postprocessing"
import fragmentShader from "@/shaders/fragment.glsl"
import vertexShader from "@/shaders/vertex.glsl"
import { Theme } from "@/ui/ThemeContext"
import { Theme } from "@/ui/helpers/UseThemeHelpers"
import Jolt from "@azaleacolburn/jolt-physics"
import { CameraControls, CameraControlsType, CustomOrbitControls } from "@/systems/scene/CameraControls"
import ScreenInteractionHandler, { InteractionEnd } from "./ScreenInteractionHandler"
Expand Down
99 changes: 1 addition & 98 deletions fission/src/ui/ModalContext.tsx
Original file line number Diff line number Diff line change
@@ -1,102 +1,5 @@
import React, { createContext, useState, useEffect, useCallback, useContext, ReactNode, ReactElement } from "react"

type ModalControlContextType = {
openModal: (modalId: string, onOpen?: () => void, onClose?: () => void) => void
closeModal: () => void
children?: ReactNode
}

const ModalControlContext = createContext<ModalControlContextType | null>(null)

export const useModalControlContext = () => {
const context = useContext(ModalControlContext)
if (!context) throw new Error("useModalControlContext must be used within a ModalControlProvider")
return context
}
import { ModalControlContext, ModalControlContextType } from "./helpers/UseModalManager"

export const ModalControlProvider: React.FC<ModalControlContextType> = ({ children, ...methods }) => {
return <ModalControlContext.Provider value={methods}>{children}</ModalControlContext.Provider>
}

type ModalInstance = {
id: string
component: ReactElement
onOpen?: () => void
onClose?: () => void
}

export const useModalManager = (modals: ReactElement[]) => {
const [modalDictionary, setModalDictionary] = useState<{
[key: string]: ModalInstance
}>({})
const [activeModalId, setActiveModalId] = useState<string | null>(null)

const openModal = useCallback(
(modalId: string, onOpen?: () => void, onClose?: () => void) => {
if (modalDictionary[modalId]) {
if (onOpen) {
modalDictionary[modalId].onOpen = onOpen
onOpen()
}
if (onClose) modalDictionary[modalId].onClose = onClose
}
setActiveModalId(modalId)
},
[modalDictionary]
)

const closeModal = useCallback(() => {
if (activeModalId) {
const inst = modalDictionary[activeModalId]
if (inst && inst.onClose) {
inst.onClose()
}
}
setActiveModalId(null)
}, [activeModalId, modalDictionary])

const registerModal = useCallback(
(modalId: string, modal: ModalInstance) => {
modalDictionary[modalId] = modal
},
[modalDictionary]
)

const unregisterModal = useCallback((modalId: string) => {
setModalDictionary(prevDictionary => {
const newDictionary = { ...prevDictionary }
delete newDictionary[modalId]
return newDictionary
})
}, [])

const getActiveModalElement = useCallback(() => {
if (activeModalId !== null) {
const modal = modalDictionary[activeModalId]
return modal ? modal.component : null
}
return null
}, [activeModalId, modalDictionary])

useEffect(() => {
modals.forEach(modalComponent => {
const id = modalComponent.props.modalId
registerModal(id, {
id: id,
component: modalComponent,
onOpen: () => {},
onClose: () => {},
})
})
}, [modals, closeModal, openModal, registerModal])

return {
modalDictionary,
activeModalId,
openModal,
closeModal,
registerModal,
unregisterModal,
getActiveModalElement,
}
}
133 changes: 1 addition & 132 deletions fission/src/ui/PanelContext.tsx
Original file line number Diff line number Diff line change
@@ -1,136 +1,5 @@
import React, { createContext, ReactElement, ReactNode, useCallback, useContext, useEffect, useState } from "react"

type PanelControlContextType = {
openPanel: (panelId: string) => void
closePanel: (panelId: string) => void
closeAllPanels: () => void
children?: ReactNode
}

const PanelControlContext = createContext<PanelControlContextType | null>(null)

export const usePanelControlContext = () => {
const context = useContext(PanelControlContext)
if (!context) throw new Error("usePanelControlContext must be used within a PanelControlProvider")
return context
}
import { PanelControlContext, PanelControlContextType } from "./helpers/UsePanelManager"

export const PanelControlProvider: React.FC<PanelControlContextType> = ({ children, ...methods }) => {
return <PanelControlContext.Provider value={methods}>{children}</PanelControlContext.Provider>
}

type PanelInstance = {
id: string
component: ReactElement
onOpen?: () => void
onClose?: () => void
}

export const usePanelManager = (panels: ReactElement[]) => {
const [panelDictionary, setPanelDictionary] = useState<{
[key: string]: PanelInstance
}>({})
const [activePanelIds, setActivePanelIds] = useState<string[]>([])

const openPanel = useCallback(
(panelId: string, onOpen?: () => void, onClose?: () => void) => {
setActivePanelIds(prevPanelIds => {
if (prevPanelIds.includes(panelId)) return prevPanelIds
if (panelDictionary[panelId]) {
if (onOpen) {
panelDictionary[panelId].onOpen = onOpen
onOpen()
}
if (onClose) panelDictionary[panelId].onClose = onClose
}
return [...activePanelIds, panelId]
})
},
[activePanelIds, panelDictionary]
)

const closePanel = useCallback(
(panelId: string) => {
let inst = panelDictionary[panelId]
if (inst) {
if (inst.onClose) inst.onClose()
setActivePanelIds(activePanelIds.filter(i => i != panelId))
} else {
setActivePanelIds(
activePanelIds.filter(i => {
inst = panelDictionary[i]
if (inst.component.props.name == panelId) {
if (inst.onClose) inst.onClose()
return false
} else {
return true
}
})
)
}
},
[activePanelIds, panelDictionary]
)

const closeAllPanels = useCallback(() => {
if (activePanelIds.length > 0) {
activePanelIds.forEach(id => {
const inst = panelDictionary[id]
if (inst && inst.onClose) {
inst.onClose()
}
})
}
setActivePanelIds([])
}, [activePanelIds, panelDictionary])

const registerPanel = useCallback(
(panelId: string, panel: PanelInstance) => {
panelDictionary[panelId] = panel
},
[panelDictionary]
)

const unregisterPanel = useCallback((panelId: string) => {
setPanelDictionary(prevDictionary => {
const newDictionary = { ...prevDictionary }
delete newDictionary[panelId]
return newDictionary
})
}, [])

const getActivePanelElements = useCallback(() => {
if (activePanelIds !== null && activePanelIds.length > 0) {
return activePanelIds
.map((id: string) => {
const panel: PanelInstance = panelDictionary[id]
return panel ? panel.component : null
})
.filter(p => p != null)
}
return []
}, [activePanelIds, panelDictionary])

useEffect(() => {
panels.forEach(panelData => {
const id = panelData.props.panelId
registerPanel(id, {
id: id,
component: panelData,
onOpen: () => {},
onClose: () => {},
})
})
}, [panels, closePanel, openPanel, registerPanel])

return {
panelDictionary,
activePanelIds,
openPanel,
closePanel,
closeAllPanels,
registerPanel,
unregisterPanel,
getActivePanelElements,
}
}
87 changes: 3 additions & 84 deletions fission/src/ui/ThemeContext.tsx
Original file line number Diff line number Diff line change
@@ -1,78 +1,7 @@
import React, { ReactNode, createContext, useContext, useState } from "react"
import { RgbaColor } from "react-colorful"
import React, { ReactNode, useState } from "react"
import { addGlobalFunc } from "@/util/dom"

export const defaultThemeName = "Default"
export type ColorName =
| "InteractiveElementSolid"
| "InteractiveElementLeft"
| "InteractiveElementRight"
| "Background"
| "BackgroundSecondary"
| "InteractiveBackground"
| "BackgroundHUD"
| "InteractiveHover"
| "InteractiveSelect"
| "MainText"
| "Scrollbar"
| "AcceptButton"
| "CancelButton"
| "InteractiveElementText"
| "Icon"
| "MainHUDIcon"
| "MainHUDCloseIcon"
| "HighlightHover"
| "HighlightSelect"
| "SkyboxTop"
| "SkyboxBottom"
| "FloorGrid"
| "AcceptCancelButtonText"
| "MatchRedAlliance"
| "MatchBlueAlliance"
| "ToastInfo"
| "ToastWarning"
| "ToastError"

export const colorNameToTailwind = (colorName: ColorName) => {
return (
"bg" +
colorName
.replace(/([A-Z]+)/g, "-$1")
.replace(/(?<=[A-Z])([A-Z])(?![A-Z]|$)/g, "-$1")
.toLowerCase()
)
}
export const colorNameToProp = (colorName: ColorName) => {
return (
"-" +
colorName
.replace(/([A-Z]+)/g, "-$1")
.replace(/(?<=[A-Z])([A-Z])(?![A-Z]|$)/g, "-$1")
.toLowerCase()
)
}

export const colorNameToVar = (colorName: ColorName) => {
return `var(${colorNameToProp(colorName)})`
}

export type Theme = {
[name in ColorName]: { color: RgbaColor; above: (ColorName | string)[] }
}
export type Themes = { [name: string]: Theme }

type ThemeContextType = {
themes: Themes
initialThemeName: string
defaultTheme: Theme
currentTheme: string
setTheme: (themeName: string) => void
updateColor: (themeName: string, colorName: ColorName, rgbaColor: RgbaColor) => void
createTheme: (themeName: string) => void
deleteTheme: (themeName: string) => void
deleteAllThemes: () => void
applyTheme: (themeName: string) => void
}
import { RgbaColor } from "react-colorful"
import { ColorName, Themes, Theme, ThemeContext, defaultThemeName, colorNameToProp } from "./helpers/UseThemeHelpers"

type ThemeProviderProps = {
themes: Themes
Expand All @@ -81,8 +10,6 @@ type ThemeProviderProps = {
children: ReactNode
}

const ThemeContext = createContext<ThemeContextType | undefined>(undefined)

export const ThemeProvider: React.FC<ThemeProviderProps> = ({ initialThemeName, themes, defaultTheme, children }) => {
const [currentTheme, setCurrentTheme] = useState<string>(initialThemeName)

Expand Down Expand Up @@ -186,11 +113,3 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ initialThemeName,
</ThemeContext.Provider>
)
}

export const useTheme = () => {
const context = useContext(ThemeContext)
if (!context) {
throw new Error("useTheme must be used within a ThemeProvider!")
}
return context
}
2 changes: 1 addition & 1 deletion fission/src/ui/components/AnalyticsConsent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Box } from "@mui/material"
import Label, { LabelSize } from "./Label"
import Button from "./Button"
import { colorNameToVar } from "../ThemeContext"
import { colorNameToVar } from "../helpers/UseThemeHelpers"
import { AiOutlineClose } from "react-icons/ai"

interface AnalyticsConsentProps {
Expand Down
2 changes: 1 addition & 1 deletion fission/src/ui/components/BespokeGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { DOMUnitExpression } from "@/util/Units"
import { useCallback, useEffect, useMemo, useReducer, useRef } from "react"
import { colorNameToVar } from "../ThemeContext"
import { colorNameToVar } from "../helpers/UseThemeHelpers"

const DEBUG_EDGE_CONTROL_LINES = false

Expand Down
Loading
Loading