@tldraw/editor 3.15.0-canary.11f7238a9bfa → 3.15.0-canary.175d131e5195
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +69 -7
- package/dist-cjs/index.js +3 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/SVGContainer.js +1 -1
- package/dist-cjs/lib/components/SVGContainer.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultBrush.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultBrush.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCursor.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultGrid.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultGrid.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultHandles.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultHandles.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js +27 -15
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +3 -3
- package/dist-cjs/lib/editor/Editor.js +42 -21
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +96 -101
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +20 -1
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +1 -1
- package/dist-cjs/lib/license/Watermark.js +2 -2
- package/dist-cjs/lib/license/Watermark.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +3 -1
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/geometry-constants.js +2 -2
- package/dist-cjs/lib/primitives/geometry/geometry-constants.js.map +2 -2
- package/dist-cjs/lib/primitives/intersect.js +4 -4
- package/dist-cjs/lib/primitives/intersect.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +4 -0
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +69 -7
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/SVGContainer.mjs +1 -1
- package/dist-esm/lib/components/SVGContainer.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultBrush.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultBrush.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCursor.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultGrid.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultGrid.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultHandles.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultHandles.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs +17 -15
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +42 -21
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +96 -101
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +20 -1
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +1 -1
- package/dist-esm/lib/license/Watermark.mjs +2 -2
- package/dist-esm/lib/license/Watermark.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +3 -1
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/geometry-constants.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/geometry-constants.mjs.map +2 -2
- package/dist-esm/lib/primitives/intersect.mjs +5 -5
- package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +4 -0
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +17 -4
- package/package.json +9 -8
- package/src/index.ts +1 -0
- package/src/lib/components/SVGContainer.tsx +1 -1
- package/src/lib/components/default-components/DefaultBrush.tsx +1 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +1 -1
- package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +1 -1
- package/src/lib/components/default-components/DefaultCursor.tsx +1 -1
- package/src/lib/components/default-components/DefaultGrid.tsx +1 -1
- package/src/lib/components/default-components/DefaultHandles.tsx +5 -1
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +1 -1
- package/src/lib/components/default-components/DefaultSnapIndictor.tsx +1 -1
- package/src/lib/components/default-components/DefaultSpinner.tsx +12 -12
- package/src/lib/editor/Editor.test.ts +407 -0
- package/src/lib/editor/Editor.ts +55 -22
- package/src/lib/editor/managers/TextManager/TextManager.ts +108 -128
- package/src/lib/editor/shapes/ShapeUtil.ts +57 -0
- package/src/lib/editor/tools/StateNode.test.ts +285 -0
- package/src/lib/editor/tools/StateNode.ts +27 -1
- package/src/lib/hooks/useEditorComponents.tsx +1 -1
- package/src/lib/license/Watermark.tsx +2 -2
- package/src/lib/primitives/geometry/Arc2d.ts +2 -2
- package/src/lib/primitives/geometry/Circle2d.ts +2 -2
- package/src/lib/primitives/geometry/CubicBezier2d.ts +4 -1
- package/src/lib/primitives/geometry/Ellipse2d.ts +2 -2
- package/src/lib/primitives/geometry/geometry-constants.ts +2 -1
- package/src/lib/primitives/intersect.test.ts +946 -0
- package/src/lib/primitives/intersect.ts +12 -5
- package/src/lib/primitives/utils.ts +11 -0
- package/src/version.ts +3 -3
- package/src/lib/test/currentToolIdMask.test.ts +0 -49
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -1803,7 +1803,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1803
1803
|
}
|
|
1804
1804
|
|
|
1805
1805
|
/**
|
|
1806
|
-
* Select all
|
|
1806
|
+
* Select all shapes. If the user has selected shapes that share a parent,
|
|
1807
|
+
* select all shapes within that parent. If the user has not selected any shapes,
|
|
1808
|
+
* or if the shapes shapes are only on select all shapes on the current page.
|
|
1807
1809
|
*
|
|
1808
1810
|
* @example
|
|
1809
1811
|
* ```ts
|
|
@@ -1813,11 +1815,34 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1813
1815
|
* @public
|
|
1814
1816
|
*/
|
|
1815
1817
|
selectAll(): this {
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
+
let parentToSelectWithinId: TLParentId | null = null
|
|
1819
|
+
|
|
1820
|
+
const selectedShapeIds = this.getSelectedShapeIds()
|
|
1821
|
+
|
|
1822
|
+
// If we have selected shapes, try to find a parent to select within
|
|
1823
|
+
if (selectedShapeIds.length > 0) {
|
|
1824
|
+
for (const id of selectedShapeIds) {
|
|
1825
|
+
const shape = this.getShape(id)
|
|
1826
|
+
if (!shape) continue
|
|
1827
|
+
if (parentToSelectWithinId === null) {
|
|
1828
|
+
// If we haven't found a parent yet, set this parent as the parent to select within
|
|
1829
|
+
parentToSelectWithinId = shape.parentId
|
|
1830
|
+
} else if (parentToSelectWithinId !== shape.parentId) {
|
|
1831
|
+
// If we've found two different parents, we can't select all, do nothing
|
|
1832
|
+
return this
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
// If we haven't found a parent from our selected shapes, select the current page
|
|
1838
|
+
if (!parentToSelectWithinId) {
|
|
1839
|
+
parentToSelectWithinId = this.getCurrentPageId()
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
// Select all the unlocked shapes within the parent
|
|
1843
|
+
const ids = this.getSortedChildIdsForParent(parentToSelectWithinId)
|
|
1818
1844
|
if (ids.length <= 0) return this
|
|
1819
1845
|
this.setSelectedShapes(this._getUnlockedShapeIds(ids))
|
|
1820
|
-
|
|
1821
1846
|
return this
|
|
1822
1847
|
}
|
|
1823
1848
|
|
|
@@ -1838,10 +1863,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1838
1863
|
firstParentId &&
|
|
1839
1864
|
selectedShapeIds.every((shapeId) => this.getShape(shapeId)?.parentId === firstParentId) &&
|
|
1840
1865
|
!isPageId(firstParentId)
|
|
1866
|
+
const filteredShapes = isSelectedWithinContainer
|
|
1867
|
+
? this.getCurrentPageShapes().filter((shape) => shape.parentId === firstParentId)
|
|
1868
|
+
: this.getCurrentPageShapes().filter((shape) => isPageId(shape.parentId))
|
|
1841
1869
|
const readingOrderShapes = isSelectedWithinContainer
|
|
1842
|
-
? this._getShapesInReadingOrder(
|
|
1843
|
-
this.getCurrentPageShapes().filter((shape) => shape.parentId === firstParentId)
|
|
1844
|
-
)
|
|
1870
|
+
? this._getShapesInReadingOrder(filteredShapes)
|
|
1845
1871
|
: this.getCurrentPageShapesInReadingOrder()
|
|
1846
1872
|
const currentShapeId: TLShapeId | undefined =
|
|
1847
1873
|
selectedShapeIds.length === 1
|
|
@@ -1858,7 +1884,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1858
1884
|
adjacentShapeId = shapeIds[adjacentIndex]
|
|
1859
1885
|
} else {
|
|
1860
1886
|
if (!currentShapeId) return
|
|
1861
|
-
adjacentShapeId = this.getNearestAdjacentShape(currentShapeId, direction)
|
|
1887
|
+
adjacentShapeId = this.getNearestAdjacentShape(filteredShapes, currentShapeId, direction)
|
|
1862
1888
|
}
|
|
1863
1889
|
|
|
1864
1890
|
const shape = this.getShape(adjacentShapeId)
|
|
@@ -1957,6 +1983,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1957
1983
|
* @public
|
|
1958
1984
|
*/
|
|
1959
1985
|
getNearestAdjacentShape(
|
|
1986
|
+
shapes: TLShape[],
|
|
1960
1987
|
currentShapeId: TLShapeId,
|
|
1961
1988
|
direction: 'left' | 'right' | 'up' | 'down'
|
|
1962
1989
|
): TLShapeId {
|
|
@@ -1964,7 +1991,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1964
1991
|
const currentShape = this.getShape(currentShapeId)
|
|
1965
1992
|
if (!currentShape) return currentShapeId
|
|
1966
1993
|
|
|
1967
|
-
const shapes = this.getCurrentPageShapes()
|
|
1968
1994
|
const tabbableShapes = shapes.filter(
|
|
1969
1995
|
(shape) => this.getShapeUtil(shape).canTabTo(shape) && shape.id !== currentShapeId
|
|
1970
1996
|
)
|
|
@@ -4395,21 +4421,28 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4395
4421
|
*/
|
|
4396
4422
|
deletePage(page: TLPageId | TLPage): this {
|
|
4397
4423
|
const id = typeof page === 'string' ? page : page.id
|
|
4398
|
-
this.run(
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4424
|
+
this.run(
|
|
4425
|
+
() => {
|
|
4426
|
+
if (this.getIsReadonly()) return
|
|
4427
|
+
const pages = this.getPages()
|
|
4428
|
+
if (pages.length === 1) return
|
|
4402
4429
|
|
|
4403
|
-
|
|
4404
|
-
|
|
4430
|
+
const deletedPage = this.getPage(id)
|
|
4431
|
+
if (!deletedPage) return
|
|
4405
4432
|
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4433
|
+
if (id === this.getCurrentPageId()) {
|
|
4434
|
+
const index = pages.findIndex((page) => page.id === id)
|
|
4435
|
+
const next = pages[index - 1] ?? pages[index + 1]
|
|
4436
|
+
this.setCurrentPage(next.id)
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4439
|
+
const shapes = this.getSortedChildIdsForParent(deletedPage.id)
|
|
4440
|
+
this.deleteShapes(shapes)
|
|
4441
|
+
|
|
4442
|
+
this.store.remove([deletedPage.id])
|
|
4443
|
+
},
|
|
4444
|
+
{ ignoreShapeLock: true }
|
|
4445
|
+
)
|
|
4413
4446
|
return this
|
|
4414
4447
|
}
|
|
4415
4448
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BoxModel, TLDefaultHorizontalAlignStyle } from '@tldraw/tlschema'
|
|
2
|
+
import { objectMapKeys } from '@tldraw/utils'
|
|
2
3
|
import { Editor } from '../../Editor'
|
|
3
4
|
|
|
4
5
|
const fixNewLines = /\r?\n|\r/g
|
|
@@ -60,10 +61,18 @@ export interface TLMeasureTextSpanOpts {
|
|
|
60
61
|
|
|
61
62
|
const spaceCharacterRegex = /\s/
|
|
62
63
|
|
|
64
|
+
const initialDefaultStyles = Object.freeze({
|
|
65
|
+
'overflow-wrap': 'break-word',
|
|
66
|
+
'word-break': 'auto',
|
|
67
|
+
width: null,
|
|
68
|
+
height: null,
|
|
69
|
+
'max-width': null,
|
|
70
|
+
'min-width': null,
|
|
71
|
+
})
|
|
72
|
+
|
|
63
73
|
/** @public */
|
|
64
74
|
export class TextManager {
|
|
65
75
|
private elm: HTMLDivElement
|
|
66
|
-
private defaultStyles: Record<string, string | null>
|
|
67
76
|
|
|
68
77
|
constructor(public editor: Editor) {
|
|
69
78
|
const elm = document.createElement('div')
|
|
@@ -73,31 +82,34 @@ export class TextManager {
|
|
|
73
82
|
elm.tabIndex = -1
|
|
74
83
|
this.editor.getContainer().appendChild(elm)
|
|
75
84
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
'word-break': 'auto',
|
|
81
|
-
width: null,
|
|
82
|
-
height: null,
|
|
83
|
-
'max-width': null,
|
|
84
|
-
'min-width': null,
|
|
85
|
+
this.elm = elm
|
|
86
|
+
|
|
87
|
+
for (const key of objectMapKeys(initialDefaultStyles)) {
|
|
88
|
+
elm.style.setProperty(key, initialDefaultStyles[key])
|
|
85
89
|
}
|
|
90
|
+
}
|
|
86
91
|
|
|
87
|
-
|
|
92
|
+
private setElementStyles(styles: Record<string, string | undefined>) {
|
|
93
|
+
const stylesToReinstate = {} as any
|
|
94
|
+
for (const key of objectMapKeys(styles)) {
|
|
95
|
+
if (typeof styles[key] === 'string') {
|
|
96
|
+
const oldValue = this.elm.style.getPropertyValue(key)
|
|
97
|
+
if (oldValue === styles[key]) continue
|
|
98
|
+
stylesToReinstate[key] = oldValue
|
|
99
|
+
this.elm.style.setProperty(key, styles[key])
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return () => {
|
|
103
|
+
for (const key of objectMapKeys(stylesToReinstate)) {
|
|
104
|
+
this.elm.style.setProperty(key, stylesToReinstate[key])
|
|
105
|
+
}
|
|
106
|
+
}
|
|
88
107
|
}
|
|
89
108
|
|
|
90
109
|
dispose() {
|
|
91
110
|
return this.elm.remove()
|
|
92
111
|
}
|
|
93
112
|
|
|
94
|
-
private resetElmStyles() {
|
|
95
|
-
const { elm, defaultStyles } = this
|
|
96
|
-
for (const key in defaultStyles) {
|
|
97
|
-
elm.style.setProperty(key, defaultStyles[key])
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
113
|
measureText(textToMeasure: string, opts: TLMeasureTextOpts): BoxModel & { scrollWidth: number } {
|
|
102
114
|
const div = document.createElement('div')
|
|
103
115
|
div.textContent = normalizeTextForDom(textToMeasure)
|
|
@@ -107,54 +119,36 @@ export class TextManager {
|
|
|
107
119
|
measureHtml(html: string, opts: TLMeasureTextOpts): BoxModel & { scrollWidth: number } {
|
|
108
120
|
const { elm } = this
|
|
109
121
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
122
|
+
const newStyles = {
|
|
123
|
+
'font-family': opts.fontFamily,
|
|
124
|
+
'font-style': opts.fontStyle,
|
|
125
|
+
'font-weight': opts.fontWeight,
|
|
126
|
+
'font-size': opts.fontSize + 'px',
|
|
127
|
+
'line-height': opts.lineHeight.toString(),
|
|
128
|
+
padding: opts.padding,
|
|
129
|
+
'max-width': opts.maxWidth ? opts.maxWidth + 'px' : undefined,
|
|
130
|
+
'min-width': opts.minWidth ? opts.minWidth + 'px' : undefined,
|
|
131
|
+
'overflow-wrap': opts.disableOverflowWrapBreaking ? 'normal' : undefined,
|
|
132
|
+
...opts.otherStyles,
|
|
117
133
|
}
|
|
118
134
|
|
|
119
|
-
|
|
135
|
+
const restoreStyles = this.setElementStyles(newStyles)
|
|
120
136
|
|
|
121
|
-
|
|
122
|
-
|
|
137
|
+
try {
|
|
138
|
+
elm.innerHTML = html
|
|
123
139
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
elm.style.setProperty('font-weight', opts.fontWeight)
|
|
127
|
-
elm.style.setProperty('font-size', opts.fontSize + 'px')
|
|
128
|
-
elm.style.setProperty('line-height', opts.lineHeight.toString())
|
|
129
|
-
elm.style.setProperty('padding', opts.padding)
|
|
140
|
+
const scrollWidth = opts.measureScrollWidth ? elm.scrollWidth : 0
|
|
141
|
+
const rect = elm.getBoundingClientRect()
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (opts.disableOverflowWrapBreaking) {
|
|
140
|
-
elm.style.setProperty('overflow-wrap', 'normal')
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (opts.otherStyles) {
|
|
144
|
-
for (const [key, value] of Object.entries(opts.otherStyles)) {
|
|
145
|
-
elm.style.setProperty(key, value)
|
|
143
|
+
return {
|
|
144
|
+
x: 0,
|
|
145
|
+
y: 0,
|
|
146
|
+
w: rect.width,
|
|
147
|
+
h: rect.height,
|
|
148
|
+
scrollWidth,
|
|
146
149
|
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const scrollWidth = opts.measureScrollWidth ? elm.scrollWidth : 0
|
|
150
|
-
const rect = elm.getBoundingClientRect()
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
x: 0,
|
|
154
|
-
y: 0,
|
|
155
|
-
w: rect.width,
|
|
156
|
-
h: rect.height,
|
|
157
|
-
scrollWidth,
|
|
150
|
+
} finally {
|
|
151
|
+
restoreStyles()
|
|
158
152
|
}
|
|
159
153
|
}
|
|
160
154
|
|
|
@@ -274,82 +268,68 @@ export class TextManager {
|
|
|
274
268
|
|
|
275
269
|
const { elm } = this
|
|
276
270
|
|
|
277
|
-
if (opts.otherStyles) {
|
|
278
|
-
for (const key in opts.otherStyles) {
|
|
279
|
-
if (!this.defaultStyles[key]) {
|
|
280
|
-
// we need to save the original style so that we can restore it when we're done
|
|
281
|
-
this.defaultStyles[key] = elm.style.getPropertyValue(key)
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
this.resetElmStyles()
|
|
287
|
-
|
|
288
|
-
elm.style.setProperty('font-family', opts.fontFamily)
|
|
289
|
-
elm.style.setProperty('font-style', opts.fontStyle)
|
|
290
|
-
elm.style.setProperty('font-weight', opts.fontWeight)
|
|
291
|
-
elm.style.setProperty('font-size', opts.fontSize + 'px')
|
|
292
|
-
elm.style.setProperty('line-height', opts.lineHeight.toString())
|
|
293
|
-
|
|
294
|
-
const elementWidth = Math.ceil(opts.width - opts.padding * 2)
|
|
295
|
-
elm.style.setProperty('width', `${elementWidth}px`)
|
|
296
|
-
elm.style.setProperty('height', 'min-content')
|
|
297
|
-
elm.style.setProperty('text-align', textAlignmentsForLtr[opts.textAlign])
|
|
298
|
-
|
|
299
271
|
const shouldTruncateToFirstLine =
|
|
300
272
|
opts.overflow === 'truncate-ellipsis' || opts.overflow === 'truncate-clip'
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
273
|
+
const elementWidth = Math.ceil(opts.width - opts.padding * 2)
|
|
274
|
+
const newStyles = {
|
|
275
|
+
'font-family': opts.fontFamily,
|
|
276
|
+
'font-style': opts.fontStyle,
|
|
277
|
+
'font-weight': opts.fontWeight,
|
|
278
|
+
'font-size': opts.fontSize + 'px',
|
|
279
|
+
'line-height': opts.lineHeight.toString(),
|
|
280
|
+
width: `${elementWidth}px`,
|
|
281
|
+
height: 'min-content',
|
|
282
|
+
'text-align': textAlignmentsForLtr[opts.textAlign],
|
|
283
|
+
'overflow-wrap': shouldTruncateToFirstLine ? 'anywhere' : undefined,
|
|
284
|
+
'word-break': shouldTruncateToFirstLine ? 'break-all' : undefined,
|
|
285
|
+
...opts.otherStyles,
|
|
311
286
|
}
|
|
287
|
+
const restoreStyles = this.setElementStyles(newStyles)
|
|
312
288
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
// Render the text into the measurement element:
|
|
316
|
-
elm.textContent = normalizedText
|
|
317
|
-
|
|
318
|
-
// actually measure the text:
|
|
319
|
-
const { spans, didTruncate } = this.measureElementTextNodeSpans(elm, {
|
|
320
|
-
shouldTruncateToFirstLine,
|
|
321
|
-
})
|
|
289
|
+
try {
|
|
290
|
+
const normalizedText = normalizeTextForDom(textToMeasure)
|
|
322
291
|
|
|
323
|
-
|
|
324
|
-
// we need to measure the ellipsis to know how much space it takes up
|
|
325
|
-
elm.textContent = '…'
|
|
326
|
-
const ellipsisWidth = Math.ceil(this.measureElementTextNodeSpans(elm).spans[0].box.w)
|
|
327
|
-
|
|
328
|
-
// then, we need to subtract that space from the width we have and measure again:
|
|
329
|
-
elm.style.setProperty('width', `${elementWidth - ellipsisWidth}px`)
|
|
292
|
+
// Render the text into the measurement element:
|
|
330
293
|
elm.textContent = normalizedText
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Finally, we add in our ellipsis at the end of the last span. We
|
|
336
|
-
// have to do this after measuring, not before, because adding the
|
|
337
|
-
// ellipsis changes how whitespace might be getting collapsed by the
|
|
338
|
-
// browser.
|
|
339
|
-
const lastSpan = truncatedSpans[truncatedSpans.length - 1]!
|
|
340
|
-
truncatedSpans.push({
|
|
341
|
-
text: '…',
|
|
342
|
-
box: {
|
|
343
|
-
x: Math.min(lastSpan.box.x + lastSpan.box.w, opts.width - opts.padding - ellipsisWidth),
|
|
344
|
-
y: lastSpan.box.y,
|
|
345
|
-
w: ellipsisWidth,
|
|
346
|
-
h: lastSpan.box.h,
|
|
347
|
-
},
|
|
294
|
+
|
|
295
|
+
// actually measure the text:
|
|
296
|
+
const { spans, didTruncate } = this.measureElementTextNodeSpans(elm, {
|
|
297
|
+
shouldTruncateToFirstLine,
|
|
348
298
|
})
|
|
349
299
|
|
|
350
|
-
|
|
351
|
-
|
|
300
|
+
if (opts.overflow === 'truncate-ellipsis' && didTruncate) {
|
|
301
|
+
// we need to measure the ellipsis to know how much space it takes up
|
|
302
|
+
elm.textContent = '…'
|
|
303
|
+
const ellipsisWidth = Math.ceil(this.measureElementTextNodeSpans(elm).spans[0].box.w)
|
|
304
|
+
|
|
305
|
+
// then, we need to subtract that space from the width we have and measure again:
|
|
306
|
+
elm.style.setProperty('width', `${elementWidth - ellipsisWidth}px`)
|
|
307
|
+
elm.textContent = normalizedText
|
|
308
|
+
const truncatedSpans = this.measureElementTextNodeSpans(elm, {
|
|
309
|
+
shouldTruncateToFirstLine: true,
|
|
310
|
+
}).spans
|
|
311
|
+
|
|
312
|
+
// Finally, we add in our ellipsis at the end of the last span. We
|
|
313
|
+
// have to do this after measuring, not before, because adding the
|
|
314
|
+
// ellipsis changes how whitespace might be getting collapsed by the
|
|
315
|
+
// browser.
|
|
316
|
+
const lastSpan = truncatedSpans[truncatedSpans.length - 1]!
|
|
317
|
+
truncatedSpans.push({
|
|
318
|
+
text: '…',
|
|
319
|
+
box: {
|
|
320
|
+
x: Math.min(lastSpan.box.x + lastSpan.box.w, opts.width - opts.padding - ellipsisWidth),
|
|
321
|
+
y: lastSpan.box.y,
|
|
322
|
+
w: ellipsisWidth,
|
|
323
|
+
h: lastSpan.box.h,
|
|
324
|
+
},
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
return truncatedSpans
|
|
328
|
+
}
|
|
352
329
|
|
|
353
|
-
|
|
330
|
+
return spans
|
|
331
|
+
} finally {
|
|
332
|
+
restoreStyles()
|
|
333
|
+
}
|
|
354
334
|
}
|
|
355
335
|
}
|
|
@@ -584,6 +584,15 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
584
584
|
*/
|
|
585
585
|
onResizeEnd?(initial: Shape, current: Shape): TLShapePartial<Shape> | void
|
|
586
586
|
|
|
587
|
+
/**
|
|
588
|
+
* A callback called when a shape resize is cancelled.
|
|
589
|
+
*
|
|
590
|
+
* @param initial - The shape at the start of the resize.
|
|
591
|
+
* @param current - The current shape.
|
|
592
|
+
* @public
|
|
593
|
+
*/
|
|
594
|
+
onResizeCancel?(initial: Shape, current: Shape): void
|
|
595
|
+
|
|
587
596
|
/**
|
|
588
597
|
* A callback called when a shape starts being translated.
|
|
589
598
|
*
|
|
@@ -613,6 +622,25 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
613
622
|
*/
|
|
614
623
|
onTranslateEnd?(initial: Shape, current: Shape): TLShapePartial<Shape> | void
|
|
615
624
|
|
|
625
|
+
/**
|
|
626
|
+
* A callback called when a shape translation is cancelled.
|
|
627
|
+
*
|
|
628
|
+
* @param initial - The shape at the start of the translation.
|
|
629
|
+
* @param current - The current shape.
|
|
630
|
+
* @public
|
|
631
|
+
*/
|
|
632
|
+
onTranslateCancel?(initial: Shape, current: Shape): void
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* A callback called when a shape's handle starts being dragged.
|
|
636
|
+
*
|
|
637
|
+
* @param shape - The shape.
|
|
638
|
+
* @param info - An object containing the handle and whether the handle is 'precise' or not.
|
|
639
|
+
* @returns A change to apply to the shape, or void.
|
|
640
|
+
* @public
|
|
641
|
+
*/
|
|
642
|
+
onHandleDragStart?(shape: Shape, info: TLHandleDragInfo<Shape>): TLShapePartial<Shape> | void
|
|
643
|
+
|
|
616
644
|
/**
|
|
617
645
|
* A callback called when a shape's handle changes.
|
|
618
646
|
*
|
|
@@ -623,6 +651,25 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
623
651
|
*/
|
|
624
652
|
onHandleDrag?(shape: Shape, info: TLHandleDragInfo<Shape>): TLShapePartial<Shape> | void
|
|
625
653
|
|
|
654
|
+
/**
|
|
655
|
+
* A callback called when a shape's handle finishes being dragged.
|
|
656
|
+
*
|
|
657
|
+
* @param current - The current shape.
|
|
658
|
+
* @param info - An object containing the handle and whether the handle is 'precise' or not.
|
|
659
|
+
* @returns A change to apply to the shape, or void.
|
|
660
|
+
* @public
|
|
661
|
+
*/
|
|
662
|
+
onHandleDragEnd?(current: Shape, info: TLHandleDragInfo<Shape>): TLShapePartial<Shape> | void
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* A callback called when a shape's handle drag is cancelled.
|
|
666
|
+
*
|
|
667
|
+
* @param current - The current shape.
|
|
668
|
+
* @param info - An object containing the handle and whether the handle is 'precise' or not.
|
|
669
|
+
* @public
|
|
670
|
+
*/
|
|
671
|
+
onHandleDragCancel?(current: Shape, info: TLHandleDragInfo<Shape>): void
|
|
672
|
+
|
|
626
673
|
/**
|
|
627
674
|
* A callback called when a shape starts being rotated.
|
|
628
675
|
*
|
|
@@ -652,6 +699,15 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
652
699
|
*/
|
|
653
700
|
onRotateEnd?(initial: Shape, current: Shape): TLShapePartial<Shape> | void
|
|
654
701
|
|
|
702
|
+
/**
|
|
703
|
+
* A callback called when a shape rotation is cancelled.
|
|
704
|
+
*
|
|
705
|
+
* @param initial - The shape at the start of the rotation.
|
|
706
|
+
* @param current - The current shape.
|
|
707
|
+
* @public
|
|
708
|
+
*/
|
|
709
|
+
onRotateCancel?(initial: Shape, current: Shape): void
|
|
710
|
+
|
|
655
711
|
/**
|
|
656
712
|
* Not currently used.
|
|
657
713
|
*
|
|
@@ -819,5 +875,6 @@ export interface TLResizeInfo<T extends TLShape> {
|
|
|
819
875
|
export interface TLHandleDragInfo<T extends TLShape> {
|
|
820
876
|
handle: TLHandle
|
|
821
877
|
isPrecise: boolean
|
|
878
|
+
isCreatingShape: boolean
|
|
822
879
|
initial?: T | undefined
|
|
823
880
|
}
|