Merge branch 'whiteboards' into feat/whiteboards-create-button

pull/6707/head
Konstantinos Kaloutas 2022-09-16 10:22:54 +03:00
commit b6ad16417e
14 changed files with 127 additions and 173 deletions

View File

@ -7,7 +7,7 @@ import * as React from 'react'
import { Arrow } from './arrow/Arrow'
import { getArrowPath } from './arrow/arrowHelpers'
import { CustomStyleProps, withClampedStyles } from './style-props'
import { getTextLabelSize } from './text/getTextSize'
import { getTextLabelSize } from '@tldraw/core'
import { LabelMask } from './text/LabelMask'
import { TextLabel } from './text/TextLabel'
@ -53,8 +53,7 @@ export class LineShape extends TLLineShape<LineShapeProps> {
label,
id,
} = this.props
const app = useApp()
const labelSize = label || isEditing ? getTextLabelSize(label, font) : [0, 0]
const labelSize = label || isEditing ? getTextLabelSize(label, font, 4) : [0, 0]
const midPoint = Vec.med(start.point, end.point)
const dist = Vec.dist(start.point, end.point)
const scale = Math.max(
@ -69,7 +68,6 @@ export class LineShape extends TLLineShape<LineShapeProps> {
const handleLabelChange = React.useCallback(
(label: string) => {
this.update?.({ label })
app.persist()
},
[label]
)
@ -105,7 +103,7 @@ export class LineShape extends TLLineShape<LineShapeProps> {
handles: { start, end },
} = this.props
const bounds = this.getBounds()
const labelSize = label ? getTextLabelSize(label, font) : [0, 0]
const labelSize = label ? getTextLabelSize(label, font, 4) : [0, 0]
const midPoint = Vec.med(start.point, end.point)
const dist = Vec.dist(start.point, end.point)
const scale = Math.max(

View File

@ -800,6 +800,10 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
ReactIndicator = observer(() => {
const bounds = this.getBounds()
const app = useApp<Shape>()
if (app.selectedShapesArray.length === 1) {
return null
}
return <rect width={bounds.width} height={bounds.height} fill="transparent" rx={8} ry={8} />
})

View File

@ -1,6 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { TextUtils, TLBounds, TLResizeStartInfo, TLTextShape, TLTextShapeProps } from '@tldraw/core'
import { HTMLContainer, TLComponentProps, TLTextMeasure } from '@tldraw/react'
import {
getTextLabelSize,
TextUtils,
TLBounds,
TLResizeStartInfo,
TLTextShape,
TLTextShapeProps,
} from '@tldraw/core'
import { HTMLContainer, TLComponentProps } from '@tldraw/react'
import { action, computed } from 'mobx'
import { observer } from 'mobx-react-lite'
import * as React from 'react'
@ -163,7 +170,7 @@ export class TextShape extends TLTextShape<TextShapeProps> {
React.useLayoutEffect(() => {
const { fontFamily, fontSize, fontWeight, lineHeight, padding } = this.props
const { width, height } = this.measure.measureText(
const [width, height] = getTextLabelSize(
text,
{ fontFamily, fontSize, fontWeight, lineHeight },
padding
@ -255,10 +262,6 @@ export class TextShape extends TLTextShape<TextShapeProps> {
return withClampedStyles(this, props)
}
// Custom
private measure = new TLTextMeasure()
getAutoSizedBoundingBox(props = {} as Partial<TextShapeProps>) {
const {
text = this.props.text,
@ -268,7 +271,7 @@ export class TextShape extends TLTextShape<TextShapeProps> {
lineHeight = this.props.lineHeight,
padding = this.props.padding,
} = props
const { width, height } = this.measure.measureText(
const [width, height] = getTextLabelSize(
text,
{ fontFamily, fontSize, lineHeight, fontWeight },
padding

View File

@ -1,7 +1,6 @@
import { TextUtils } from '@tldraw/core'
import * as React from 'react'
import { LETTER_SPACING } from './constants'
import { getTextLabelSize } from './getTextSize'
import { getTextLabelSize } from '@tldraw/core'
import { TextAreaUtils } from './TextAreaUtils'
const stopPropagation = (e: KeyboardEvent | React.SyntheticEvent<any, Event>) => e.stopPropagation()
@ -122,7 +121,7 @@ export const TextLabel = React.memo(function TextLabel({
React.useLayoutEffect(() => {
const elm = rInnerWrapper.current
if (!elm) return
const size = getTextLabelSize(text, font)
const size = getTextLabelSize(text, font, 4)
elm.style.transform = `scale(${scale}, ${scale}) translate(${offsetX}px, ${offsetY}px)`
elm.style.width = size[0] + 1 + 'px'
elm.style.height = size[1] + 1 + 'px'
@ -136,7 +135,6 @@ export const TextLabel = React.memo(function TextLabel({
style={{
font,
color,
letterSpacing: LETTER_SPACING,
pointerEvents: text ? 'all' : 'none',
userSelect: isEditing ? 'text' : 'none',
}}

View File

@ -1,2 +1 @@
export const LETTER_SPACING = '-0.03em'
export const GHOSTED_OPACITY = 0.3

View File

@ -1,82 +0,0 @@
import { LETTER_SPACING } from './constants'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let melm: any
function getMeasurementDiv() {
// A div used for measurement
document.getElementById('__textLabelMeasure')?.remove()
const pre = document.createElement('pre')
pre.id = '__textLabelMeasure'
Object.assign(pre.style, {
whiteSpace: 'pre',
width: 'auto',
border: '1px solid transparent',
padding: '4px',
margin: '0px',
letterSpacing: LETTER_SPACING,
opacity: '0',
position: 'absolute',
top: '-500px',
left: '0px',
zIndex: '9999',
pointerEvents: 'none',
userSelect: 'none',
alignmentBaseline: 'mathematical',
dominantBaseline: 'mathematical',
})
pre.tabIndex = -1
document.body.appendChild(pre)
return pre
}
if (typeof window !== 'undefined') {
melm = getMeasurementDiv()
}
const cache = new Map<string, [number, number]>()
const getKey = (text: string, font: string) => {
return `${text}-${font}`
}
const hasCached = (text: string, font: string) => {
const key = getKey(text, font)
return cache.has(key)
}
const getCached = (text: string, font: string) => {
const key = getKey(text, font)
return cache.get(key)
}
const saveCached = (text: string, font: string, size: [number, number]) => {
const key = getKey(text, font)
cache.set(key, size)
}
export function getTextLabelSize(text: string, font: string) {
if (!text) {
return [16, 32]
}
if (!hasCached(text, font)) {
if (!melm) {
// We're in SSR
return [10, 10]
}
if (!melm.parent) document.body.appendChild(melm)
melm.textContent = text
melm.style.font = font
// In tests, offsetWidth and offsetHeight will be 0
const width = melm.offsetWidth || 1
const height = melm.offsetHeight || 1
saveCached(text, font, [width, height])
}
return getCached(text, font)!
}

View File

@ -22,7 +22,7 @@ export class EditingShapeState<
onExit = () => {
// cleanup text shapes
if ('text' in this.editingShape.props) {
if (this.editingShape && 'text' in this.editingShape.props) {
// @ts-expect-error better typing
const newText = this.editingShape.props['text'].trim()

View File

@ -0,0 +1,105 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let melm: any
interface TLTextMeasureStyles {
fontStyle?: string
fontVariant?: string
fontWeight?: number
fontSize: number
fontFamily: string
lineHeight: number
}
function getMeasurementDiv() {
// A div used for measurement
document.getElementById('__textLabelMeasure')?.remove()
const pre = document.createElement('pre')
pre.id = '__textLabelMeasure'
Object.assign(pre.style, {
whiteSpace: 'pre',
width: 'auto',
borderLeft: '2px solid transparent',
borderRight: '1px solid transparent',
borderBottom: '2px solid transparent',
padding: '0px',
margin: '0px',
opacity: '0',
position: 'absolute',
top: '-500px',
left: '0px',
zIndex: '9999',
userSelect: 'none',
pointerEvents: 'none',
})
pre.tabIndex = -1
document.body.appendChild(pre)
return pre
}
if (typeof window !== 'undefined') {
melm = getMeasurementDiv()
}
const cache = new Map<string, [number, number]>()
const getKey = (text: string, font: string, padding: number) => {
return `${text}-${font}-${padding}`
}
const hasCached = (text: string, font: string, padding: number) => {
const key = getKey(text, font, padding)
return cache.has(key)
}
const getCached = (text: string, font: string, padding: number) => {
const key = getKey(text, font, padding)
return cache.get(key)
}
const saveCached = (text: string, font: string, padding: number, size: [number, number]) => {
const key = getKey(text, font, padding)
cache.set(key, size)
}
export function getTextLabelSize(
text: string,
fontOrStyles: string | TLTextMeasureStyles,
padding = 0
) {
if (!text) {
return [16, 32]
}
let font: string
if (typeof fontOrStyles === 'string') {
font = fontOrStyles
} else {
font = `${fontOrStyles.fontStyle ?? 'normal'} ${fontOrStyles.fontVariant ?? 'normal'} ${
fontOrStyles.fontWeight ?? 'normal'
} ${fontOrStyles.fontSize}px/${fontOrStyles.fontSize * fontOrStyles.lineHeight}px ${
fontOrStyles.fontFamily
}`
}
if (!hasCached(text, font, padding)) {
if (!melm) {
// We're in SSR
return [10, 10]
}
if (!melm.parent) document.body.appendChild(melm)
melm.innerHTML = `${text}&#8203;`
melm.style.font = font
melm.style.padding = padding + 'px'
// In tests, offsetWidth and offsetHeight will be 0
const width = melm.offsetWidth || 1
const height = melm.offsetHeight || 1
saveCached(text, font, padding, [width, height])
}
return getCached(text, font, padding)!
}

View File

@ -7,6 +7,7 @@ export * from './PolygonUtils'
export * from './SvgPathUtils'
export * from './DataUtils'
export * from './TextUtils'
export * from './getTextSize'
export function uniqueId() {
return uuid.v1()

View File

@ -138,7 +138,6 @@ export const Canvas = observer(function Renderer<S extends TLReactShape>({
/>
))}
{!app.isIn('select.pinching') &&
selectedShapes?.length !== 1 &&
selectedShapes?.map(shape => (
<Indicator
key={'selected_indicator_' + shape.id}

View File

@ -52,12 +52,6 @@ export function useCanvasEvents() {
const onDrop = async (e: React.DragEvent<Element>) => {
e.preventDefault()
Array.from(e.dataTransfer.items).forEach(item => {
const type = item.type
item.getAsString(s => {
console.log(type, ":", s)
})
})
if (!e.dataTransfer.files?.length) return
const point = [e.clientX, e.clientY]

View File

@ -1,63 +0,0 @@
import { uniqueId } from '@tldraw/core'
export interface TLTextMeasureStyles {
fontStyle?: string
fontVariant?: string
fontWeight?: number
fontSize: number
fontFamily: string
lineHeight: number
}
export class TLTextMeasure {
private elm: HTMLPreElement
constructor() {
const pre = document.createElement('pre')
const id = uniqueId()
pre.id = `__textMeasure_${id}`
Object.assign(pre.style, {
whiteSpace: 'pre',
width: 'auto',
borderLeft: '2px solid transparent',
borderRight: '1px solid transparent',
borderBottom: '2px solid transparent',
padding: '0px',
margin: '0px',
opacity: '0',
position: 'absolute',
top: '-500px',
left: '0px',
zIndex: '9999',
userSelect: 'none',
pointerEvents: 'none',
})
pre.tabIndex = -1
document.body.appendChild(pre)
this.elm = pre
}
measureText = (text: string, styles: TLTextMeasureStyles, padding = 0) => {
const { elm } = this
elm.style.setProperty(
'font',
`${styles.fontStyle ?? 'normal'} ${styles.fontVariant ?? 'normal'} ${
styles.fontWeight ?? 'normal'
} ${styles.fontSize}px/${styles.fontSize * styles.lineHeight}px ${styles.fontFamily}`
)
elm.style.padding = padding + 'px'
elm.innerHTML = `${text}&#8203;`
const width = elm.offsetWidth ?? 1
const height = elm.offsetHeight ?? 1
return {
width,
height,
}
}
}

View File

@ -1 +0,0 @@
export * from './TLTextMeasure'

View File

@ -1,4 +1,3 @@
export * from './shapes'
export * from './TLReactShape'
export * from './TLReactApp'
export * from './TLTextMeasure'