@tldraw/editor 3.12.0-canary.ceec8eda0db0 → 3.12.0-canary.d0e07565d818
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 +165 -17
- package/dist-cjs/index.js +3 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +5 -0
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/GeometryDebuggingView.js +2 -2
- package/dist-cjs/lib/components/GeometryDebuggingView.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +10 -14
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +10 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +224 -32
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +1 -1
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FocusManager.js +1 -1
- package/dist-cjs/lib/editor/managers/FocusManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FontManager.js +1 -1
- package/dist-cjs/lib/editor/managers/FontManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +12 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +4 -13
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +4 -1
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/editor/types/selection-types.js.map +1 -1
- package/dist-cjs/lib/exports/StyleEmbedder.js +19 -5
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/cssRules.js +127 -0
- package/dist-cjs/lib/exports/cssRules.js.map +7 -0
- package/dist-cjs/lib/exports/parseCss.js +0 -69
- package/dist-cjs/lib/exports/parseCss.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +13 -8
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +3 -3
- package/dist-cjs/lib/hooks/useDocumentEvents.js +16 -0
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useGestureEvents.js +12 -6
- package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
- package/dist-cjs/lib/license/Watermark.js +10 -20
- package/dist-cjs/lib/license/Watermark.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +128 -16
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +3 -3
- package/dist-cjs/lib/primitives/geometry/Group2d.js +53 -10
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/intersect.js +20 -0
- package/dist-cjs/lib/primitives/intersect.js.map +2 -2
- package/dist-cjs/lib/utils/debug-flags.js +2 -1
- package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
- package/dist-cjs/lib/utils/reorderShapes.js +2 -8
- package/dist-cjs/lib/utils/reorderShapes.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 +165 -17
- package/dist-esm/index.mjs +8 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +5 -0
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/GeometryDebuggingView.mjs +3 -3
- package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +11 -15
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +10 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +225 -32
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +1 -1
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FocusManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/FocusManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FontManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/FontManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +12 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +4 -13
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +4 -1
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs +21 -12
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/cssRules.mjs +107 -0
- package/dist-esm/lib/exports/cssRules.mjs.map +7 -0
- package/dist-esm/lib/exports/parseCss.mjs +0 -69
- package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +13 -8
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +3 -3
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +16 -0
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs +12 -6
- package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
- package/dist-esm/lib/license/Watermark.mjs +10 -20
- package/dist-esm/lib/license/Watermark.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +132 -14
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +54 -11
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/intersect.mjs +20 -0
- package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
- package/dist-esm/lib/utils/debug-flags.mjs +2 -1
- package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
- package/dist-esm/lib/utils/reorderShapes.mjs +2 -8
- package/dist-esm/lib/utils/reorderShapes.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +51 -30
- package/package.json +7 -7
- package/src/index.ts +11 -2
- package/src/lib/TldrawEditor.tsx +30 -3
- package/src/lib/components/GeometryDebuggingView.tsx +3 -3
- package/src/lib/components/Shape.tsx +15 -19
- package/src/lib/components/default-components/DefaultCanvas.tsx +6 -1
- package/src/lib/editor/Editor.ts +334 -39
- package/src/lib/editor/derivations/notVisibleShapes.ts +1 -1
- package/src/lib/editor/managers/FocusManager.ts +1 -1
- package/src/lib/editor/managers/FontManager.ts +1 -1
- package/src/lib/editor/shapes/ShapeUtil.ts +14 -0
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +7 -15
- package/src/lib/editor/tools/StateNode.ts +6 -1
- package/src/lib/editor/types/selection-types.ts +3 -0
- package/src/lib/exports/StyleEmbedder.ts +25 -15
- package/src/lib/exports/cssRules.ts +126 -0
- package/src/lib/exports/parseCss.ts +0 -79
- package/src/lib/hooks/useCanvasEvents.ts +19 -8
- package/src/lib/hooks/useDocumentEvents.ts +18 -0
- package/src/lib/hooks/useGestureEvents.ts +12 -6
- package/src/lib/license/Watermark.tsx +18 -29
- package/src/lib/primitives/geometry/Geometry2d.ts +196 -16
- package/src/lib/primitives/geometry/Group2d.ts +75 -12
- package/src/lib/primitives/intersect.ts +41 -0
- package/src/lib/utils/debug-flags.ts +1 -0
- package/src/lib/utils/reorderShapes.ts +2 -9
- package/src/version.ts +3 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { assertExists, objectMapValues, uniqueId } from '@tldraw/utils'
|
|
1
|
+
import { assertExists, getOwnProperty, objectMapValues, uniqueId } from '@tldraw/utils'
|
|
2
2
|
import { FontEmbedder } from './FontEmbedder'
|
|
3
|
+
import { ReadonlyStyles, Styles, cssRules } from './cssRules'
|
|
3
4
|
import {
|
|
4
5
|
elementStyle,
|
|
5
6
|
getComputedStyle,
|
|
@@ -7,15 +8,8 @@ import {
|
|
|
7
8
|
getRenderedChildren,
|
|
8
9
|
} from './domUtils'
|
|
9
10
|
import { resourceToDataUrl } from './fetchCache'
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
isPropertyInherited,
|
|
13
|
-
parseCssValueUrls,
|
|
14
|
-
shouldIncludeCssProperty,
|
|
15
|
-
} from './parseCss'
|
|
16
|
-
|
|
17
|
-
type Styles = { [K in string]?: string }
|
|
18
|
-
type ReadonlyStyles = { readonly [K in string]?: string }
|
|
11
|
+
import { parseCssValueUrls, shouldIncludeCssProperty } from './parseCss'
|
|
12
|
+
|
|
19
13
|
const NO_STYLES = {} as const
|
|
20
14
|
|
|
21
15
|
interface ElementStyleInfo {
|
|
@@ -239,15 +233,22 @@ function styleFromComputedStyleMap(
|
|
|
239
233
|
{ defaultStyles, parentStyles }: ReadStyleOpts
|
|
240
234
|
) {
|
|
241
235
|
const styles: Record<string, string> = {}
|
|
236
|
+
const currentColor = style.get('color')?.toString() || ''
|
|
237
|
+
const ruleOptions = {
|
|
238
|
+
currentColor,
|
|
239
|
+
parentStyles,
|
|
240
|
+
defaultStyles,
|
|
241
|
+
getStyle: (property: string) => style.get(property)?.toString() ?? '',
|
|
242
|
+
}
|
|
242
243
|
for (const property of style.keys()) {
|
|
243
244
|
if (!shouldIncludeCssProperty(property)) continue
|
|
244
245
|
|
|
245
246
|
const value = style.get(property)!.toString()
|
|
246
247
|
|
|
247
248
|
if (defaultStyles[property] === value) continue
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
249
|
+
|
|
250
|
+
const rule = getOwnProperty(cssRules, property)
|
|
251
|
+
if (rule && rule(value, property, ruleOptions)) continue
|
|
251
252
|
|
|
252
253
|
styles[property] = value
|
|
253
254
|
}
|
|
@@ -260,14 +261,23 @@ function styleFromComputedStyle(
|
|
|
260
261
|
{ defaultStyles, parentStyles }: ReadStyleOpts
|
|
261
262
|
) {
|
|
262
263
|
const styles: Record<string, string> = {}
|
|
264
|
+
const currentColor = style.color
|
|
265
|
+
const ruleOptions = {
|
|
266
|
+
currentColor,
|
|
267
|
+
parentStyles,
|
|
268
|
+
defaultStyles,
|
|
269
|
+
getStyle: (property: string) => style.getPropertyValue(property),
|
|
270
|
+
}
|
|
271
|
+
|
|
263
272
|
for (const property in style) {
|
|
264
273
|
if (!shouldIncludeCssProperty(property)) continue
|
|
265
274
|
|
|
266
275
|
const value = style.getPropertyValue(property)
|
|
267
276
|
|
|
268
277
|
if (defaultStyles[property] === value) continue
|
|
269
|
-
|
|
270
|
-
|
|
278
|
+
|
|
279
|
+
const rule = getOwnProperty(cssRules, property)
|
|
280
|
+
if (rule && rule(value, property, ruleOptions)) continue
|
|
271
281
|
|
|
272
282
|
styles[property] = value
|
|
273
283
|
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export type Styles = { [K in string]?: string }
|
|
2
|
+
export type ReadonlyStyles = { readonly [K in string]?: string }
|
|
3
|
+
|
|
4
|
+
type CanSkipRule = (
|
|
5
|
+
value: string,
|
|
6
|
+
property: string,
|
|
7
|
+
options: {
|
|
8
|
+
getStyle(property: string): string
|
|
9
|
+
parentStyles: ReadonlyStyles
|
|
10
|
+
defaultStyles: ReadonlyStyles
|
|
11
|
+
currentColor: string
|
|
12
|
+
}
|
|
13
|
+
) => boolean
|
|
14
|
+
|
|
15
|
+
const isCoveredByCurrentColor: CanSkipRule = (value, property, { currentColor }) => {
|
|
16
|
+
return value === 'currentColor' || value === currentColor
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const isInherited: CanSkipRule = (value, property, { parentStyles }) => {
|
|
20
|
+
return parentStyles[property] === value
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// see comment below about why we exclude border styles
|
|
24
|
+
const isExcludedBorder =
|
|
25
|
+
(borderDirection: string): CanSkipRule =>
|
|
26
|
+
(value, property, { getStyle }) => {
|
|
27
|
+
const borderWidth = getStyle(`border-${borderDirection}-width`)
|
|
28
|
+
const borderStyle = getStyle(`border-${borderDirection}-style`)
|
|
29
|
+
|
|
30
|
+
if (borderWidth === '0px') return true
|
|
31
|
+
if (borderStyle === 'none') return true
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const cssRules = {
|
|
36
|
+
// currentColor properties:
|
|
37
|
+
'border-block-end-color': isCoveredByCurrentColor,
|
|
38
|
+
'border-block-start-color': isCoveredByCurrentColor,
|
|
39
|
+
'border-bottom-color': isCoveredByCurrentColor,
|
|
40
|
+
'border-inline-end-color': isCoveredByCurrentColor,
|
|
41
|
+
'border-inline-start-color': isCoveredByCurrentColor,
|
|
42
|
+
'border-left-color': isCoveredByCurrentColor,
|
|
43
|
+
'border-right-color': isCoveredByCurrentColor,
|
|
44
|
+
'border-top-color': isCoveredByCurrentColor,
|
|
45
|
+
'caret-color': isCoveredByCurrentColor,
|
|
46
|
+
'column-rule-color': isCoveredByCurrentColor,
|
|
47
|
+
'outline-color': isCoveredByCurrentColor,
|
|
48
|
+
'text-decoration': (value, property, { currentColor }) => {
|
|
49
|
+
return value === 'none solid currentColor' || value === 'none solid ' + currentColor
|
|
50
|
+
},
|
|
51
|
+
'text-decoration-color': isCoveredByCurrentColor,
|
|
52
|
+
'text-emphasis-color': isCoveredByCurrentColor,
|
|
53
|
+
|
|
54
|
+
// inherited properties:
|
|
55
|
+
'border-collapse': isInherited,
|
|
56
|
+
'border-spacing': isInherited,
|
|
57
|
+
'caption-side': isInherited,
|
|
58
|
+
// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements
|
|
59
|
+
// 'color': isInherited,
|
|
60
|
+
cursor: isInherited,
|
|
61
|
+
direction: isInherited,
|
|
62
|
+
'empty-cells': isInherited,
|
|
63
|
+
'font-family': isInherited,
|
|
64
|
+
'font-size': isInherited,
|
|
65
|
+
'font-style': isInherited,
|
|
66
|
+
'font-variant': isInherited,
|
|
67
|
+
'font-weight': isInherited,
|
|
68
|
+
'font-size-adjust': isInherited,
|
|
69
|
+
'font-stretch': isInherited,
|
|
70
|
+
font: isInherited,
|
|
71
|
+
'letter-spacing': isInherited,
|
|
72
|
+
'line-height': isInherited,
|
|
73
|
+
'list-style-image': isInherited,
|
|
74
|
+
'list-style-position': isInherited,
|
|
75
|
+
'list-style-type': isInherited,
|
|
76
|
+
'list-style': isInherited,
|
|
77
|
+
orphans: isInherited,
|
|
78
|
+
'overflow-wrap': isInherited,
|
|
79
|
+
quotes: isInherited,
|
|
80
|
+
'stroke-linecap': isInherited,
|
|
81
|
+
'stroke-linejoin': isInherited,
|
|
82
|
+
'tab-size': isInherited,
|
|
83
|
+
'text-align': isInherited,
|
|
84
|
+
'text-align-last': isInherited,
|
|
85
|
+
'text-indent': isInherited,
|
|
86
|
+
'text-justify': isInherited,
|
|
87
|
+
'text-shadow': isInherited,
|
|
88
|
+
'text-transform': isInherited,
|
|
89
|
+
visibility: isInherited,
|
|
90
|
+
'white-space': isInherited,
|
|
91
|
+
'white-space-collapse': isInherited,
|
|
92
|
+
widows: isInherited,
|
|
93
|
+
'word-break': isInherited,
|
|
94
|
+
'word-spacing': isInherited,
|
|
95
|
+
'word-wrap': isInherited,
|
|
96
|
+
|
|
97
|
+
// special border cases - we have a weird case (tailwind seems to trigger this) where all
|
|
98
|
+
// border-styles sometimes get set to 'solid', but the border-width is 0 so they don't render.
|
|
99
|
+
// but in SVGs, **sometimes**, the border-width defaults (i think from a UA style-sheet? but
|
|
100
|
+
// honestly can't tell) to 1.5px so the border displays. we work around this by only including
|
|
101
|
+
// border styles at all if both the border-width and border-style are set to something that
|
|
102
|
+
// would show a border.
|
|
103
|
+
'border-top': isExcludedBorder('top'),
|
|
104
|
+
'border-right': isExcludedBorder('right'),
|
|
105
|
+
'border-bottom': isExcludedBorder('bottom'),
|
|
106
|
+
'border-left': isExcludedBorder('left'),
|
|
107
|
+
'border-block-end': isExcludedBorder('block-end'),
|
|
108
|
+
'border-block-start': isExcludedBorder('block-start'),
|
|
109
|
+
'border-inline-end': isExcludedBorder('inline-end'),
|
|
110
|
+
'border-inline-start': isExcludedBorder('inline-start'),
|
|
111
|
+
'border-top-style': isExcludedBorder('top'),
|
|
112
|
+
'border-right-style': isExcludedBorder('right'),
|
|
113
|
+
'border-bottom-style': isExcludedBorder('bottom'),
|
|
114
|
+
'border-left-style': isExcludedBorder('left'),
|
|
115
|
+
'border-block-end-style': isExcludedBorder('block-end'),
|
|
116
|
+
'border-block-start-style': isExcludedBorder('block-start'),
|
|
117
|
+
'border-inline-end-style': isExcludedBorder('inline-end'),
|
|
118
|
+
'border-inline-start-style': isExcludedBorder('inline-start'),
|
|
119
|
+
'border-top-width': isExcludedBorder('top'),
|
|
120
|
+
'border-right-width': isExcludedBorder('right'),
|
|
121
|
+
'border-bottom-width': isExcludedBorder('bottom'),
|
|
122
|
+
'border-left-width': isExcludedBorder('left'),
|
|
123
|
+
'border-block-end-width': isExcludedBorder('block-end'),
|
|
124
|
+
'border-block-start-width': isExcludedBorder('block-start'),
|
|
125
|
+
'border-inline-end-width': isExcludedBorder('inline-end'),
|
|
126
|
+
} satisfies Record<string, CanSkipRule>
|
|
@@ -110,82 +110,3 @@ export function parseCssValueUrls(value: string) {
|
|
|
110
110
|
url: m[1] || m[2] || m[3],
|
|
111
111
|
}))
|
|
112
112
|
}
|
|
113
|
-
|
|
114
|
-
const currentColorProperties = new Set([
|
|
115
|
-
'border-block-end-color',
|
|
116
|
-
'border-block-start-color',
|
|
117
|
-
'border-bottom-color',
|
|
118
|
-
'border-inline-end-color',
|
|
119
|
-
'border-inline-start-color',
|
|
120
|
-
'border-left-color',
|
|
121
|
-
'border-right-color',
|
|
122
|
-
'border-top-color',
|
|
123
|
-
'caret-color',
|
|
124
|
-
'column-rule-color',
|
|
125
|
-
'outline-color',
|
|
126
|
-
'text-decoration',
|
|
127
|
-
'text-decoration-color',
|
|
128
|
-
'text-emphasis-color',
|
|
129
|
-
])
|
|
130
|
-
|
|
131
|
-
export function isPropertyCoveredByCurrentColor(
|
|
132
|
-
currentColor: string,
|
|
133
|
-
property: string,
|
|
134
|
-
value: string
|
|
135
|
-
) {
|
|
136
|
-
if (currentColorProperties.has(property)) {
|
|
137
|
-
return (
|
|
138
|
-
value === 'currentColor' ||
|
|
139
|
-
value === currentColor ||
|
|
140
|
-
(property === 'text-decoration' && value === `none solid ${currentColor}`)
|
|
141
|
-
)
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const inheritedProperties = new Set([
|
|
146
|
-
'border-collapse',
|
|
147
|
-
'border-spacing',
|
|
148
|
-
'caption-side',
|
|
149
|
-
// N.B. We shouldn't inherit 'color' because there's some UA styling, e.g. `mark` elements
|
|
150
|
-
// 'color',
|
|
151
|
-
'cursor',
|
|
152
|
-
'direction',
|
|
153
|
-
'empty-cells',
|
|
154
|
-
'font-family',
|
|
155
|
-
'font-size',
|
|
156
|
-
'font-style',
|
|
157
|
-
'font-variant',
|
|
158
|
-
'font-weight',
|
|
159
|
-
'font-size-adjust',
|
|
160
|
-
'font-stretch',
|
|
161
|
-
'font',
|
|
162
|
-
'letter-spacing',
|
|
163
|
-
'line-height',
|
|
164
|
-
'list-style-image',
|
|
165
|
-
'list-style-position',
|
|
166
|
-
'list-style-type',
|
|
167
|
-
'list-style',
|
|
168
|
-
'orphans',
|
|
169
|
-
'overflow-wrap',
|
|
170
|
-
'quotes',
|
|
171
|
-
'stroke-linecap',
|
|
172
|
-
'stroke-linejoin',
|
|
173
|
-
'tab-size',
|
|
174
|
-
'text-align',
|
|
175
|
-
'text-align-last',
|
|
176
|
-
'text-indent',
|
|
177
|
-
'text-justify',
|
|
178
|
-
'text-shadow',
|
|
179
|
-
'text-transform',
|
|
180
|
-
'visibility',
|
|
181
|
-
'white-space',
|
|
182
|
-
'white-space-collapse',
|
|
183
|
-
'widows',
|
|
184
|
-
'word-break',
|
|
185
|
-
'word-spacing',
|
|
186
|
-
'word-wrap',
|
|
187
|
-
])
|
|
188
|
-
|
|
189
|
-
export function isPropertyInherited(property: string) {
|
|
190
|
-
return inheritedProperties.has(property)
|
|
191
|
-
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useValue } from '@tldraw/state-react'
|
|
1
2
|
import React, { useMemo } from 'react'
|
|
2
3
|
import { RIGHT_MOUSE_BUTTON } from '../constants'
|
|
3
4
|
import {
|
|
@@ -11,6 +12,7 @@ import { useEditor } from './useEditor'
|
|
|
11
12
|
|
|
12
13
|
export function useCanvasEvents() {
|
|
13
14
|
const editor = useEditor()
|
|
15
|
+
const currentTool = useValue('current tool', () => editor.getCurrentTool(), [editor])
|
|
14
16
|
|
|
15
17
|
const events = useMemo(
|
|
16
18
|
function canvasEvents() {
|
|
@@ -49,12 +51,21 @@ export function useCanvasEvents() {
|
|
|
49
51
|
lastX = e.clientX
|
|
50
52
|
lastY = e.clientY
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
// For tools that benefit from a higher fidelity of events,
|
|
55
|
+
// we dispatch the coalesced events.
|
|
56
|
+
// N.B. Sometimes getCoalescedEvents isn't present on iOS, ugh.
|
|
57
|
+
const events =
|
|
58
|
+
currentTool.useCoalescedEvents && e.nativeEvent.getCoalescedEvents
|
|
59
|
+
? e.nativeEvent.getCoalescedEvents()
|
|
60
|
+
: [e]
|
|
61
|
+
for (const singleEvent of events) {
|
|
62
|
+
editor.dispatch({
|
|
63
|
+
type: 'pointer',
|
|
64
|
+
target: 'canvas',
|
|
65
|
+
name: 'pointer_move',
|
|
66
|
+
...getPointerInfo(singleEvent),
|
|
67
|
+
})
|
|
68
|
+
}
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
function onPointerUp(e: React.PointerEvent) {
|
|
@@ -100,7 +111,7 @@ export function useCanvasEvents() {
|
|
|
100
111
|
if (
|
|
101
112
|
e.target.tagName !== 'A' &&
|
|
102
113
|
e.target.tagName !== 'TEXTAREA' &&
|
|
103
|
-
e.target.isContentEditable &&
|
|
114
|
+
!e.target.isContentEditable &&
|
|
104
115
|
// When in EditingShape state, we are actually clicking on a 'DIV'
|
|
105
116
|
// not A/TEXTAREA/contenteditable element yet. So, to preserve cursor position
|
|
106
117
|
// for edit mode on mobile we need to not preventDefault.
|
|
@@ -159,7 +170,7 @@ export function useCanvasEvents() {
|
|
|
159
170
|
onClick,
|
|
160
171
|
}
|
|
161
172
|
},
|
|
162
|
-
[editor]
|
|
173
|
+
[editor, currentTool]
|
|
163
174
|
)
|
|
164
175
|
|
|
165
176
|
return events
|
|
@@ -104,6 +104,7 @@ export function useDocumentEvents() {
|
|
|
104
104
|
|
|
105
105
|
if ((e as any).isKilled) return
|
|
106
106
|
;(e as any).isKilled = true
|
|
107
|
+
const hasSelectedShapes = !!editor.getSelectedShapeIds().length
|
|
107
108
|
|
|
108
109
|
switch (e.key) {
|
|
109
110
|
case '=':
|
|
@@ -124,6 +125,23 @@ export function useDocumentEvents() {
|
|
|
124
125
|
if (areShortcutsDisabled(editor)) {
|
|
125
126
|
return
|
|
126
127
|
}
|
|
128
|
+
if (hasSelectedShapes) {
|
|
129
|
+
// This is used in tandem with shape navigation.
|
|
130
|
+
preventDefault(e)
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
}
|
|
134
|
+
case 'ArrowLeft':
|
|
135
|
+
case 'ArrowRight':
|
|
136
|
+
case 'ArrowUp':
|
|
137
|
+
case 'ArrowDown': {
|
|
138
|
+
if (areShortcutsDisabled(editor)) {
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
if (hasSelectedShapes && (e.metaKey || e.ctrlKey)) {
|
|
142
|
+
// This is used in tandem with shape navigation.
|
|
143
|
+
preventDefault(e)
|
|
144
|
+
}
|
|
127
145
|
break
|
|
128
146
|
}
|
|
129
147
|
case ',': {
|
|
@@ -135,7 +135,6 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
|
|
|
135
135
|
|
|
136
136
|
let initDistanceBetweenFingers = 1 // the distance between the two fingers when the pinch starts
|
|
137
137
|
let initZoom = 1 // the browser's zoom level when the pinch starts
|
|
138
|
-
let currZoom = 1 // the current zoom level according to the pinch gesture recognizer
|
|
139
138
|
let currDistanceBetweenFingers = 0
|
|
140
139
|
const initPointBetweenFingers = new Vec()
|
|
141
140
|
const prevPointBetweenFingers = new Vec()
|
|
@@ -239,7 +238,7 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
|
|
|
239
238
|
|
|
240
239
|
switch (pinchState) {
|
|
241
240
|
case 'zooming': {
|
|
242
|
-
currZoom = offset[0]
|
|
241
|
+
const currZoom = offset[0] ** editor.getCameraOptions().zoomSpeed
|
|
243
242
|
|
|
244
243
|
editor.dispatch({
|
|
245
244
|
type: 'pinch',
|
|
@@ -278,7 +277,7 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
|
|
|
278
277
|
if (event instanceof WheelEvent) return
|
|
279
278
|
if (!(event.target === elm || elm?.contains(event.target as Node))) return
|
|
280
279
|
|
|
281
|
-
const scale = offset[0]
|
|
280
|
+
const scale = offset[0] ** editor.getCameraOptions().zoomSpeed
|
|
282
281
|
|
|
283
282
|
pinchState = 'not sure'
|
|
284
283
|
|
|
@@ -309,14 +308,21 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
|
|
|
309
308
|
target: ref,
|
|
310
309
|
eventOptions: { passive: false },
|
|
311
310
|
pinch: {
|
|
312
|
-
from: () =>
|
|
311
|
+
from: () => {
|
|
312
|
+
const { zoomSpeed } = editor.getCameraOptions()
|
|
313
|
+
const level = editor.getZoomLevel() ** (1 / zoomSpeed)
|
|
314
|
+
return [level, 0]
|
|
315
|
+
}, // Return the camera z to use when pinch starts
|
|
313
316
|
scaleBounds: () => {
|
|
314
317
|
const baseZoom = editor.getBaseZoom()
|
|
315
|
-
const zoomSteps = editor.getCameraOptions()
|
|
318
|
+
const { zoomSteps, zoomSpeed } = editor.getCameraOptions()
|
|
316
319
|
const zoomMin = zoomSteps[0] * baseZoom
|
|
317
320
|
const zoomMax = zoomSteps[zoomSteps.length - 1] * baseZoom
|
|
318
321
|
|
|
319
|
-
return {
|
|
322
|
+
return {
|
|
323
|
+
max: zoomMax ** (1 / zoomSpeed),
|
|
324
|
+
min: zoomMin ** (1 / zoomSpeed),
|
|
325
|
+
}
|
|
320
326
|
},
|
|
321
327
|
},
|
|
322
328
|
})
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useValue } from '@tldraw/state-react'
|
|
2
2
|
import { memo, useRef } from 'react'
|
|
3
|
-
import { tlenv } from '../globals/environment'
|
|
4
3
|
import { useCanvasEvents } from '../hooks/useCanvasEvents'
|
|
5
4
|
import { useEditor } from '../hooks/useEditor'
|
|
6
5
|
import { usePassThroughWheelEvents } from '../hooks/usePassThroughWheelEvents'
|
|
@@ -57,29 +56,17 @@ const WatermarkInner = memo(function WatermarkInner({ src }: { src: string }) {
|
|
|
57
56
|
draggable={false}
|
|
58
57
|
{...events}
|
|
59
58
|
>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
) : (
|
|
72
|
-
<a
|
|
73
|
-
href={url}
|
|
74
|
-
target="_blank"
|
|
75
|
-
rel="noreferrer"
|
|
76
|
-
draggable={false}
|
|
77
|
-
onPointerDown={(e) => {
|
|
78
|
-
stopEventPropagation(e)
|
|
79
|
-
}}
|
|
80
|
-
style={{ mask: maskCss, WebkitMask: maskCss }}
|
|
81
|
-
/>
|
|
82
|
-
)}
|
|
59
|
+
<button
|
|
60
|
+
draggable={false}
|
|
61
|
+
role="button"
|
|
62
|
+
onPointerDown={(e) => {
|
|
63
|
+
stopEventPropagation(e)
|
|
64
|
+
preventDefault(e)
|
|
65
|
+
}}
|
|
66
|
+
title="made with tldraw"
|
|
67
|
+
onClick={() => runtime.openWindow(url, '_blank')}
|
|
68
|
+
style={{ mask: maskCss, WebkitMask: maskCss }}
|
|
69
|
+
/>
|
|
83
70
|
</div>
|
|
84
71
|
)
|
|
85
72
|
})
|
|
@@ -115,7 +102,7 @@ To remove the watermark, please purchase a license at tldraw.dev.
|
|
|
115
102
|
box-sizing: content-box;
|
|
116
103
|
}
|
|
117
104
|
|
|
118
|
-
.${className} >
|
|
105
|
+
.${className} > button {
|
|
119
106
|
position: absolute;
|
|
120
107
|
width: 96px;
|
|
121
108
|
height: 32px;
|
|
@@ -123,6 +110,8 @@ To remove the watermark, please purchase a license at tldraw.dev.
|
|
|
123
110
|
cursor: inherit;
|
|
124
111
|
color: var(--color-text);
|
|
125
112
|
opacity: .38;
|
|
113
|
+
border: 0;
|
|
114
|
+
padding: 0;
|
|
126
115
|
background-color: currentColor;
|
|
127
116
|
}
|
|
128
117
|
|
|
@@ -137,13 +126,13 @@ To remove the watermark, please purchase a license at tldraw.dev.
|
|
|
137
126
|
height: 48px;
|
|
138
127
|
}
|
|
139
128
|
|
|
140
|
-
.${className}[data-mobile='true'] >
|
|
129
|
+
.${className}[data-mobile='true'] > button {
|
|
141
130
|
width: 8px;
|
|
142
131
|
height: 32px;
|
|
143
132
|
}
|
|
144
133
|
|
|
145
134
|
@media (hover: hover) {
|
|
146
|
-
.${className} >
|
|
135
|
+
.${className} > button {
|
|
147
136
|
pointer-events: none;
|
|
148
137
|
}
|
|
149
138
|
|
|
@@ -153,12 +142,12 @@ To remove the watermark, please purchase a license at tldraw.dev.
|
|
|
153
142
|
transition-delay: 0.32s;
|
|
154
143
|
}
|
|
155
144
|
|
|
156
|
-
.${className}:hover >
|
|
145
|
+
.${className}:hover > button {
|
|
157
146
|
animation: delayed_link 0.2s forwards ease-in-out;
|
|
158
147
|
animation-delay: 0.32s;
|
|
159
148
|
}
|
|
160
149
|
|
|
161
|
-
.${className} >
|
|
150
|
+
.${className} > button:focus-visible {
|
|
162
151
|
opacity: 1;
|
|
163
152
|
}
|
|
164
153
|
}
|