HTMLShape.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /* eslint-disable @typescript-eslint/no-explicit-any */
  2. import * as React from 'react'
  3. import { TLBoxShape, TLBoxShapeProps } from '@tldraw/core'
  4. import { HTMLContainer, TLComponentProps, useApp } from '@tldraw/react'
  5. import { observer } from 'mobx-react-lite'
  6. import { CustomStyleProps, withClampedStyles } from './style-props'
  7. import { useCameraMovingRef } from '~hooks/useCameraMoving'
  8. import type { Shape } from '~lib'
  9. export interface HTMLShapeProps extends TLBoxShapeProps, CustomStyleProps {
  10. type: 'html'
  11. html: string
  12. }
  13. export class HTMLShape extends TLBoxShape<HTMLShapeProps> {
  14. static id = 'html'
  15. static defaultProps: HTMLShapeProps = {
  16. id: 'html',
  17. type: 'html',
  18. parentId: 'page',
  19. point: [0, 0],
  20. size: [600, 320],
  21. stroke: '#000000',
  22. fill: '#ffffff',
  23. strokeWidth: 2,
  24. opacity: 1,
  25. html: '',
  26. }
  27. canChangeAspectRatio = true
  28. canFlip = false
  29. canEdit = true
  30. ReactComponent = observer(({ events, isErasing, isEditing }: TLComponentProps) => {
  31. const {
  32. props: { opacity, html },
  33. } = this
  34. const isMoving = useCameraMovingRef()
  35. const app = useApp<Shape>()
  36. const isSelected = app.selectedIds.has(this.id)
  37. const tlEventsEnabled =
  38. isMoving || (isSelected && !isEditing) || app.selectedTool.id !== 'select'
  39. const stop = React.useCallback(
  40. e => {
  41. if (!tlEventsEnabled) {
  42. // TODO: pinching inside Logseq Shape issue
  43. e.stopPropagation()
  44. }
  45. },
  46. [tlEventsEnabled]
  47. )
  48. return (
  49. <HTMLContainer
  50. style={{
  51. overflow: 'hidden',
  52. pointerEvents: 'all',
  53. opacity: isErasing ? 0.2 : opacity,
  54. }}
  55. {...events}
  56. >
  57. <div
  58. onWheelCapture={stop}
  59. onPointerDown={stop}
  60. onPointerUp={stop}
  61. className="html-container"
  62. style={{
  63. width: '100%',
  64. height: '100%',
  65. pointerEvents: isEditing ? 'all' : 'none',
  66. userSelect: 'none',
  67. position: 'relative',
  68. margin: 0,
  69. overflow: 'auto',
  70. }}
  71. dangerouslySetInnerHTML={{ __html: html }}
  72. />
  73. </HTMLContainer>
  74. )
  75. })
  76. ReactIndicator = observer(() => {
  77. const {
  78. props: {
  79. size: [w, h],
  80. },
  81. } = this
  82. return <rect width={w} height={h} fill="transparent" />
  83. })
  84. validateProps = (props: Partial<HTMLShapeProps>) => {
  85. if (props.size !== undefined) {
  86. props.size[0] = Math.max(props.size[0], 120)
  87. props.size[1] = Math.max(props.size[1], 80)
  88. }
  89. return withClampedStyles(props)
  90. }
  91. }