refactor(PipConfigPanel): 提取核心逻辑Hook
This commit is contained in:
+123
@@ -0,0 +1,123 @@
|
||||
import { useState, useCallback, useMemo } from "react"
|
||||
import type { PipConfig, PipLayer, PipGridPosition } from "../types"
|
||||
import { DEFAULT_PIP_LAYER, DEFAULT_PIP_CONFIG } from "../types"
|
||||
import { GRID_POSITION_MAP, genLayerId } from "../constants"
|
||||
|
||||
interface UsePipConfigPanelOptions {
|
||||
config: PipConfig
|
||||
onChange: (config: PipConfig) => void
|
||||
}
|
||||
|
||||
export const usePipConfigPanel = ({ config, onChange }: UsePipConfigPanelOptions) => {
|
||||
const [selectedId, setSelectedId] = useState<string>("")
|
||||
|
||||
const selectedLayer = useMemo(
|
||||
() => config.layers.find((l) => l.id === selectedId) ?? null,
|
||||
[config.layers, selectedId],
|
||||
)
|
||||
|
||||
/* ── 添加图层 ── */
|
||||
const handleAddLayer = useCallback(() => {
|
||||
const newLayer: PipLayer = {
|
||||
...DEFAULT_PIP_LAYER,
|
||||
id: genLayerId(),
|
||||
name: `图层 ${config.layers.length + 1}`,
|
||||
z_index: config.layers.length + 1,
|
||||
}
|
||||
onChange({
|
||||
...config,
|
||||
layers: [...config.layers, newLayer],
|
||||
})
|
||||
setSelectedId(newLayer.id)
|
||||
}, [config, onChange])
|
||||
|
||||
/* ── 删除图层 ── */
|
||||
const handleDeleteLayer = useCallback(
|
||||
(id: string) => {
|
||||
const newLayers = config.layers.filter((l) => l.id !== id)
|
||||
onChange({ ...config, layers: newLayers })
|
||||
if (selectedId === id) {
|
||||
setSelectedId(newLayers.length > 0 ? newLayers[0].id : "")
|
||||
}
|
||||
},
|
||||
[config, onChange, selectedId],
|
||||
)
|
||||
|
||||
/* ── 更新图层 ── */
|
||||
const updateLayer = useCallback(
|
||||
(id: string, partial: Partial<PipLayer>) => {
|
||||
onChange({
|
||||
...config,
|
||||
layers: config.layers.map((l) => (l.id === id ? { ...l, ...partial } : l)),
|
||||
})
|
||||
},
|
||||
[config, onChange],
|
||||
)
|
||||
|
||||
/* ── 切换启用 ── */
|
||||
const handleEnableToggle = useCallback(
|
||||
(checked: boolean) => {
|
||||
onChange({ ...config, enabled: checked })
|
||||
},
|
||||
[config, onChange],
|
||||
)
|
||||
|
||||
/* ── 重置 ── */
|
||||
const handleReset = useCallback(() => {
|
||||
onChange({ ...DEFAULT_PIP_CONFIG })
|
||||
setSelectedId("")
|
||||
}, [onChange])
|
||||
|
||||
/* ── 九宫格点击 ── */
|
||||
const handleGridClick = useCallback(
|
||||
(pos: PipGridPosition) => {
|
||||
if (!selectedLayer) return
|
||||
const coords = GRID_POSITION_MAP[pos]
|
||||
updateLayer(selectedLayer.id, {
|
||||
grid_position: pos,
|
||||
x: coords.x,
|
||||
y: coords.y,
|
||||
})
|
||||
},
|
||||
[selectedLayer, updateLayer],
|
||||
)
|
||||
|
||||
/* ── 宽高变化 ── */
|
||||
const handleWidthChange = useCallback(
|
||||
(val: number) => {
|
||||
if (!selectedLayer) return
|
||||
const partial: Partial<PipLayer> = { width: val }
|
||||
if (selectedLayer.aspect_lock) {
|
||||
partial.height = val
|
||||
}
|
||||
updateLayer(selectedLayer.id, partial)
|
||||
},
|
||||
[selectedLayer, updateLayer],
|
||||
)
|
||||
|
||||
const handleHeightChange = useCallback(
|
||||
(val: number) => {
|
||||
if (!selectedLayer) return
|
||||
const partial: Partial<PipLayer> = { height: val }
|
||||
if (selectedLayer.aspect_lock) {
|
||||
partial.width = val
|
||||
}
|
||||
updateLayer(selectedLayer.id, partial)
|
||||
},
|
||||
[selectedLayer, updateLayer],
|
||||
)
|
||||
|
||||
return {
|
||||
selectedId,
|
||||
setSelectedId,
|
||||
selectedLayer,
|
||||
handleAddLayer,
|
||||
handleDeleteLayer,
|
||||
updateLayer,
|
||||
handleEnableToggle,
|
||||
handleReset,
|
||||
handleGridClick,
|
||||
handleWidthChange,
|
||||
handleHeightChange,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user