feat: snap floating add button to edge
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { archivePanelFlags, calendarModeLabel, changedHabitFields, clampFabPosition, countdownDayText, countdownKindLabel, dateKey, defaultView, formatArchivedAt, formatAuditAction, formatAuditEntity, formatHabitApiError, formatLocalShortDateTime, formatUserAgent, habitActionState, habitButtonNotice, habitButtonValue, habitWeek, invalidateHabitGridCache, isFabDrag, isHabitComplete, isHabitScheduledToday, isTaskView, nextHabitSwipeValue, nextTotalAfterLocalTaskAdd, nextTotalAfterLocalTaskRemoval, normalizeRequiredName, numericHabitInputValue, performHabitRestore, performTrashMutation, previousHabitSwipeValue, quickTaskFields, readCountdownCache, readHabitGridCache, readStoredBoolean, readStoredNavigation, shouldToggleRowSwipe, validateHabitForm, writeCountdownCache, writeHabitGridCache, writeStoredBoolean, writeStoredNavigation } from './mvp-utils'
|
||||
import { archivePanelFlags, calendarModeLabel, changedHabitFields, clampFabPosition, countdownDayText, countdownKindLabel, dateKey, defaultView, formatArchivedAt, formatAuditAction, formatAuditEntity, formatHabitApiError, formatLocalShortDateTime, formatUserAgent, habitActionState, habitButtonNotice, habitButtonValue, habitWeek, invalidateHabitGridCache, isFabDrag, isHabitComplete, isHabitScheduledToday, isTaskView, nextHabitSwipeValue, nextTotalAfterLocalTaskAdd, nextTotalAfterLocalTaskRemoval, snapFabPosition, normalizeRequiredName, numericHabitInputValue, performHabitRestore, performTrashMutation, previousHabitSwipeValue, quickTaskFields, readCountdownCache, readHabitGridCache, readStoredBoolean, readStoredNavigation, shouldToggleRowSwipe, validateHabitForm, writeCountdownCache, writeHabitGridCache, writeStoredBoolean, writeStoredNavigation } from './mvp-utils'
|
||||
|
||||
describe('MVP view utilities', () => {
|
||||
it('formats a local date as YYYY-MM-DD', () => {
|
||||
@@ -181,6 +181,12 @@ describe('MVP view utilities', () => {
|
||||
expect(clampFabPosition(120, 300, 390, 844)).toEqual({ x: 120, y: 300 })
|
||||
})
|
||||
|
||||
it('snaps the add button to the nearest horizontal edge while preserving its safe vertical position', () => {
|
||||
expect(snapFabPosition(40, 300, 390, 844)).toEqual({ x: 14, y: 300 })
|
||||
expect(snapFabPosition(280, 300, 390, 844)).toEqual({ x: 324, y: 300 })
|
||||
expect(snapFabPosition(180, 900, 390, 844)).toEqual({ x: 324, y: 718 })
|
||||
})
|
||||
|
||||
it('validates safe habit input and emits only changed patch fields', () => {
|
||||
expect(normalizeRequiredName(' 喝水 ')).toEqual({ value: '喝水', error: '' })
|
||||
expect(normalizeRequiredName(' \n ')).toEqual({ value: '', error: '名称不能为空,请输入至少一个可见字符。' })
|
||||
|
||||
@@ -170,6 +170,14 @@ export function clampFabPosition(x: number, y: number, viewportWidth: number, vi
|
||||
}
|
||||
}
|
||||
|
||||
export function snapFabPosition(x: number, y: number, viewportWidth: number, viewportHeight: number, size = 52, margin = 14, bottomReserved = 74) {
|
||||
const clamped = clampFabPosition(x, y, viewportWidth, viewportHeight, size, margin, bottomReserved)
|
||||
const left = margin
|
||||
const right = Math.max(margin, viewportWidth - size - margin)
|
||||
const midpoint = viewportWidth / 2
|
||||
return { x: clamped.x + size / 2 < midpoint ? left : right, y: clamped.y }
|
||||
}
|
||||
|
||||
export function isFabDrag(deltaX: number, deltaY: number, threshold = 8) {
|
||||
return Math.hypot(deltaX, deltaY) >= threshold
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user