修改组件逻辑+优化代码

This commit is contained in:
2025-11-11 17:20:43 +08:00
parent ce688a6834
commit f2bb7f3196
2 changed files with 306 additions and 162 deletions

View File

@@ -45,7 +45,7 @@ body {
background-color: var(--color-light); background-color: var(--color-light);
-webkit-font-smoothing: antialiased; /* 字体抗锯齿 */ -webkit-font-smoothing: antialiased; /* 字体抗锯齿 */
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
overflow-x: hidden; overflow: hidden;
} }
/* ===== 排版元素 ===== */ /* ===== 排版元素 ===== */

View File

@@ -42,10 +42,10 @@ interface IElementRect {
width: number; width: number;
/** 高度 */ /** 高度 */
height: number; height: number;
/** 顶点坐标(相对 offsetParent */ /** x坐标 */
top: number; x: number;
/** 左点坐标(相对 offsetParent */ /** y坐标 */
left: number; y: number;
} }
/** 窗口自定义事件 */ /** 窗口自定义事件 */
@@ -75,38 +75,50 @@ export class WindowFormElement extends LitElement {
@property({ type: Boolean }) closable = true @property({ type: Boolean }) closable = true
@property({ type: Boolean, reflect: true }) focused: boolean = true @property({ type: Boolean, reflect: true }) focused: boolean = true
@property({ type: String, reflect: true }) windowFormState: TWindowFormState = 'default' @property({ type: String, reflect: true }) windowFormState: TWindowFormState = 'default'
@property({ type: Object }) dragContainer?: HTMLElement @property({ type: Object }) dragContainer?: HTMLElement // 元素的父容器
@property({ type: Boolean }) allowOverflow = true // 允许窗口超出容器 @property({ type: Number }) snapDistance = 0 // 吸附距离
@property({ type: Number }) snapDistance = 20 // 吸附距离 @property({ type: Boolean }) snapAnimation = false // 吸附动画
@property({ type: Boolean }) snapAnimation = true // 吸附动画
@property({ type: Number }) snapAnimationDuration = 300 // 吸附动画时长 ms @property({ type: Number }) snapAnimationDuration = 300 // 吸附动画时长 ms
@property({ type: Number }) maxWidth?: number = Infinity @property({ type: Number }) maxWidth?: number = Infinity
@property({ type: Number }) minWidth?: number = 0 @property({ type: Number }) minWidth?: number = 200
@property({ type: Number }) maxHeight?: number = Infinity @property({ type: Number }) maxHeight?: number = Infinity
@property({ type: Number }) minHeight?: number = 0 @property({ type: Number }) minHeight?: number = 200
@property({ type: String }) taskbarElementId?: string @property({ type: String }) taskbarElementId?: string
@property({ type: Object }) wfData: any; @property({ type: Object }) wfData: any;
private _listeners: Array<{ type: string; original: Function; wrapped: EventListener }> = [] private _listeners: Array<{ type: string; original: Function; wrapped: EventListener }> = []
// ==== 拖拽/缩放状态(内部变量,不触发渲染) ==== // ==== 拖拽/缩放状态(内部变量,不触发渲染) ====
private dragging = false // 自身的x坐标
private resizeDir: TResizeDirection | null = null
private startX = 0
private startY = 0
private startWidth = 0
private startHeight = 0
private startX_host = 0
private startY_host = 0
private x = 0 private x = 0
// 自身的y坐标
private y = 0 private y = 0
private preX = 0 // 自身的宽度
private preY = 0
private width = 640 private width = 640
// 自身的高度
private height = 360 private height = 360
// 记录拖拽开始时自身x坐标
private originalX = 0
// 记录拖拽开始时自身y坐标
private originalY = 0
// 鼠标开始拖拽时自身宽度
private originalWidth = 640
// 鼠标开始拖拽时高度
private originalHeight = 360
// 鼠标开始拖拽时x坐标
private pointStartX = 0
// 鼠标开始拖拽时x坐标
private pointStartY = 0
private animationFrame?: number private animationFrame?: number
// 是否拖拽状态
private dragging = false
// 是否缩放状态
private resizing = false private resizing = false
// 缩放方向
private resizeDir: TResizeDirection | null = null
// private get x() { // private get x() {
// return this.wfData.state.x // return this.wfData.state.x
@@ -198,25 +210,28 @@ export class WindowFormElement extends LitElement {
} }
override firstUpdated() { override firstUpdated() {
console.log(this.wfData) const { width, height } = this.getBoundingClientRect()
// wfem.addEventListener('windowFormFocus', this.windowFormFocusFun) this.width = width || this.width
window.addEventListener('pointerup', this.onPointerUp) this.height = height || this.height
window.addEventListener('pointermove', this.onPointerMove)
this.addEventListener('pointerdown', this.toggleFocus)
const container = this.dragContainer || document.body const container = this.dragContainer || document.body
const containerRect = container.getBoundingClientRect() const containerRect = container.getBoundingClientRect()
this.x = containerRect.width / 2 - this.width / 2 this.x = containerRect.width / 2 - this.width / 2
this.y = containerRect.height / 2 - this.height / 2 this.y = containerRect.height / 2 - this.height / 2
this.style.width = `${this.width}px` this.style.width = `${this.width}px`
this.style.height = `${this.height}px` this.style.height = `${this.height}px`
this.style.transform = `translate(${this.x}px, ${this.y}px)` this.style.transform = `translate(${this.x}px, ${this.y}px)`
window.addEventListener('pointerup', this.onPointerUp)
window.addEventListener('pointermove', this.onPointerMove)
this.addEventListener('pointerdown', this.toggleFocus)
this.targetBounds = { this.targetBounds = {
width: this.offsetWidth, width: this.width,
height: this.offsetHeight, height: this.height,
top: this.x, x: this.x,
left: this.y, y: this.y,
} }
} }
@@ -257,10 +272,10 @@ export class WindowFormElement extends LitElement {
e.preventDefault() e.preventDefault()
this.dragging = true this.dragging = true
this.startX = e.clientX this.pointStartX = e.clientX
this.startY = e.clientY this.pointStartY = e.clientY
this.preX = this.x this.originalX = this.x
this.preY = this.y this.originalY = this.y
this.setPointerCapture?.(e.pointerId) this.setPointerCapture?.(e.pointerId)
this.dispatchEvent( this.dispatchEvent(
@@ -272,15 +287,20 @@ export class WindowFormElement extends LitElement {
) )
} }
/**
* 鼠标指针移动
* @param e
*/
private onPointerMove = (e: PointerEvent) => { private onPointerMove = (e: PointerEvent) => {
if (this.dragging) { if (this.dragging) {
const dx = e.clientX - this.startX const dx = e.clientX - this.pointStartX
const dy = e.clientY - this.startY const dy = e.clientY - this.pointStartY
const x = this.preX + dx const x = this.originalX + dx
const y = this.preY + dy const y = this.originalY + dy
this.applyPosition(x, y, false) const pos = this.applyBoundary(x, y, e.clientX, e.clientY)
this.applyPosition(pos.x, pos.y)
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('windowForm:dragMove', { new CustomEvent('windowForm:dragMove', {
detail: { x, y }, detail: { x, y },
@@ -293,6 +313,10 @@ export class WindowFormElement extends LitElement {
} }
} }
/**
* 鼠标指针抬起
* @param e
*/
private onPointerUp = (e: PointerEvent) => { private onPointerUp = (e: PointerEvent) => {
if (this.dragging) { if (this.dragging) {
this.dragUp(e) this.dragUp(e)
@@ -320,13 +344,14 @@ export class WindowFormElement extends LitElement {
} }
/** /**
* 获取最近的吸附点 * 根据传入的坐标点位计算吸附距离最近的坐标位置
* @param x 左上角起始点x * @param x 坐标点 x
* @param y 左上角起始点y * @param y 坐标点 y
* @returns {x: number, y: number} 新的位置坐标
*/ */
private applySnapping(x: number, y: number) { private calculateSnapping(x: number, y: number): { x: number, y: number} {
let snappedX = x, let snappedX = x
snappedY = y let snappedY = y
const containerSnap = this.getSnapPoints() const containerSnap = this.getSnapPoints()
if (this.snapDistance > 0) { if (this.snapDistance > 0) {
for (const sx of containerSnap.x) for (const sx of containerSnap.x)
@@ -343,22 +368,28 @@ export class WindowFormElement extends LitElement {
return { x: snappedX, y: snappedY } return { x: snappedX, y: snappedY }
} }
/**
* 拖拽结束
* @param e
* @private
*/
private dragUp(e: PointerEvent) { private dragUp(e: PointerEvent) {
const snapped = this.applySnapping(this.x, this.y) const snapped = this.calculateSnapping(this.x, this.y)
if (this.snapAnimation) { if (this.snapAnimation) {
this.animateTo(snapped.x, snapped.y, this.snapAnimationDuration, () => { this.animateTo(this.x, this.y, snapped.x, snapped.y, this.snapAnimationDuration,
this.updateTargetBounds(snapped.x, snapped.y) (x, y) => {
this.dispatchEvent( this.applyPosition(x, y)
new CustomEvent('windowForm:dragEnd', { },
(x, y) => {
this.applyPosition(snapped.x, snapped.y)
this.dispatchEvent(new CustomEvent('windowForm:dragEnd', {
detail: { x: snapped.x, y: snapped.y }, detail: { x: snapped.x, y: snapped.y },
bubbles: true, bubbles: true,
composed: true, composed: true,
}), }))
)
}) })
} else { } else {
this.applyPosition(snapped.x, snapped.y, true) this.applyPosition(snapped.x, snapped.y)
this.updateTargetBounds(snapped.x, snapped.y)
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('windowForm:dragEnd', { new CustomEvent('windowForm:dragEnd', {
detail: { x: snapped.x, y: snapped.y }, detail: { x: snapped.x, y: snapped.y },
@@ -369,29 +400,65 @@ export class WindowFormElement extends LitElement {
} }
} }
private applyPosition(x: number, y: number, isFinal: boolean) { /**
* 根据鼠标指针的位置是否在容器边界内来限制窗口坐标
* @param x 当前元素的左上角坐标 x
* @param y 当前元素的左上角坐标 y
* @param pointerX 当前鼠标在容器中的 X 坐标
* @param pointerY 当前鼠标在容器中的 Y 坐标
* @returns 限制后的坐标点 { x, y }
*/
private applyBoundary(x: number, y: number, pointerX: number, pointerY: number): { x: number; y: number } {
const containerRect = (this.dragContainer || document.body).getBoundingClientRect()
// 限制指针在容器内
const limitedPointerX = Math.min(Math.max(pointerX, containerRect.left), containerRect.right)
const limitedPointerY = Math.min(Math.max(pointerY, containerRect.top), containerRect.bottom)
// 计算指针被限制后的偏移量
const dx = limitedPointerX - pointerX
const dy = limitedPointerY - pointerY
// 根据指针偏移调整窗口位置
x += dx
y += dy
return { x, y }
}
/**
* 设置拖拽的窗口位置
* @param x 当前元素的左上角坐标点 x
* @param y 当前元素的左上角坐标点 y
* @private
*/
private applyPosition(x: number, y: number) {
this.x = x this.x = x
this.y = y this.y = y
this.style.transform = `translate(${x}px, ${y}px)` this.style.transform = `translate(${x}px, ${y}px)`
if (isFinal) this.applyBoundary()
} }
private applyBoundary() { /**
if (this.allowOverflow) return * 动画移动窗口
let { x, y } = { x: this.x, y: this.y } * @param startX 窗口起始点 x
* @param startY 窗口起始点 y
const rect = this.getBoundingClientRect() * @param targetX 目标点 x
const containerRect = (this.dragContainer || document.body).getBoundingClientRect() * @param targetY 目标点 y
x = Math.min(Math.max(x, 0), containerRect.width - rect.width) * @param duration 动画时长
y = Math.min(Math.max(y, 0), containerRect.height - rect.height) * @param onMove 移动回调
* @param onComplete 完成回调
this.applyPosition(x, y, false) * @private
} */
private animateTo(
private animateTo(targetX: number, targetY: number, duration: number, onComplete?: () => void) { startX: number,
startY: number,
targetX: number,
targetY: number,
duration: number,
onMove?: (x: number, y: number) => void,
onComplete?: (x: number, y: number) => void
) {
if (this.animationFrame) cancelAnimationFrame(this.animationFrame) if (this.animationFrame) cancelAnimationFrame(this.animationFrame)
const startX = this.x
const startY = this.y
const deltaX = targetX - startX const deltaX = targetX - startX
const deltaY = targetY - startY const deltaY = targetY - startY
const startTime = performance.now() const startTime = performance.now()
@@ -404,7 +471,7 @@ export class WindowFormElement extends LitElement {
const x = startX + deltaX * ease const x = startX + deltaX * ease
const y = startY + deltaY * ease const y = startY + deltaY * ease
this.applyPosition(x, y, false) onMove?.(x, y)
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('windowForm:dragMove', { new CustomEvent('windowForm:dragMove', {
detail: { x, y }, detail: { x, y },
@@ -416,8 +483,7 @@ export class WindowFormElement extends LitElement {
if (progress < 1) { if (progress < 1) {
this.animationFrame = requestAnimationFrame(step) this.animationFrame = requestAnimationFrame(step)
} else { } else {
this.applyPosition(targetX, targetY, true) onComplete?.(targetX, targetY)
onComplete?.()
} }
} }
this.animationFrame = requestAnimationFrame(step) this.animationFrame = requestAnimationFrame(step)
@@ -432,14 +498,12 @@ export class WindowFormElement extends LitElement {
e.stopPropagation() e.stopPropagation()
this.resizing = true this.resizing = true
this.resizeDir = dir this.resizeDir = dir
this.startX = e.clientX this.pointStartX = e.clientX
this.startY = e.clientY this.pointStartY = e.clientY
this.originalX = this.x
const rect = this.getBoundingClientRect() this.originalY = this.y
this.startWidth = rect.width this.originalWidth = this.width
this.startHeight = rect.height this.originalHeight = this.height
this.startX_host = rect.left
this.startY_host = rect.top
const target = e.target as HTMLElement const target = e.target as HTMLElement
document.body.style.cursor = target.style.cursor || window.getComputedStyle(target).cursor document.body.style.cursor = target.style.cursor || window.getComputedStyle(target).cursor
@@ -454,59 +518,72 @@ export class WindowFormElement extends LitElement {
) )
} }
/**
* 缩放
* @param e
* @private
*/
private performResize(e: PointerEvent) { private performResize(e: PointerEvent) {
if (!this.resizeDir || !this.resizing) return if (!this.resizeDir || !this.resizing) return
let newWidth = this.startWidth let newWidth = this.originalWidth
let newHeight = this.startHeight let newHeight = this.originalHeight
let newX = this.startX_host let newX = this.originalX
let newY = this.startY_host let newY = this.originalY
const dx = e.clientX - this.startX const dx = e.clientX - this.pointStartX
const dy = e.clientY - this.startY const dy = e.clientY - this.pointStartY
// ====== 根据方向计算临时尺寸与位置 ======
switch (this.resizeDir) { switch (this.resizeDir) {
case 'r': case 'r': // 右侧
newWidth += dx newWidth += dx
break break
case 'b': case 'b': // 下方
newHeight += dy newHeight += dy
break break
case 'l': case 'l': // 左侧
newWidth -= dx newWidth -= dx
newX += dx newX += dx
break break
case 't': case 't': // 上方
newHeight -= dy newHeight -= dy
newY += dy newY += dy
break break
case 'tl': case 'tl': // 左上角
newWidth -= dx newWidth -= dx
newX += dx newX += dx
newHeight -= dy newHeight -= dy
newY += dy newY += dy
break break
case 'tr': case 'tr': // 右上角
newWidth += dx newWidth += dx
newHeight -= dy newHeight -= dy
newY += dy newY += dy
break break
case 'bl': case 'bl': // 左下角
newWidth -= dx newWidth -= dx
newX += dx newX += dx
newHeight += dy newHeight += dy
break break
case 'br': case 'br': // 右下角
newWidth += dx newWidth += dx
newHeight += dy newHeight += dy
break break
} }
const d = this.applyResizeBounds(newX, newY, newWidth, newHeight) const { x, y, width, height } = this.applyResizeBounds(newX, newY, newWidth, newHeight, this.resizeDir)
this.x = x
this.y = y
this.width = width
this.height = height
this.style.width = `${this.width}px`
this.style.height = `${this.height}px`
this.style.transform = `translate(${this.x}px, ${this.y}px)`
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('windowForm:resizeMove', { new CustomEvent('windowForm:resizeMove', {
detail: { dir: this.resizeDir, width: d.width, height: d.height, left: d.left, top: d.top }, detail: { dir: this.resizeDir, width: width, height: height, left: x, top: y },
bubbles: true, bubbles: true,
composed: true, composed: true,
}), }),
@@ -514,68 +591,107 @@ export class WindowFormElement extends LitElement {
} }
/** /**
* 应用尺寸调整边界 * 计算尺寸调整约束逻辑,返回约束后的尺寸
* @param newX 新的X坐标 * @param x 坐标 x
* @param newY 新的Y坐标 * @param y 坐标 y
* @param newWidth 新的宽度 * @param width 宽度
* @param newHeight 新的高度 * @param height 高度
* @private * @private
* @returns { x: number, y: number, width: number, height: number } 约束后的尺寸
*/ */
private applyResizeBounds( private applyResizeBounds(
newX: number, x: number,
newY: number, y: number,
newWidth: number, width: number,
newHeight: number, height: number,
resizeDir: TResizeDirection
): { ): {
left: number x: number
top: number y: number
width: number width: number
height: number height: number
} { } {
// 最小/最大宽高限制 const { minWidth = 100, minHeight = 100, maxWidth = Infinity, maxHeight = Infinity } = this
if (this.minWidth != null) newWidth = Math.max(this.minWidth, newWidth)
if (this.maxWidth != null) newWidth = Math.min(this.maxWidth, newWidth)
if (this.minHeight != null) newHeight = Math.max(this.minHeight, newHeight)
if (this.maxHeight != null) newHeight = Math.min(this.maxHeight, newHeight)
// 边界限制 //#region 限制最大/最小尺寸
if (this.allowOverflow) { // 限制宽度
this.x = newX if (width < minWidth) {
this.y = newY // 左缩时要修正X坐标否则会跳动
this.width = newWidth if (resizeDir.includes('l')) x -= minWidth - width
this.height = newHeight width = minWidth
this.style.width = `${newWidth}px` } else if (width > maxWidth) {
this.style.height = `${newHeight}px` if (resizeDir.includes('l')) x += width - maxWidth
this.applyPosition(newX, newY, false) width = maxWidth
return {
left: newX,
top: newY,
width: newWidth,
height: newHeight,
}
} }
// 限制高度
if (height < minHeight) {
if (resizeDir.includes('t')) y -= minHeight - height
height = minHeight
} else if (height > maxHeight) {
if (resizeDir.includes('t')) y += height - maxHeight
height = maxHeight
}
//#endregion
//#region 限制在容器边界内
const containerRect = (this.dragContainer || document.body).getBoundingClientRect() const containerRect = (this.dragContainer || document.body).getBoundingClientRect()
newX = Math.min(Math.max(0, newX), containerRect.width - newWidth) const maxLeft = containerRect.width - width
newY = Math.min(Math.max(0, newY), containerRect.height - newHeight) const maxTop = containerRect.height - height
this.x = newX // 左越界(从左侧缩放时)
this.y = newY if (x < 0) {
this.width = newWidth if (resizeDir.includes('l')) {
this.height = newHeight // 如果是往左拉出容器,锁定边界
this.style.width = `${newWidth}px` width += x // 因为x是负数相当于减小宽度
this.style.height = `${newHeight}px` }
this.applyPosition(newX, newY, false) x = 0
}
// 顶部越界(从上侧缩放时)
if (y < 0) {
if (resizeDir.includes('t')) {
height += y // y是负数相当于减小高度
}
y = 0
}
// 右越界(从右侧缩放时)
if (x + width > containerRect.width) {
if (resizeDir.includes('r')) {
width = containerRect.width - x
} else {
x = Math.min(x, maxLeft)
}
}
// 底部越界(从下侧缩放时)
if (y + height > containerRect.height) {
if (resizeDir.includes('b')) {
height = containerRect.height - y
} else {
y = Math.min(y, maxTop)
}
}
//#endregion
// 二次防护:确保不小于最小值
width = Math.max(width, minWidth)
height = Math.max(height, minHeight)
return { return {
left: newX, x,
top: newY, y,
width: newWidth, width,
height: newHeight, height
} }
} }
/**
* 缩放结束
* @param e
* @private
*/
private resizeUp(e: PointerEvent) { private resizeUp(e: PointerEvent) {
if (!this.resizable) return if (!this.resizable) return
@@ -617,12 +733,16 @@ export class WindowFormElement extends LitElement {
startY, startY,
startW, startW,
startH, startH,
rect.left, rect.x,
rect.top, rect.y,
rect.width, rect.width,
rect.height, rect.height,
400, 400,
() => { (x, y, w, h) => {
this.applyWindowStyle(x, y, w, h)
},
(x, y, w, h) => {
this.applyWindowStyle(x, y, w, h)
this.style.display = 'none' this.style.display = 'none'
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('windowForm:stateChange:minimize', { new CustomEvent('windowForm:stateChange:minimize', {
@@ -667,7 +787,11 @@ export class WindowFormElement extends LitElement {
targetW, targetW,
targetH, targetH,
300, 300,
() => { (x, y, w, h) => {
this.applyWindowStyle(x, y, w, h)
},
(x, y, w, h) => {
this.applyWindowStyle(x, y, w, h)
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('windowForm:stateChange:maximize', { new CustomEvent('windowForm:stateChange:maximize', {
detail: { state: this.windowFormState }, detail: { state: this.windowFormState },
@@ -713,12 +837,16 @@ export class WindowFormElement extends LitElement {
startY, startY,
startW, startW,
startH, startH,
b.left, b.x,
b.top, b.y,
b.width, b.width,
b.height, b.height,
300, 300,
() => { (x, y, w, h) => {
this.applyWindowStyle(x, y, w, h)
},
(x, y, w, h) => {
this.applyWindowStyle(x, y, w, h)
onComplete?.() onComplete?.()
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('windowForm:stateChange:restore', { new CustomEvent('windowForm:stateChange:restore', {
@@ -731,6 +859,24 @@ export class WindowFormElement extends LitElement {
) )
} }
/**
* 应用窗体样式
* @param x
* @param y
* @param w
* @param h
* @private
*/
private applyWindowStyle(x: number, y: number, w: number, h: number) {
this.width = w
this.height = h
this.x = x
this.y = y
this.style.width = `${w}px`
this.style.height = `${h}px`
this.style.transform = `translate(${x}px, ${y}px)`
}
private windowFormClose() { private windowFormClose() {
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('windowForm:close', { new CustomEvent('windowForm:close', {
@@ -764,7 +910,8 @@ export class WindowFormElement extends LitElement {
targetW: number, targetW: number,
targetH: number, targetH: number,
duration: number, duration: number,
onComplete?: () => void, onUpdating?: (x: number, y: number, w: number, h: number) => void,
onComplete?: (x: number, y: number, w: number, h: number) => void,
) { ) {
const startTime = performance.now() const startTime = performance.now()
const step = (now: number) => { const step = (now: number) => {
@@ -777,17 +924,14 @@ export class WindowFormElement extends LitElement {
const w = startW + (targetW - startW) * ease const w = startW + (targetW - startW) * ease
const h = startH + (targetH - startH) * ease const h = startH + (targetH - startH) * ease
this.style.width = `${w}px` onUpdating?.(x, y, w, h)
this.style.height = `${h}px`
this.applyPosition(x, y, false)
if (progress < 1) { if (progress < 1) {
requestAnimationFrame(step) requestAnimationFrame(step)
} else { } else {
this.style.width = `${targetW}px` this.style.width = `${targetW}px`
this.style.height = `${targetH}px` this.style.height = `${targetH}px`
this.applyPosition(targetX, targetY, true) onComplete?.(x, y, w, h)
onComplete?.()
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('windowForm:stateChange', { new CustomEvent('windowForm:stateChange', {
detail: { state: this.windowFormState }, detail: { state: this.windowFormState },
@@ -800,10 +944,10 @@ export class WindowFormElement extends LitElement {
requestAnimationFrame(step) requestAnimationFrame(step)
} }
private updateTargetBounds(left: number, top: number, width?: number, height?: number) { private updateTargetBounds(x: number, y: number, width?: number, height?: number) {
this.targetBounds = { this.targetBounds = {
left, x,
top, y,
width: width ?? this.offsetWidth, width: width ?? this.offsetWidth,
height: height ?? this.offsetHeight, height: height ?? this.offsetHeight,
} }