105 lines
2.0 KiB
TypeScript
105 lines
2.0 KiB
TypeScript
import { useWindowEvent } from '@/utils/hooks/useWindowEvent'
|
|
import { useState } from 'preact/hooks'
|
|
import { BoxDefinition } from '../types'
|
|
import { GRID_H_SNAP, GRID_WIDTH } from '../constants'
|
|
|
|
export enum ResizingMode {
|
|
NONE,
|
|
WIDTH,
|
|
HEIGHT,
|
|
ALL,
|
|
}
|
|
|
|
type Props = {
|
|
cellWidth: number
|
|
boxes: BoxDefinition[]
|
|
box: BoxDefinition
|
|
}
|
|
|
|
// TODO: This is not optimized at all
|
|
export const useResize = ({ cellWidth, box, boxes }: Props) => {
|
|
const [state, setState] = useState({
|
|
mode: ResizingMode.NONE,
|
|
w: 0,
|
|
h: 0,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
})
|
|
|
|
const isResizing = state.mode !== ResizingMode.NONE
|
|
|
|
const maxHeights = isResizing
|
|
? Array(GRID_WIDTH)
|
|
.fill(null)
|
|
.map((_, index) => {
|
|
return boxes
|
|
.filter(
|
|
(b) =>
|
|
b.id !== box.id &&
|
|
b.x <= index &&
|
|
b.x + b.w > index &&
|
|
b.y > box.y
|
|
)
|
|
.reduce(
|
|
(acc, item) => (item.y - box.y > acc ? item.y - box.y : acc),
|
|
0
|
|
)
|
|
})
|
|
: []
|
|
|
|
const actualHeight = isResizing
|
|
? Math.min(
|
|
...Array(box.w)
|
|
.fill(null)
|
|
.map((_, x) => maxHeights[box.x + x])
|
|
.filter((x) => x > 0),
|
|
Math.round(state.h / GRID_H_SNAP) * GRID_H_SNAP
|
|
)
|
|
: 0
|
|
|
|
const maxWidth = isResizing
|
|
? boxes
|
|
.filter(
|
|
(b) =>
|
|
b.id !== box.id &&
|
|
b.x > box.x &&
|
|
b.y < box.y + box.h &&
|
|
box.y < b.y + b.h
|
|
)
|
|
.map((b) => b.x - box.x)
|
|
.reduce((acc, item) => (item < acc ? item : acc), GRID_WIDTH)
|
|
: 0
|
|
|
|
const actualWidth = Math.min(maxWidth, Math.round(state.w / cellWidth))
|
|
|
|
useWindowEvent('mousemove', (e) => {
|
|
if (isResizing) {
|
|
const newState = {
|
|
...state,
|
|
}
|
|
|
|
if (
|
|
state.mode === ResizingMode.ALL ||
|
|
state.mode === ResizingMode.HEIGHT
|
|
) {
|
|
newState.h = box.h + e.clientY - state.offsetY
|
|
}
|
|
|
|
if (
|
|
state.mode === ResizingMode.ALL ||
|
|
state.mode === ResizingMode.WIDTH
|
|
) {
|
|
newState.w = box.w * cellWidth + e.clientX - state.offsetX
|
|
}
|
|
|
|
setState(newState)
|
|
}
|
|
})
|
|
|
|
return {
|
|
setResizing: setState,
|
|
resizingSize: { w: actualWidth, h: actualHeight },
|
|
resizing: state,
|
|
}
|
|
}
|