wip: auto height calculation

pull/8279/head
Konstantinos Kaloutas 2023-01-11 20:41:44 +02:00
parent 50fc185df0
commit 4dac7a2776
1 changed files with 89 additions and 5 deletions

View File

@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { TLBoxShape, TLBoxShapeProps } from '@tldraw/core'
import { HTMLContainer, TLComponentProps } from '@tldraw/react'
import { TLBoxShape, TLBoxShapeProps, TLResizeInfo, TLResetBoundsInfo } from '@tldraw/core'
import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
import Vec from '@tldraw/vec'
import { action, computed } from 'mobx'
import { observer } from 'mobx-react-lite'
import { withClampedStyles } from './style-props'
@ -27,8 +28,10 @@ export class TweetShape extends TLBoxShape<TweetShapeProps> {
}
canFlip = false
canEdit = true
initialHeightCalculated = true
getInnerHeight: (() => number) | null = null // will be overridden in the hook
ref = React.createRef<HTMLDivElement>()
@computed get embedId() {
const url = this.props.url
@ -45,6 +48,20 @@ export class TweetShape extends TLBoxShape<TweetShapeProps> {
const {
renderers: { Tweet },
} = React.useContext(LogseqContext)
const app = useApp<Shape>()
const cpRefContainer = React.useRef<HTMLDivElement>(null)
this.useComponentSize(cpRefContainer, '.twitter-tweet')
React.useEffect(() => {
if (!this.initialHeightCalculated) {
setTimeout(() => {
this.onResetBounds()
app.persist(true)
})
}
}, [this.initialHeightCalculated])
return (
<HTMLContainer
@ -56,7 +73,7 @@ export class TweetShape extends TLBoxShape<TweetShapeProps> {
{...events}
>
<div
className="rounded-lg w-full h-full relative overflow-hidden shadow-xl"
className="rounded-xl w-full h-full relative shadow-xl"
style={{
pointerEvents: isEditing ? 'all' : 'none',
userSelect: 'none',
@ -79,9 +96,76 @@ export class TweetShape extends TLBoxShape<TweetShapeProps> {
return <rect width={w} height={h} fill="transparent" rx={8} ry={8} />
})
useComponentSize<T extends HTMLElement>(ref: React.RefObject<T> | null, selector = '') {
const [size, setSize] = React.useState<[number, number]>([0, 0])
const app = useApp<Shape>()
React.useEffect(() => {
if (ref?.current) {
const el = selector ? ref.current.querySelector<HTMLElement>(selector) : ref.current
if (el) {
const updateSize = () => {
const { width, height } = el.getBoundingClientRect()
const bound = Vec.div([width, height], app.viewport.camera.zoom) as [number, number]
setSize(bound)
return bound
}
updateSize()
this.getInnerHeight = () => updateSize()[1]
const resizeObserver = new ResizeObserver(() => {
updateSize()
})
resizeObserver.observe(el)
return () => {
resizeObserver.disconnect()
}
}
}
return () => {}
}, [ref, selector])
return size
}
getAutoResizeHeight() {
if (this.getInnerHeight) {
return this.getInnerHeight()
}
return null
}
onResetBounds = (info?: TLResetBoundsInfo) => {
const height = this.getAutoResizeHeight()
if (height !== null && Math.abs(height - this.props.size[1]) > 1) {
this.update({
size: [this.props.size[0], height],
})
this.initialHeightCalculated = true
}
return this
}
onResize = (initialProps: any, info: TLResizeInfo): this => {
const {
bounds,
rotation,
scale: [scaleX, scaleY],
} = info
const nextScale = [...this.scale]
if (scaleX < 0) nextScale[0] *= -1
if (scaleY < 0) nextScale[1] *= -1
const height = this.getAutoResizeHeight() ?? bounds.height
return this.update({
point: [bounds.minX, bounds.minY],
size: [Math.max(1, bounds.width), Math.max(1, height)],
scale: nextScale,
rotation,
})
}
validateProps = (props: Partial<TweetShapeProps>) => {
if (props.size !== undefined) {
props.size[0] = Math.max(props.size[0], 1)
props.size[0] = Math.min(Math.max(props.size[0], 1), 550)
props.size[1] = Math.max(props.size[1], 1)
}
return withClampedStyles(this, props)