87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
import {
|
|
type AnyNodeId,
|
|
useInteractive,
|
|
useScene,
|
|
type WindowInteractiveState,
|
|
} from '@pascal-app/core'
|
|
|
|
export const WINDOW_TOGGLE_ANIMATION_MS = 520
|
|
|
|
type WindowOpenAnimationOptions = {
|
|
persist?: boolean
|
|
}
|
|
|
|
export function isOperableWindowType(windowType: string | undefined) {
|
|
return (
|
|
windowType === 'sliding' ||
|
|
windowType === 'casement' ||
|
|
windowType === 'awning' ||
|
|
windowType === 'hopper' ||
|
|
windowType === 'single-hung' ||
|
|
windowType === 'double-hung' ||
|
|
windowType === 'louvered'
|
|
)
|
|
}
|
|
|
|
function getDisplayedWindowValue(windowId: AnyNodeId, nodeValue: number | undefined) {
|
|
const interactive = useInteractive.getState()
|
|
const runtimeValue = interactive.windows[windowId]?.operationState
|
|
if (runtimeValue !== undefined) return runtimeValue
|
|
|
|
const queuedValue = interactive.windowAnimations[windowId]?.from
|
|
if (queuedValue !== undefined) return queuedValue
|
|
|
|
return nodeValue ?? 0
|
|
}
|
|
|
|
function startWindowOpenAnimation(
|
|
windowId: AnyNodeId,
|
|
field: keyof WindowInteractiveState,
|
|
from: number,
|
|
to: number,
|
|
options?: WindowOpenAnimationOptions,
|
|
) {
|
|
useInteractive.getState().startWindowAnimation(windowId, {
|
|
field,
|
|
from,
|
|
to,
|
|
startedAt: null,
|
|
durationMs: WINDOW_TOGGLE_ANIMATION_MS,
|
|
persist: options?.persist ?? true,
|
|
})
|
|
}
|
|
|
|
export function toggleWindowOpenState(windowId: AnyNodeId, options?: WindowOpenAnimationOptions) {
|
|
const node = useScene.getState().nodes[windowId]
|
|
if (
|
|
node?.type !== 'window' ||
|
|
node.openingKind === 'opening' ||
|
|
!isOperableWindowType(node.windowType)
|
|
) {
|
|
return
|
|
}
|
|
|
|
const currentOpenAmount = getDisplayedWindowValue(windowId, node.operationState)
|
|
startWindowOpenAnimation(
|
|
windowId,
|
|
'operationState',
|
|
currentOpenAmount,
|
|
currentOpenAmount >= 0.5 ? 0 : 1,
|
|
options,
|
|
)
|
|
}
|
|
|
|
export function closeWindowOpenState(windowId: AnyNodeId, options?: WindowOpenAnimationOptions) {
|
|
const node = useScene.getState().nodes[windowId]
|
|
if (
|
|
node?.type !== 'window' ||
|
|
node.openingKind === 'opening' ||
|
|
!isOperableWindowType(node.windowType)
|
|
) {
|
|
return
|
|
}
|
|
|
|
const currentOpenAmount = getDisplayedWindowValue(windowId, node.operationState)
|
|
startWindowOpenAnimation(windowId, 'operationState', currentOpenAmount, 0, options)
|
|
}
|