/* eslint-disable @typescript-eslint/no-explicit-any */ import { delay, TLBoxShape, TLBoxShapeProps, 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 * as React from 'react' import type { SizeLevel, Shape } from '.' import { useCameraMovingRef } from '../../hooks/useCameraMoving' import { withClampedStyles } from './style-props' export interface HTMLShapeProps extends TLBoxShapeProps { type: 'html' html: string scaleLevel?: SizeLevel } const levelToScale = { xs: 0.5, sm: 0.8, md: 1, lg: 1.5, xl: 2, xxl: 3, } export class HTMLShape extends TLBoxShape { static id = 'html' static defaultProps: HTMLShapeProps = { id: 'html', type: 'html', parentId: 'page', point: [0, 0], size: [600, 0], html: '', } canChangeAspectRatio = true canFlip = false canEdit = true htmlAnchorRef = React.createRef() @computed get scaleLevel() { return this.props.scaleLevel ?? 'md' } @action setScaleLevel = async (v?: SizeLevel) => { const newSize = Vec.mul( this.props.size, levelToScale[(v as SizeLevel) ?? 'md'] / levelToScale[this.props.scaleLevel ?? 'md'] ) this.update({ scaleLevel: v, }) await delay() this.update({ size: newSize, }) } onResetBounds = (info?: TLResetBoundsInfo) => { if (this.htmlAnchorRef.current) { const rect = this.htmlAnchorRef.current.getBoundingClientRect() const [w, h] = Vec.div([rect.width, rect.height], info?.zoom ?? 1) const clamp = (v: number) => Math.max(Math.min(v || 400, 1400), 10) this.update({ size: [clamp(w), clamp(h)], }) } return this } ReactComponent = observer(({ events, isErasing, isEditing }: TLComponentProps) => { const { props: { html, scaleLevel }, } = this const isMoving = useCameraMovingRef() const app = useApp() const isSelected = app.selectedIds.has(this.id) const tlEventsEnabled = isMoving || (isSelected && !isEditing) || app.selectedTool.id !== 'select' const stop = React.useCallback( e => { if (!tlEventsEnabled) { // TODO: pinching inside Logseq Shape issue e.stopPropagation() } }, [tlEventsEnabled] ) const scaleRatio = levelToScale[scaleLevel ?? 'md'] React.useEffect(() => { if (this.props.size[1] === 0) { this.onResetBounds({ zoom: app.viewport.camera.zoom }) app.persist(true) } }, []) return (
) }) ReactIndicator = observer(() => { const { props: { size: [w, h], }, } = this return }) validateProps = (props: Partial) => { if (props.size !== undefined) { props.size[0] = Math.max(props.size[0], 1) props.size[1] = Math.max(props.size[1], 1) } return withClampedStyles(this, props) } }