tldraw 3.16.0-canary.5dac57cf9465 → 3.16.0-canary.6f3aedaa1c01
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 +32 -1
- package/dist-cjs/index.js +2 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +3 -3
- package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +3 -3
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +12 -12
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +2 -2
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js +2 -1
- package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js.map +2 -2
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +5 -1
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/line/LineShapeUtil.js +5 -1
- package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +4 -4
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/ShapeFill.js +5 -5
- package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
- package/dist-cjs/lib/shapes/text/TextShapeUtil.js +2 -2
- package/dist-cjs/lib/shapes/text/TextShapeUtil.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
- package/dist-cjs/lib/ui/components/MobileStylePanel.js +1 -1
- package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +1 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +30 -13
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +152 -1
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTools.js +76 -9
- package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-esm/index.d.mts +32 -1
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +4 -3
- package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +4 -3
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +13 -12
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +3 -2
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs +2 -1
- package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs.map +2 -2
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +6 -1
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +6 -1
- package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +5 -4
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/ShapeFill.mjs +6 -5
- package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
- package/dist-esm/lib/shapes/text/TextShapeUtil.mjs +3 -2
- package/dist-esm/lib/shapes/text/TextShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
- package/dist-esm/lib/ui/components/MobileStylePanel.mjs +2 -1
- package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +2 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +31 -14
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +160 -3
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTools.mjs +83 -10
- package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +2 -0
- package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +4 -3
- package/src/lib/shapes/draw/DrawShapeUtil.tsx +4 -3
- package/src/lib/shapes/frame/FrameShapeUtil.tsx +13 -14
- package/src/lib/shapes/geo/GeoShapeUtil.tsx +3 -2
- package/src/lib/shapes/geo/components/GeoShapeBody.tsx +2 -2
- package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +7 -1
- package/src/lib/shapes/line/LineShapeUtil.tsx +6 -1
- package/src/lib/shapes/note/NoteShapeUtil.tsx +9 -4
- package/src/lib/shapes/shared/ShapeFill.tsx +6 -5
- package/src/lib/shapes/text/TextShapeUtil.tsx +3 -2
- package/src/lib/tools/SelectTool/childStates/Translating.ts +0 -1
- package/src/lib/ui/components/MobileStylePanel.tsx +5 -3
- package/src/lib/ui/components/primitives/TldrawUiButtonPicker.tsx +3 -2
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +35 -16
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +218 -2
- package/src/lib/ui/context/events.tsx +1 -0
- package/src/lib/ui/hooks/useTools.tsx +118 -10
- package/src/lib/ui/version.ts +3 -3
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
VecLike,
|
|
15
15
|
drawShapeMigrations,
|
|
16
16
|
drawShapeProps,
|
|
17
|
+
getColorValue,
|
|
17
18
|
last,
|
|
18
19
|
lerp,
|
|
19
20
|
rng,
|
|
@@ -289,7 +290,7 @@ function DrawShapeSvg({ shape, zoomOverride }: { shape: TLDrawShape; zoomOverrid
|
|
|
289
290
|
<path
|
|
290
291
|
d={svgInk(allPointsFromSegments, options)}
|
|
291
292
|
strokeLinecap="round"
|
|
292
|
-
fill={theme
|
|
293
|
+
fill={getColorValue(theme, shape.props.color, 'solid')}
|
|
293
294
|
/>
|
|
294
295
|
</>
|
|
295
296
|
)
|
|
@@ -313,8 +314,8 @@ function DrawShapeSvg({ shape, zoomOverride }: { shape: TLDrawShape; zoomOverrid
|
|
|
313
314
|
<path
|
|
314
315
|
d={solidStrokePath}
|
|
315
316
|
strokeLinecap="round"
|
|
316
|
-
fill={isDot ? theme
|
|
317
|
-
stroke={theme
|
|
317
|
+
fill={isDot ? getColorValue(theme, shape.props.color, 'solid') : 'none'}
|
|
318
|
+
stroke={getColorValue(theme, shape.props.color, 'solid')}
|
|
318
319
|
strokeWidth={sw}
|
|
319
320
|
strokeDasharray={isDot ? 'none' : getDrawShapeStrokeDashArray(shape, sw, dotAdjustment)}
|
|
320
321
|
strokeDashoffset="0"
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
compact,
|
|
20
20
|
frameShapeMigrations,
|
|
21
21
|
frameShapeProps,
|
|
22
|
+
getColorValue,
|
|
22
23
|
getDefaultColorTheme,
|
|
23
24
|
lerp,
|
|
24
25
|
resizeBox,
|
|
@@ -220,13 +221,12 @@ export class FrameShapeUtil extends BaseBoxShapeUtil<TLFrameShape> {
|
|
|
220
221
|
)
|
|
221
222
|
|
|
222
223
|
const showFrameColors = this.options.showColors
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
const
|
|
228
|
-
const
|
|
229
|
-
const frameHeadingText = showFrameColors ? color.frame.text : theme.text
|
|
224
|
+
const colorToUse = showFrameColors ? shape.props.color : 'black'
|
|
225
|
+
const frameFill = getColorValue(theme, colorToUse, 'frameFill')
|
|
226
|
+
const frameStroke = getColorValue(theme, colorToUse, 'frameStroke')
|
|
227
|
+
const frameHeadingStroke = getColorValue(theme, colorToUse, 'frameHeadingStroke')
|
|
228
|
+
const frameHeadingFill = getColorValue(theme, colorToUse, 'frameHeadingFill')
|
|
229
|
+
const frameHeadingText = getColorValue(theme, colorToUse, 'frameText')
|
|
230
230
|
|
|
231
231
|
return (
|
|
232
232
|
<>
|
|
@@ -277,13 +277,12 @@ export class FrameShapeUtil extends BaseBoxShapeUtil<TLFrameShape> {
|
|
|
277
277
|
const text = createTextJsxFromSpans(this.editor, spans, opts)
|
|
278
278
|
|
|
279
279
|
const showFrameColors = this.options.showColors
|
|
280
|
-
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
const
|
|
284
|
-
const
|
|
285
|
-
const
|
|
286
|
-
const frameHeadingText = showFrameColors ? color.frame.text : theme.text
|
|
280
|
+
const colorToUse = showFrameColors ? shape.props.color : 'black'
|
|
281
|
+
const frameFill = getColorValue(theme, colorToUse, 'frameFill')
|
|
282
|
+
const frameStroke = getColorValue(theme, colorToUse, 'frameStroke')
|
|
283
|
+
const frameHeadingStroke = getColorValue(theme, colorToUse, 'frameHeadingStroke')
|
|
284
|
+
const frameHeadingFill = getColorValue(theme, colorToUse, 'frameHeadingFill')
|
|
285
|
+
const frameHeadingText = getColorValue(theme, colorToUse, 'frameText')
|
|
287
286
|
|
|
288
287
|
return (
|
|
289
288
|
<>
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
exhaustiveSwitchError,
|
|
19
19
|
geoShapeMigrations,
|
|
20
20
|
geoShapeProps,
|
|
21
|
+
getColorValue,
|
|
21
22
|
getDefaultColorTheme,
|
|
22
23
|
getFontsFromRichText,
|
|
23
24
|
isEqual,
|
|
@@ -220,7 +221,7 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
|
|
|
220
221
|
verticalAlign={verticalAlign}
|
|
221
222
|
richText={richText}
|
|
222
223
|
isSelected={isOnlySelected}
|
|
223
|
-
labelColor={theme
|
|
224
|
+
labelColor={getColorValue(theme, props.labelColor, 'solid')}
|
|
224
225
|
wrap
|
|
225
226
|
/>
|
|
226
227
|
</HTMLContainer>
|
|
@@ -278,7 +279,7 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
|
|
|
278
279
|
align={props.align}
|
|
279
280
|
verticalAlign={props.verticalAlign}
|
|
280
281
|
richText={props.richText}
|
|
281
|
-
labelColor={theme
|
|
282
|
+
labelColor={getColorValue(theme, props.labelColor, 'solid')}
|
|
282
283
|
bounds={bounds}
|
|
283
284
|
padding={LABEL_PADDING}
|
|
284
285
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TLGeoShape } from '@tldraw/editor'
|
|
1
|
+
import { getColorValue, TLGeoShape } from '@tldraw/editor'
|
|
2
2
|
import { ShapeFill } from '../../shared/ShapeFill'
|
|
3
3
|
import { STROKE_SIZES } from '../../shared/default-shape-constants'
|
|
4
4
|
import { useDefaultColorTheme } from '../../shared/useDefaultColorTheme'
|
|
@@ -33,7 +33,7 @@ export function GeoShapeBody({
|
|
|
33
33
|
strokeWidth,
|
|
34
34
|
forceSolid,
|
|
35
35
|
randomSeed: shape.id,
|
|
36
|
-
props: { fill: 'none', stroke: theme
|
|
36
|
+
props: { fill: 'none', stroke: getColorValue(theme, color, 'solid') },
|
|
37
37
|
})}
|
|
38
38
|
</>
|
|
39
39
|
)
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
TLHighlightShapeProps,
|
|
11
11
|
TLResizeInfo,
|
|
12
12
|
VecLike,
|
|
13
|
+
getColorValue,
|
|
13
14
|
highlightShapeMigrations,
|
|
14
15
|
highlightShapeProps,
|
|
15
16
|
last,
|
|
@@ -289,7 +290,12 @@ function HighlightRenderer({
|
|
|
289
290
|
: getShapeDot(shape.props.segments[0].points[0])
|
|
290
291
|
|
|
291
292
|
const colorSpace = useColorSpace()
|
|
292
|
-
|
|
293
|
+
|
|
294
|
+
const color = getColorValue(
|
|
295
|
+
theme,
|
|
296
|
+
shape.props.color,
|
|
297
|
+
colorSpace === 'p3' ? 'highlightP3' : 'highlightSrgb'
|
|
298
|
+
)
|
|
293
299
|
|
|
294
300
|
return (
|
|
295
301
|
<path
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
WeakCache,
|
|
13
13
|
ZERO_INDEX_KEY,
|
|
14
14
|
assert,
|
|
15
|
+
getColorValue,
|
|
15
16
|
getIndexAbove,
|
|
16
17
|
getIndexBetween,
|
|
17
18
|
getIndices,
|
|
@@ -346,6 +347,10 @@ function LineShapeSvg({
|
|
|
346
347
|
strokeWidth,
|
|
347
348
|
forceSolid,
|
|
348
349
|
randomSeed: shape.id,
|
|
349
|
-
props: {
|
|
350
|
+
props: {
|
|
351
|
+
transform: `scale(${scale})`,
|
|
352
|
+
stroke: getColorValue(theme, color, 'solid'),
|
|
353
|
+
fill: 'none',
|
|
354
|
+
},
|
|
350
355
|
})
|
|
351
356
|
}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
Vec,
|
|
18
18
|
WeakCache,
|
|
19
19
|
exhaustiveSwitchError,
|
|
20
|
+
getColorValue,
|
|
20
21
|
getDefaultColorTheme,
|
|
21
22
|
getFontsFromRichText,
|
|
22
23
|
isEqual,
|
|
@@ -288,7 +289,7 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
288
289
|
style={{
|
|
289
290
|
width: nw,
|
|
290
291
|
height: nh,
|
|
291
|
-
backgroundColor: theme
|
|
292
|
+
backgroundColor: getColorValue(theme, color, 'noteFill'),
|
|
292
293
|
borderBottom: hideShadows
|
|
293
294
|
? isDarkMode
|
|
294
295
|
? `${2 * scale}px solid rgb(20, 20, 20)`
|
|
@@ -308,7 +309,11 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
308
309
|
verticalAlign={verticalAlign}
|
|
309
310
|
richText={richText}
|
|
310
311
|
isSelected={isSelected}
|
|
311
|
-
labelColor={
|
|
312
|
+
labelColor={
|
|
313
|
+
labelColor === 'black'
|
|
314
|
+
? getColorValue(theme, color, 'noteText')
|
|
315
|
+
: getColorValue(theme, labelColor, 'fill')
|
|
316
|
+
}
|
|
312
317
|
wrap
|
|
313
318
|
padding={LABEL_PADDING * scale}
|
|
314
319
|
hasCustomTabBehavior
|
|
@@ -343,7 +348,7 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
343
348
|
align={shape.props.align}
|
|
344
349
|
verticalAlign={shape.props.verticalAlign}
|
|
345
350
|
richText={shape.props.richText}
|
|
346
|
-
labelColor={theme
|
|
351
|
+
labelColor={getColorValue(theme, shape.props.color, 'noteText')}
|
|
347
352
|
bounds={bounds}
|
|
348
353
|
padding={LABEL_PADDING}
|
|
349
354
|
showTextOutline={false}
|
|
@@ -357,7 +362,7 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
357
362
|
rx={1}
|
|
358
363
|
width={NOTE_SIZE}
|
|
359
364
|
height={bounds.h}
|
|
360
|
-
fill={theme
|
|
365
|
+
fill={getColorValue(theme, shape.props.color, 'noteFill')}
|
|
361
366
|
/>
|
|
362
367
|
{textLabel}
|
|
363
368
|
</>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
getColorValue,
|
|
2
3
|
TLDefaultColorStyle,
|
|
3
4
|
TLDefaultColorTheme,
|
|
4
5
|
TLDefaultFillStyle,
|
|
@@ -29,13 +30,13 @@ export const ShapeFill = React.memo(function ShapeFill({
|
|
|
29
30
|
return null
|
|
30
31
|
}
|
|
31
32
|
case 'solid': {
|
|
32
|
-
return <path fill={theme
|
|
33
|
+
return <path fill={getColorValue(theme, color, 'semi')} d={d} />
|
|
33
34
|
}
|
|
34
35
|
case 'semi': {
|
|
35
|
-
return <path fill={theme
|
|
36
|
+
return <path fill={getColorValue(theme, color, 'solid')} d={d} />
|
|
36
37
|
}
|
|
37
38
|
case 'fill': {
|
|
38
|
-
return <path fill={theme
|
|
39
|
+
return <path fill={getColorValue(theme, color, 'fill')} d={d} />
|
|
39
40
|
}
|
|
40
41
|
case 'pattern': {
|
|
41
42
|
return <PatternFill theme={theme} color={color} fill={fill} d={d} scale={scale} />
|
|
@@ -53,13 +54,13 @@ export function PatternFill({ d, color, theme }: ShapeFillProps) {
|
|
|
53
54
|
|
|
54
55
|
return (
|
|
55
56
|
<>
|
|
56
|
-
<path fill={theme
|
|
57
|
+
<path fill={getColorValue(theme, color, 'pattern')} d={d} />
|
|
57
58
|
<path
|
|
58
59
|
fill={
|
|
59
60
|
svgExport
|
|
60
61
|
? `url(#${getHashPatternZoomName(1, theme.id)})`
|
|
61
62
|
: teenyTiny
|
|
62
|
-
? theme
|
|
63
|
+
? getColorValue(theme, color, 'semi')
|
|
63
64
|
: `url(#${getHashPatternZoomName(zoomLevel, theme.id)})`
|
|
64
65
|
}
|
|
65
66
|
d={d}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
TLTextShape,
|
|
12
12
|
Vec,
|
|
13
13
|
createComputedCache,
|
|
14
|
+
getColorValue,
|
|
14
15
|
getDefaultColorTheme,
|
|
15
16
|
getFontsFromRichText,
|
|
16
17
|
isEqual,
|
|
@@ -135,7 +136,7 @@ export class TextShapeUtil extends ShapeUtil<TLTextShape> {
|
|
|
135
136
|
align={textAlign}
|
|
136
137
|
verticalAlign="middle"
|
|
137
138
|
richText={richText}
|
|
138
|
-
labelColor={theme
|
|
139
|
+
labelColor={getColorValue(theme, color, 'solid')}
|
|
139
140
|
isSelected={isSelected}
|
|
140
141
|
textWidth={width}
|
|
141
142
|
textHeight={height}
|
|
@@ -171,7 +172,7 @@ export class TextShapeUtil extends ShapeUtil<TLTextShape> {
|
|
|
171
172
|
align={shape.props.textAlign}
|
|
172
173
|
verticalAlign="middle"
|
|
173
174
|
richText={shape.props.richText}
|
|
174
|
-
labelColor={theme
|
|
175
|
+
labelColor={getColorValue(theme, shape.props.color, 'solid')}
|
|
175
176
|
bounds={exportBounds}
|
|
176
177
|
padding={0}
|
|
177
178
|
/>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DefaultColorStyle,
|
|
3
3
|
TLDefaultColorStyle,
|
|
4
|
+
getColorValue,
|
|
4
5
|
getDefaultColorTheme,
|
|
5
6
|
useEditor,
|
|
6
7
|
useValue,
|
|
@@ -25,9 +26,10 @@ export function MobileStylePanel() {
|
|
|
25
26
|
const relevantStyles = useRelevantStyles()
|
|
26
27
|
const color = relevantStyles?.get(DefaultColorStyle)
|
|
27
28
|
const theme = getDefaultColorTheme({ isDarkMode: editor.user.getIsDarkMode() })
|
|
28
|
-
const currentColor =
|
|
29
|
-
color?.type === 'shared'
|
|
30
|
-
|
|
29
|
+
const currentColor =
|
|
30
|
+
color?.type === 'shared'
|
|
31
|
+
? getColorValue(theme, color.value as TLDefaultColorStyle, 'solid')
|
|
32
|
+
: getColorValue(theme, 'black', 'solid')
|
|
31
33
|
|
|
32
34
|
const disableStylePanel = useValue(
|
|
33
35
|
'disable style panel',
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DefaultColorStyle,
|
|
3
|
+
getColorValue,
|
|
3
4
|
SharedStyle,
|
|
4
5
|
StyleProp,
|
|
5
6
|
TLDefaultColorStyle,
|
|
6
7
|
TLDefaultColorTheme,
|
|
7
8
|
useEditor,
|
|
8
9
|
} from '@tldraw/editor'
|
|
9
|
-
import {
|
|
10
|
+
import { memo, ReactElement, useMemo, useRef } from 'react'
|
|
10
11
|
import { StyleValuesForUi } from '../../../styles'
|
|
11
12
|
import { PORTRAIT_BREAKPOINT } from '../../constants'
|
|
12
13
|
import { useBreakpoint } from '../../context/breakpoints'
|
|
@@ -140,7 +141,7 @@ export const TldrawUiButtonPicker = memo(function TldrawUiButtonPicker<T extends
|
|
|
140
141
|
title={label}
|
|
141
142
|
style={
|
|
142
143
|
style === (DefaultColorStyle as StyleProp<unknown>)
|
|
143
|
-
? { color: theme
|
|
144
|
+
? { color: getColorValue(theme, item.value as TLDefaultColorStyle, 'solid') }
|
|
144
145
|
: undefined
|
|
145
146
|
}
|
|
146
147
|
onPointerEnter={handleButtonPointerEnter}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Editor, uniqueId, useMaybeEditor, Vec } from '@tldraw/editor'
|
|
1
|
+
import { assert, Editor, uniqueId, useMaybeEditor, Vec } from '@tldraw/editor'
|
|
2
2
|
import { Tooltip as _Tooltip } from 'radix-ui'
|
|
3
3
|
import React, { createContext, useContext, useEffect, useRef, useState } from 'react'
|
|
4
4
|
import { usePrefersReducedMotion } from '../../../shapes/shared/usePrefersReducedMotion'
|
|
@@ -69,20 +69,32 @@ class TooltipManager {
|
|
|
69
69
|
this.notify()
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
hideTooltip(tooltipId: string) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.destroyTimeoutId = null
|
|
82
|
-
this.notify()
|
|
83
|
-
}, 300)
|
|
72
|
+
hideTooltip(tooltipId: string, instant: boolean = false) {
|
|
73
|
+
const hide = () => {
|
|
74
|
+
// Only hide if this is the current tooltip
|
|
75
|
+
if (this.currentTooltipId === tooltipId) {
|
|
76
|
+
this.currentTooltipId = null
|
|
77
|
+
this.currentContent = ''
|
|
78
|
+
this.activeElement = null
|
|
79
|
+
this.destroyTimeoutId = null
|
|
80
|
+
this.notify()
|
|
84
81
|
}
|
|
85
82
|
}
|
|
83
|
+
|
|
84
|
+
if (instant) {
|
|
85
|
+
hide()
|
|
86
|
+
} else if (this.editor) {
|
|
87
|
+
// Start destroy timeout (1 second)
|
|
88
|
+
this.destroyTimeoutId = this.editor.timers.setTimeout(hide, 300)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
hideAllTooltips() {
|
|
93
|
+
this.currentTooltipId = null
|
|
94
|
+
this.currentContent = ''
|
|
95
|
+
this.activeElement = null
|
|
96
|
+
this.destroyTimeoutId = null
|
|
97
|
+
this.notify()
|
|
86
98
|
}
|
|
87
99
|
|
|
88
100
|
getCurrentTooltipData() {
|
|
@@ -96,7 +108,7 @@ class TooltipManager {
|
|
|
96
108
|
}
|
|
97
109
|
}
|
|
98
110
|
|
|
99
|
-
const tooltipManager = TooltipManager.getInstance()
|
|
111
|
+
export const tooltipManager = TooltipManager.getInstance()
|
|
100
112
|
|
|
101
113
|
// Context for the tooltip singleton
|
|
102
114
|
const TooltipSingletonContext = createContext<boolean>(false)
|
|
@@ -274,7 +286,11 @@ export function TldrawUiTooltip({
|
|
|
274
286
|
)
|
|
275
287
|
}
|
|
276
288
|
|
|
289
|
+
const child = React.Children.only(children)
|
|
290
|
+
assert(React.isValidElement(child), 'TldrawUiTooltip children must be a single element')
|
|
291
|
+
|
|
277
292
|
const handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {
|
|
293
|
+
child.props.onMouseEnter?.(event)
|
|
278
294
|
tooltipManager.showTooltip(
|
|
279
295
|
tooltipId.current,
|
|
280
296
|
content,
|
|
@@ -284,11 +300,13 @@ export function TldrawUiTooltip({
|
|
|
284
300
|
)
|
|
285
301
|
}
|
|
286
302
|
|
|
287
|
-
const handleMouseLeave = () => {
|
|
303
|
+
const handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {
|
|
304
|
+
child.props.onMouseLeave?.(event)
|
|
288
305
|
tooltipManager.hideTooltip(tooltipId.current)
|
|
289
306
|
}
|
|
290
307
|
|
|
291
308
|
const handleFocus = (event: React.FocusEvent<HTMLElement>) => {
|
|
309
|
+
child.props.onFocus?.(event)
|
|
292
310
|
tooltipManager.showTooltip(
|
|
293
311
|
tooltipId.current,
|
|
294
312
|
content,
|
|
@@ -298,7 +316,8 @@ export function TldrawUiTooltip({
|
|
|
298
316
|
)
|
|
299
317
|
}
|
|
300
318
|
|
|
301
|
-
const handleBlur = () => {
|
|
319
|
+
const handleBlur = (event: React.FocusEvent<HTMLElement>) => {
|
|
320
|
+
child.props.onBlur?.(event)
|
|
302
321
|
tooltipManager.hideTooltip(tooltipId.current)
|
|
303
322
|
}
|
|
304
323
|
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
exhaustiveSwitchError,
|
|
3
|
+
getPointerInfo,
|
|
4
|
+
preventDefault,
|
|
5
|
+
TLPointerEventInfo,
|
|
6
|
+
useEditor,
|
|
7
|
+
Vec,
|
|
8
|
+
VecModel,
|
|
9
|
+
} from '@tldraw/editor'
|
|
2
10
|
import { ContextMenu as _ContextMenu } from 'radix-ui'
|
|
3
|
-
import { useState } from 'react'
|
|
11
|
+
import { useMemo, useState } from 'react'
|
|
4
12
|
import { unwrapLabel } from '../../../context/actions'
|
|
5
13
|
import { TLUiEventSource } from '../../../context/events'
|
|
6
14
|
import { useReadonly } from '../../../hooks/useReadonly'
|
|
15
|
+
import { TLUiToolItem } from '../../../hooks/useTools'
|
|
7
16
|
import { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'
|
|
8
17
|
import { useTranslation } from '../../../hooks/useTranslation/useTranslation'
|
|
9
18
|
import { kbdStr } from '../../../kbd-utils'
|
|
@@ -15,6 +24,7 @@ import { TldrawUiDropdownMenuItem } from '../TldrawUiDropdownMenu'
|
|
|
15
24
|
import { TLUiIconJsx } from '../TldrawUiIcon'
|
|
16
25
|
import { TldrawUiKbd } from '../TldrawUiKbd'
|
|
17
26
|
import { TldrawUiToolbarButton } from '../TldrawUiToolbar'
|
|
27
|
+
import { tooltipManager } from '../TldrawUiTooltip'
|
|
18
28
|
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
|
19
29
|
|
|
20
30
|
/** @public */
|
|
@@ -63,6 +73,10 @@ export interface TLUiMenuItemProps<
|
|
|
63
73
|
* Whether the item is selected.
|
|
64
74
|
*/
|
|
65
75
|
isSelected?: boolean
|
|
76
|
+
/**
|
|
77
|
+
* The function to call when the item is dragged. If this is provided, the item will be draggable.
|
|
78
|
+
*/
|
|
79
|
+
onDragStart?(source: TLUiEventSource, info: TLPointerEventInfo): void
|
|
66
80
|
}
|
|
67
81
|
|
|
68
82
|
/** @public @react */
|
|
@@ -81,6 +95,7 @@ export function TldrawUiMenuItem<
|
|
|
81
95
|
onSelect,
|
|
82
96
|
noClose,
|
|
83
97
|
isSelected,
|
|
98
|
+
onDragStart,
|
|
84
99
|
}: TLUiMenuItemProps<TranslationKey, IconType>) {
|
|
85
100
|
const { type: menuType, sourceId } = useTldrawUiMenuContext()
|
|
86
101
|
|
|
@@ -207,6 +222,20 @@ export function TldrawUiMenuItem<
|
|
|
207
222
|
)
|
|
208
223
|
}
|
|
209
224
|
case 'toolbar': {
|
|
225
|
+
if (onDragStart) {
|
|
226
|
+
return (
|
|
227
|
+
<DraggableToolbarButton
|
|
228
|
+
id={id}
|
|
229
|
+
icon={icon}
|
|
230
|
+
onSelect={onSelect}
|
|
231
|
+
onDragStart={onDragStart}
|
|
232
|
+
labelToUse={labelToUse}
|
|
233
|
+
titleStr={titleStr}
|
|
234
|
+
disabled={disabled}
|
|
235
|
+
isSelected={isSelected}
|
|
236
|
+
/>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
210
239
|
return (
|
|
211
240
|
<TldrawUiToolbarButton
|
|
212
241
|
aria-label={labelStr}
|
|
@@ -227,6 +256,21 @@ export function TldrawUiMenuItem<
|
|
|
227
256
|
)
|
|
228
257
|
}
|
|
229
258
|
case 'toolbar-overflow': {
|
|
259
|
+
if (onDragStart) {
|
|
260
|
+
return (
|
|
261
|
+
<DraggableToolbarButton
|
|
262
|
+
id={id}
|
|
263
|
+
icon={icon}
|
|
264
|
+
onSelect={onSelect}
|
|
265
|
+
onDragStart={onDragStart}
|
|
266
|
+
labelToUse={labelToUse}
|
|
267
|
+
titleStr={titleStr}
|
|
268
|
+
disabled={disabled}
|
|
269
|
+
isSelected={isSelected}
|
|
270
|
+
overflow
|
|
271
|
+
/>
|
|
272
|
+
)
|
|
273
|
+
}
|
|
230
274
|
return (
|
|
231
275
|
<TldrawUiToolbarButton
|
|
232
276
|
aria-label={labelStr}
|
|
@@ -248,3 +292,175 @@ export function TldrawUiMenuItem<
|
|
|
248
292
|
}
|
|
249
293
|
}
|
|
250
294
|
}
|
|
295
|
+
|
|
296
|
+
function useDraggableEvents(
|
|
297
|
+
onDragStart: TLUiToolItem['onDragStart'],
|
|
298
|
+
onSelect: TLUiToolItem['onSelect']
|
|
299
|
+
) {
|
|
300
|
+
const editor = useEditor()
|
|
301
|
+
const events = useMemo(() => {
|
|
302
|
+
let state = { name: 'idle' } as
|
|
303
|
+
| {
|
|
304
|
+
name: 'idle'
|
|
305
|
+
}
|
|
306
|
+
| {
|
|
307
|
+
name: 'pointing'
|
|
308
|
+
screenSpaceStart: VecModel
|
|
309
|
+
}
|
|
310
|
+
| {
|
|
311
|
+
name: 'dragging'
|
|
312
|
+
screenSpaceStart: VecModel
|
|
313
|
+
}
|
|
314
|
+
| {
|
|
315
|
+
name: 'dragged'
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function handlePointerDown(e: React.PointerEvent<HTMLButtonElement>) {
|
|
319
|
+
state = {
|
|
320
|
+
name: 'pointing',
|
|
321
|
+
screenSpaceStart: { x: e.clientX, y: e.clientY },
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
e.currentTarget.setPointerCapture(e.pointerId)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function handlePointerMove(e: React.PointerEvent<HTMLButtonElement>) {
|
|
328
|
+
if ((e as any).isSpecialRedispatchedEvent) return
|
|
329
|
+
|
|
330
|
+
if (state.name === 'pointing') {
|
|
331
|
+
const distanceSq = Vec.Dist2(state.screenSpaceStart, { x: e.clientX, y: e.clientY })
|
|
332
|
+
if (
|
|
333
|
+
distanceSq >
|
|
334
|
+
(editor.getInstanceState().isCoarsePointer
|
|
335
|
+
? editor.options.coarseDragDistanceSquared
|
|
336
|
+
: editor.options.dragDistanceSquared)
|
|
337
|
+
) {
|
|
338
|
+
const screenSpaceStart = state.screenSpaceStart
|
|
339
|
+
state = {
|
|
340
|
+
name: 'dragging',
|
|
341
|
+
screenSpaceStart,
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
editor.run(() => {
|
|
345
|
+
// Set origin point
|
|
346
|
+
editor.dispatch({
|
|
347
|
+
type: 'pointer',
|
|
348
|
+
target: 'canvas',
|
|
349
|
+
name: 'pointer_down',
|
|
350
|
+
...getPointerInfo(e),
|
|
351
|
+
point: screenSpaceStart,
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
// Pointer down potentially selects shapes, so we need to deselect them.
|
|
355
|
+
editor.selectNone()
|
|
356
|
+
|
|
357
|
+
// start drag
|
|
358
|
+
onDragStart?.('toolbar', {
|
|
359
|
+
type: 'pointer',
|
|
360
|
+
target: 'canvas',
|
|
361
|
+
name: 'pointer_move',
|
|
362
|
+
...getPointerInfo(e),
|
|
363
|
+
point: screenSpaceStart,
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
tooltipManager.hideAllTooltips()
|
|
367
|
+
})
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function handlePointerUp(e: React.PointerEvent<HTMLButtonElement>) {
|
|
373
|
+
if ((e as any).isSpecialRedispatchedEvent) return
|
|
374
|
+
|
|
375
|
+
e.currentTarget.releasePointerCapture(e.pointerId)
|
|
376
|
+
|
|
377
|
+
editor.dispatch({
|
|
378
|
+
type: 'pointer',
|
|
379
|
+
target: 'canvas',
|
|
380
|
+
name: 'pointer_up',
|
|
381
|
+
...getPointerInfo(e),
|
|
382
|
+
})
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function handleClick() {
|
|
386
|
+
if (state.name === 'dragging' || state.name === 'dragged') {
|
|
387
|
+
state = { name: 'idle' }
|
|
388
|
+
return true
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
state = { name: 'idle' }
|
|
392
|
+
onSelect?.('toolbar')
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
onPointerDown: handlePointerDown,
|
|
397
|
+
onPointerMove: handlePointerMove,
|
|
398
|
+
onPointerUp: handlePointerUp,
|
|
399
|
+
onClick: handleClick,
|
|
400
|
+
}
|
|
401
|
+
}, [onDragStart, editor, onSelect])
|
|
402
|
+
|
|
403
|
+
return events
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function DraggableToolbarButton({
|
|
407
|
+
id,
|
|
408
|
+
labelToUse,
|
|
409
|
+
titleStr,
|
|
410
|
+
disabled,
|
|
411
|
+
isSelected,
|
|
412
|
+
icon,
|
|
413
|
+
onSelect,
|
|
414
|
+
onDragStart,
|
|
415
|
+
overflow,
|
|
416
|
+
}: {
|
|
417
|
+
id: string
|
|
418
|
+
disabled: boolean
|
|
419
|
+
labelToUse?: string
|
|
420
|
+
titleStr?: string
|
|
421
|
+
isSelected?: boolean
|
|
422
|
+
icon: TLUiMenuItemProps['icon']
|
|
423
|
+
onSelect: TLUiMenuItemProps['onSelect']
|
|
424
|
+
onDragStart: TLUiMenuItemProps['onDragStart']
|
|
425
|
+
overflow?: boolean
|
|
426
|
+
}) {
|
|
427
|
+
const events = useDraggableEvents(onDragStart, onSelect)
|
|
428
|
+
|
|
429
|
+
if (overflow) {
|
|
430
|
+
return (
|
|
431
|
+
<TldrawUiToolbarButton
|
|
432
|
+
aria-label={labelToUse}
|
|
433
|
+
aria-pressed={isSelected ? 'true' : 'false'}
|
|
434
|
+
isActive={isSelected}
|
|
435
|
+
className="tlui-button-grid__button"
|
|
436
|
+
data-testid={`tools.more.${id}`}
|
|
437
|
+
data-value={id}
|
|
438
|
+
disabled={disabled}
|
|
439
|
+
title={titleStr}
|
|
440
|
+
type="icon"
|
|
441
|
+
{...events}
|
|
442
|
+
>
|
|
443
|
+
<TldrawUiButtonIcon icon={icon!} />
|
|
444
|
+
</TldrawUiToolbarButton>
|
|
445
|
+
)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return (
|
|
449
|
+
<TldrawUiToolbarButton
|
|
450
|
+
aria-label={labelToUse}
|
|
451
|
+
aria-pressed={isSelected ? 'true' : 'false'}
|
|
452
|
+
data-testid={`tools.${id}`}
|
|
453
|
+
data-value={id}
|
|
454
|
+
disabled={disabled}
|
|
455
|
+
onTouchStart={(e) => {
|
|
456
|
+
preventDefault(e)
|
|
457
|
+
onSelect('toolbar')
|
|
458
|
+
}}
|
|
459
|
+
title={titleStr}
|
|
460
|
+
type="tool"
|
|
461
|
+
{...events}
|
|
462
|
+
>
|
|
463
|
+
<TldrawUiButtonIcon icon={icon!} />
|
|
464
|
+
</TldrawUiToolbarButton>
|
|
465
|
+
)
|
|
466
|
+
}
|