Skip to content

Commit 8bf34f0

Browse files
authored
feat: enhance drag functionality by storing initial drag state and coordinates (#96)
1 parent 60739b6 commit 8bf34f0

File tree

3 files changed

+53
-17
lines changed

3 files changed

+53
-17
lines changed

packages/components/splitter/src/connect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
105105
event.preventDefault()
106106
return
107107
}
108-
send({ type: 'POINTER_DOWN', id })
108+
send({ type: 'POINTER_DOWN', id, point: { x: event.clientX, y: event.clientY } })
109109
event.currentTarget.setPointerCapture(event.pointerId)
110110
event.preventDefault()
111111
event.stopPropagation()

packages/components/splitter/src/machine.ts

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { MachineContext, MachineState, UserDefinedContext } from './types'
2-
import { getRelativePoint, raf, trackPointerMove } from '@destyler/dom'
2+
import { raf, trackPointerMove } from '@destyler/dom'
33
import { compact } from '@destyler/utils'
44
import { createMachine } from '@destyler/xstate'
55
import { dom } from './dom'
@@ -21,6 +21,8 @@ export function machine(userContext: UserDefinedContext) {
2121
isAtMin: false,
2222
isAtMax: false,
2323
},
24+
initialDragPoint: null,
25+
initialDragSizes: null,
2426
...ctx,
2527
},
2628

@@ -121,7 +123,7 @@ export function machine(userContext: UserDefinedContext) {
121123

122124
'dragging': {
123125
tags: ['focus'],
124-
entry: 'focusResizeHandle',
126+
entry: ['focusResizeHandle', 'storeInitialDragState'],
125127
activities: ['trackPointerMove'],
126128
on: {
127129
POINTER_MOVE: {
@@ -240,6 +242,17 @@ export function machine(userContext: UserDefinedContext) {
240242
dom.getActiveHandleEl(ctx)?.blur()
241243
})
242244
},
245+
storeInitialDragState(ctx, evt) {
246+
const panels = getHandlePanels(ctx)
247+
if (!panels)
248+
return
249+
const { before, after } = panels
250+
ctx.initialDragPoint = evt.point
251+
ctx.initialDragSizes = {
252+
before: before.size,
253+
after: after.size,
254+
}
255+
},
243256
setPreviousPanels(ctx) {
244257
ctx.previousPanels = ctx.panels.slice()
245258
},
@@ -264,27 +277,48 @@ export function machine(userContext: UserDefinedContext) {
264277
if (!rootEl)
265278
return
266279

267-
const relativePoint = getRelativePoint(evt.point, rootEl)
268-
const percentValue = relativePoint.getPercentValue({
269-
dir: ctx.dir,
270-
orientation: ctx.orientation,
271-
})
280+
if (!ctx.initialDragPoint || !ctx.initialDragSizes)
281+
return
282+
283+
const { before, after } = panels
284+
285+
// Calculate relative movement from initial drag position
286+
const rootSize = ctx.isHorizontal ? rootEl.offsetWidth : rootEl.offsetHeight
287+
const currentPos = ctx.isHorizontal ? evt.point.x : evt.point.y
288+
const initialPos = ctx.isHorizontal ? ctx.initialDragPoint.x : ctx.initialDragPoint.y
272289

273-
let pointValue = percentValue * 100
290+
// Handle RTL for horizontal orientation
291+
const isRtl = ctx.dir === 'rtl' && ctx.isHorizontal
292+
const deltaPixels = isRtl ? (initialPos - currentPos) : (currentPos - initialPos)
293+
const deltaPercent = (deltaPixels / rootSize) * 100
274294

275-
// update active resize state here because we use `previousPanels` in the calculations
295+
// Calculate new sizes based on delta from initial sizes
296+
let newBeforeSize = ctx.initialDragSizes.before + deltaPercent
297+
let newAfterSize = ctx.initialDragSizes.after - deltaPercent
298+
299+
// Update active resize state
276300
ctx.activeResizeState = {
277-
isAtMin: pointValue < bounds.min,
278-
isAtMax: pointValue > bounds.max,
301+
isAtMin: newBeforeSize <= before.minSize,
302+
isAtMax: newBeforeSize >= before.maxSize,
279303
}
280304

281-
pointValue = clamp(pointValue, bounds.min, bounds.max)
305+
// Apply constraints
306+
newBeforeSize = clamp(newBeforeSize, before.minSize, before.maxSize)
307+
newAfterSize = clamp(newAfterSize, after.minSize, after.maxSize)
282308

283-
const { before, after } = panels
309+
// Ensure total doesn't exceed available space
310+
const totalSize = ctx.initialDragSizes.before + ctx.initialDragSizes.after
311+
if (newBeforeSize + newAfterSize > totalSize) {
312+
if (deltaPercent > 0) {
313+
newAfterSize = totalSize - newBeforeSize
314+
}
315+
else {
316+
newBeforeSize = totalSize - newAfterSize
317+
}
318+
}
284319

285-
const offset = pointValue - before.end
286-
ctx.size[before.index].size = before.size + offset
287-
ctx.size[after.index].size = after.size - offset
320+
ctx.size[before.index].size = newBeforeSize
321+
ctx.size[after.index].size = newAfterSize
288322
},
289323
},
290324
},

packages/components/splitter/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ interface PrivateContext {
6969
previousPanels: NormalizedPanelData
7070
activeResizeState: { isAtMin: boolean, isAtMax: boolean }
7171
initialSize: Array<Required<Pick<PanelSizeData, 'id' | 'size'>>>
72+
initialDragPoint: { x: number, y: number } | null
73+
initialDragSizes: { before: number, after: number } | null
7274
}
7375

7476
export interface MachineContext extends PublicContext, ComputedContext, PrivateContext {}

0 commit comments

Comments
 (0)