tldraw 3.16.0-canary.1647ca5bba28 → 3.16.0-canary.1e91d2e19e07
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 +122 -49
- package/dist-cjs/index.js +25 -9
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/arrowLabel.js +6 -0
- package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +2 -1
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +9 -4
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/{primitives/TldrawUiButtonPicker.js → StylePanel/StylePanelButtonPicker.js} +52 -45
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
- package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
- package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +23 -20
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +1 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +2 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +33 -5
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +5 -5
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +1 -1
- package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
- package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +2 -2
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +1 -1
- 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 +122 -49
- package/dist-esm/index.mjs +49 -17
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
- package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +2 -1
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +14 -5
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/{primitives/TldrawUiButtonPicker.mjs → StylePanel/StylePanelButtonPicker.mjs} +54 -43
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
- package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
- package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
- package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +20 -17
- package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +1 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +2 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +34 -5
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +5 -5
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +1 -1
- package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
- package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +2 -2
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +1 -1
- 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 +36 -13
- package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +2 -2
- package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +41 -0
- package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
- package/src/lib/shapes/frame/FrameShapeUtil.tsx +1 -0
- package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
- package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
- package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +27 -13
- package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -381
- package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +63 -50
- package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
- package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
- package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
- package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
- package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +2 -2
- package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +3 -0
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +50 -16
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +6 -6
- package/src/lib/ui/hooks/useTools.tsx +1 -1
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +2 -2
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +16 -2
- package/src/test/getCulledShapes.test.tsx +71 -2
- package/tldraw.css +24 -5
- package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
- package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
- package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
- package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
- package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
|
@@ -4,46 +4,52 @@ import {
|
|
|
4
4
|
SharedStyle,
|
|
5
5
|
StyleProp,
|
|
6
6
|
TLDefaultColorStyle,
|
|
7
|
-
TLDefaultColorTheme,
|
|
8
7
|
useEditor,
|
|
9
8
|
} from '@tldraw/editor'
|
|
10
9
|
import { memo, ReactElement, useMemo, useRef } from 'react'
|
|
10
|
+
import { useDefaultColorTheme } from '../../../shapes/shared/useDefaultColorTheme'
|
|
11
11
|
import { StyleValuesForUi } from '../../../styles'
|
|
12
12
|
import { PORTRAIT_BREAKPOINT } from '../../constants'
|
|
13
13
|
import { useBreakpoint } from '../../context/breakpoints'
|
|
14
14
|
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
|
15
15
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
16
|
-
import { TldrawUiButtonIcon } from '
|
|
17
|
-
import {
|
|
18
|
-
|
|
16
|
+
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
|
17
|
+
import {
|
|
18
|
+
TldrawUiToolbar,
|
|
19
|
+
TldrawUiToolbarToggleGroup,
|
|
20
|
+
TldrawUiToolbarToggleItem,
|
|
21
|
+
} from '../primitives/TldrawUiToolbar'
|
|
22
|
+
import { TldrawUiGrid, TldrawUiRow } from '../primitives/layout'
|
|
23
|
+
import { useStylePanelContext } from './StylePanelContext'
|
|
24
|
+
import { StylePanelSubheading } from './StylePanelSubheading'
|
|
19
25
|
|
|
20
26
|
/** @public */
|
|
21
|
-
export interface
|
|
27
|
+
export interface StylePanelButtonPickerProps<T extends string> {
|
|
22
28
|
title: string
|
|
23
29
|
uiType: string
|
|
24
30
|
style: StyleProp<T>
|
|
25
31
|
value: SharedStyle<T>
|
|
26
32
|
items: StyleValuesForUi<T>
|
|
27
|
-
|
|
28
|
-
onValueChange(style: StyleProp<T>, value: T): void
|
|
33
|
+
onValueChange?(style: StyleProp<T>, value: T): void
|
|
29
34
|
onHistoryMark?(id: string): void
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
/** @public */
|
|
33
|
-
export const
|
|
34
|
-
props:
|
|
38
|
+
export const StylePanelButtonPicker = memo(function StylePanelButtonPicker<T extends string>(
|
|
39
|
+
props: StylePanelButtonPickerProps<T>
|
|
35
40
|
) {
|
|
41
|
+
const ctx = useStylePanelContext()
|
|
42
|
+
|
|
36
43
|
const {
|
|
37
44
|
uiType,
|
|
38
45
|
items,
|
|
39
46
|
title,
|
|
40
47
|
style,
|
|
41
48
|
value,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
onHistoryMark,
|
|
45
|
-
theme,
|
|
49
|
+
onValueChange = ctx.onValueChange,
|
|
50
|
+
onHistoryMark = ctx.onHistoryMark,
|
|
46
51
|
} = props
|
|
52
|
+
const theme = useDefaultColorTheme()
|
|
47
53
|
const editor = useEditor()
|
|
48
54
|
const msg = useTranslation()
|
|
49
55
|
const breakpoint = useBreakpoint()
|
|
@@ -117,43 +123,50 @@ export const TldrawUiButtonPicker = memo(function TldrawUiButtonPicker<T extends
|
|
|
117
123
|
}
|
|
118
124
|
}, [editor, breakpoint, value, onHistoryMark, onValueChange, style])
|
|
119
125
|
|
|
120
|
-
const
|
|
126
|
+
const Layout = items.length > 4 ? TldrawUiGrid : TldrawUiRow
|
|
121
127
|
|
|
122
128
|
return (
|
|
123
|
-
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
129
|
+
<>
|
|
130
|
+
{ctx.showUiLabels && <StylePanelSubheading>{title}</StylePanelSubheading>}
|
|
131
|
+
<TldrawUiToolbar label={title}>
|
|
132
|
+
<TldrawUiToolbarToggleGroup
|
|
133
|
+
data-testid={`style.${uiType}`}
|
|
134
|
+
type="single"
|
|
135
|
+
value={value.type === 'shared' ? value.value : undefined}
|
|
136
|
+
asChild
|
|
137
|
+
>
|
|
138
|
+
<Layout>
|
|
139
|
+
{items.map((item) => {
|
|
140
|
+
const label =
|
|
141
|
+
title + ' — ' + msg(`${uiType}-style.${item.value}` as TLUiTranslationKey)
|
|
142
|
+
return (
|
|
143
|
+
<TldrawUiToolbarToggleItem
|
|
144
|
+
type="icon"
|
|
145
|
+
key={item.value}
|
|
146
|
+
data-id={item.value}
|
|
147
|
+
data-testid={`style.${uiType}.${item.value}`}
|
|
148
|
+
aria-label={label}
|
|
149
|
+
value={item.value}
|
|
150
|
+
data-state={value.type === 'shared' && value.value === item.value ? 'on' : 'off'}
|
|
151
|
+
data-isactive={value.type === 'shared' && value.value === item.value}
|
|
152
|
+
title={label}
|
|
153
|
+
style={
|
|
154
|
+
style === (DefaultColorStyle as StyleProp<unknown>)
|
|
155
|
+
? { color: getColorValue(theme, item.value as TLDefaultColorStyle, 'solid') }
|
|
156
|
+
: undefined
|
|
157
|
+
}
|
|
158
|
+
onPointerEnter={handleButtonPointerEnter}
|
|
159
|
+
onPointerDown={handleButtonPointerDown}
|
|
160
|
+
onPointerUp={handleButtonPointerUp}
|
|
161
|
+
onClick={handleButtonClick}
|
|
162
|
+
>
|
|
163
|
+
<TldrawUiButtonIcon icon={item.icon} />
|
|
164
|
+
</TldrawUiToolbarToggleItem>
|
|
165
|
+
)
|
|
166
|
+
})}
|
|
167
|
+
</Layout>
|
|
168
|
+
</TldrawUiToolbarToggleGroup>
|
|
169
|
+
</TldrawUiToolbar>
|
|
170
|
+
</>
|
|
158
171
|
)
|
|
159
|
-
}) as <T extends string>(props:
|
|
172
|
+
}) as <T extends string>(props: StylePanelButtonPickerProps<T>) => ReactElement
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ReadonlySharedStyleMap, StyleProp, useEditor, useValue } from '@tldraw/editor'
|
|
2
|
+
import { createContext, useCallback, useContext } from 'react'
|
|
3
|
+
import { useUiEvents } from '../../context/events'
|
|
4
|
+
|
|
5
|
+
/** @public */
|
|
6
|
+
export interface StylePanelContext {
|
|
7
|
+
styles: ReadonlySharedStyleMap
|
|
8
|
+
showUiLabels: boolean
|
|
9
|
+
onHistoryMark(id: string): void
|
|
10
|
+
onValueChange<T>(style: StyleProp<T>, value: T): void
|
|
11
|
+
}
|
|
12
|
+
const StylePanelContext = createContext<null | StylePanelContext>(null)
|
|
13
|
+
|
|
14
|
+
/** @public */
|
|
15
|
+
export interface StylePanelContextProviderProps {
|
|
16
|
+
children: React.ReactNode
|
|
17
|
+
styles: ReadonlySharedStyleMap
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** @public @react */
|
|
21
|
+
export function StylePanelContextProvider({ children, styles }: StylePanelContextProviderProps) {
|
|
22
|
+
const editor = useEditor()
|
|
23
|
+
const trackEvent = useUiEvents()
|
|
24
|
+
|
|
25
|
+
const onHistoryMark = useCallback((id: string) => editor.markHistoryStoppingPoint(id), [editor])
|
|
26
|
+
const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
|
|
27
|
+
const onValueChange = useCallback(
|
|
28
|
+
function <T>(style: StyleProp<T>, value: T) {
|
|
29
|
+
editor.run(() => {
|
|
30
|
+
if (editor.isIn('select')) {
|
|
31
|
+
editor.setStyleForSelectedShapes(style, value)
|
|
32
|
+
}
|
|
33
|
+
editor.setStyleForNextShapes(style, value)
|
|
34
|
+
editor.updateInstanceState({ isChangingStyle: true })
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
trackEvent('set-style', { source: 'style-panel', id: style.id, value: value as string })
|
|
38
|
+
},
|
|
39
|
+
[editor, trackEvent]
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<StylePanelContext.Provider
|
|
44
|
+
value={{
|
|
45
|
+
styles: styles,
|
|
46
|
+
showUiLabels,
|
|
47
|
+
onHistoryMark,
|
|
48
|
+
onValueChange,
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
{children}
|
|
52
|
+
</StylePanelContext.Provider>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** @public */
|
|
57
|
+
export function useStylePanelContext() {
|
|
58
|
+
const context = useContext(StylePanelContext)
|
|
59
|
+
if (!context) {
|
|
60
|
+
throw new Error('useStylePanelContext must be used within a StylePanelContextProvider')
|
|
61
|
+
}
|
|
62
|
+
return context
|
|
63
|
+
}
|
|
@@ -11,8 +11,10 @@ import {
|
|
|
11
11
|
} from '../primitives/TldrawUiPopover'
|
|
12
12
|
import { TldrawUiToolbar, TldrawUiToolbarButton } from '../primitives/TldrawUiToolbar'
|
|
13
13
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
|
14
|
+
import { useStylePanelContext } from './StylePanelContext'
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
/** @public */
|
|
17
|
+
export interface StylePanelDoubleDropdownPickerProps<T extends string> {
|
|
16
18
|
uiTypeA: string
|
|
17
19
|
uiTypeB: string
|
|
18
20
|
label: TLUiTranslationKey | Exclude<string, TLUiTranslationKey>
|
|
@@ -24,23 +26,27 @@ interface DoubleDropdownPickerProps<T extends string> {
|
|
|
24
26
|
styleB: StyleProp<T>
|
|
25
27
|
valueA: SharedStyle<T>
|
|
26
28
|
valueB: SharedStyle<T>
|
|
27
|
-
onValueChange(style: StyleProp<T>, value: T): void
|
|
29
|
+
onValueChange?(style: StyleProp<T>, value: T): void
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
function DoubleDropdownPickerInner<T extends string>(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
function DoubleDropdownPickerInner<T extends string>(
|
|
33
|
+
props: StylePanelDoubleDropdownPickerProps<T>
|
|
34
|
+
) {
|
|
35
|
+
const ctx = useStylePanelContext()
|
|
36
|
+
const {
|
|
37
|
+
label,
|
|
38
|
+
uiTypeA,
|
|
39
|
+
uiTypeB,
|
|
40
|
+
labelA,
|
|
41
|
+
labelB,
|
|
42
|
+
itemsA,
|
|
43
|
+
itemsB,
|
|
44
|
+
styleA,
|
|
45
|
+
styleB,
|
|
46
|
+
valueA,
|
|
47
|
+
valueB,
|
|
48
|
+
onValueChange = ctx.onValueChange,
|
|
49
|
+
} = props
|
|
44
50
|
const editor = useEditor()
|
|
45
51
|
const msg = useTranslation()
|
|
46
52
|
const [isOpenA, setIsOpenA] = React.useState(false)
|
|
@@ -155,6 +161,9 @@ function DoubleDropdownPickerInner<T extends string>({
|
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
// need to memo like this to get generics
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
/** @public @react */
|
|
165
|
+
export const StylePanelDoubleDropdownPicker = React.memo(DoubleDropdownPickerInner) as <
|
|
166
|
+
T extends string,
|
|
167
|
+
>(
|
|
168
|
+
props: StylePanelDoubleDropdownPickerProps<T>
|
|
169
|
+
) => React.JSX.Element
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { SharedStyle, StyleProp, tlmenus, useEditor } from '@tldraw/editor'
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
import { StyleValuesForUi } from '../../../styles'
|
|
4
|
+
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
|
5
|
+
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
6
|
+
import { TLUiIconType } from '../../icon-types'
|
|
7
|
+
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
|
8
|
+
import { TldrawUiButtonLabel } from '../primitives/Button/TldrawUiButtonLabel'
|
|
9
|
+
import {
|
|
10
|
+
TldrawUiPopover,
|
|
11
|
+
TldrawUiPopoverContent,
|
|
12
|
+
TldrawUiPopoverTrigger,
|
|
13
|
+
} from '../primitives/TldrawUiPopover'
|
|
14
|
+
import { TldrawUiToolbar, TldrawUiToolbarButton } from '../primitives/TldrawUiToolbar'
|
|
15
|
+
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
|
16
|
+
import { useStylePanelContext } from './StylePanelContext'
|
|
17
|
+
|
|
18
|
+
/** @public */
|
|
19
|
+
export interface StylePanelDropdownPickerProps<T extends string> {
|
|
20
|
+
id: string
|
|
21
|
+
label?: TLUiTranslationKey | Exclude<string, TLUiTranslationKey>
|
|
22
|
+
uiType: string
|
|
23
|
+
stylePanelType: string
|
|
24
|
+
style: StyleProp<T>
|
|
25
|
+
value: SharedStyle<T>
|
|
26
|
+
items: StyleValuesForUi<T>
|
|
27
|
+
type: 'icon' | 'tool' | 'menu'
|
|
28
|
+
onValueChange?(style: StyleProp<T>, value: T): void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function DropdownPickerInner<T extends string>(props: StylePanelDropdownPickerProps<T>) {
|
|
32
|
+
const ctx = useStylePanelContext()
|
|
33
|
+
const {
|
|
34
|
+
id,
|
|
35
|
+
label,
|
|
36
|
+
uiType,
|
|
37
|
+
stylePanelType,
|
|
38
|
+
style,
|
|
39
|
+
items,
|
|
40
|
+
type,
|
|
41
|
+
value,
|
|
42
|
+
onValueChange = ctx.onValueChange,
|
|
43
|
+
} = props
|
|
44
|
+
const msg = useTranslation()
|
|
45
|
+
const editor = useEditor()
|
|
46
|
+
const [isOpen, setIsOpen] = React.useState(false)
|
|
47
|
+
|
|
48
|
+
const icon = React.useMemo(
|
|
49
|
+
() => items.find((item) => value.type === 'shared' && item.value === value.value)?.icon,
|
|
50
|
+
[items, value]
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const stylePanelName = msg(`style-panel.${stylePanelType}` as TLUiTranslationKey)
|
|
54
|
+
|
|
55
|
+
const titleStr =
|
|
56
|
+
value.type === 'mixed'
|
|
57
|
+
? msg('style-panel.mixed')
|
|
58
|
+
: stylePanelName + ' — ' + msg(`${uiType}-style.${value.value}` as TLUiTranslationKey)
|
|
59
|
+
const labelStr = label ? msg(label) : ''
|
|
60
|
+
|
|
61
|
+
const popoverId = `style panel ${id}`
|
|
62
|
+
return (
|
|
63
|
+
<TldrawUiToolbar label={stylePanelName}>
|
|
64
|
+
<TldrawUiPopover
|
|
65
|
+
id={popoverId}
|
|
66
|
+
open={isOpen}
|
|
67
|
+
onOpenChange={setIsOpen}
|
|
68
|
+
className="tlui-style-panel__dropdown-picker"
|
|
69
|
+
>
|
|
70
|
+
<TldrawUiPopoverTrigger>
|
|
71
|
+
<TldrawUiToolbarButton
|
|
72
|
+
type={type}
|
|
73
|
+
data-testid={`style.${uiType}`}
|
|
74
|
+
data-direction="left"
|
|
75
|
+
title={titleStr}
|
|
76
|
+
>
|
|
77
|
+
{labelStr && <TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>}
|
|
78
|
+
<TldrawUiButtonIcon icon={(icon as TLUiIconType) ?? 'mixed'} />
|
|
79
|
+
</TldrawUiToolbarButton>
|
|
80
|
+
</TldrawUiPopoverTrigger>
|
|
81
|
+
<TldrawUiPopoverContent side="left" align="center">
|
|
82
|
+
<TldrawUiToolbar orientation={items.length > 4 ? 'grid' : 'horizontal'} label={labelStr}>
|
|
83
|
+
<TldrawUiMenuContextProvider type="icons" sourceId="style-panel">
|
|
84
|
+
{items.map((item) => {
|
|
85
|
+
return (
|
|
86
|
+
<TldrawUiToolbarButton
|
|
87
|
+
key={item.value}
|
|
88
|
+
type="icon"
|
|
89
|
+
data-testid={`style.${uiType}.${item.value}`}
|
|
90
|
+
title={
|
|
91
|
+
stylePanelName +
|
|
92
|
+
' — ' +
|
|
93
|
+
msg(`${uiType}-style.${item.value}` as TLUiTranslationKey)
|
|
94
|
+
}
|
|
95
|
+
isActive={icon === item.icon}
|
|
96
|
+
onClick={() => {
|
|
97
|
+
ctx.onHistoryMark('select style dropdown item')
|
|
98
|
+
onValueChange(style, item.value)
|
|
99
|
+
tlmenus.deleteOpenMenu(popoverId, editor.contextId)
|
|
100
|
+
setIsOpen(false)
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
<TldrawUiButtonIcon icon={item.icon} />
|
|
104
|
+
</TldrawUiToolbarButton>
|
|
105
|
+
)
|
|
106
|
+
})}
|
|
107
|
+
</TldrawUiMenuContextProvider>
|
|
108
|
+
</TldrawUiToolbar>
|
|
109
|
+
</TldrawUiPopoverContent>
|
|
110
|
+
</TldrawUiPopover>
|
|
111
|
+
</TldrawUiToolbar>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// need to export like this to get generics
|
|
116
|
+
/** @public @react */
|
|
117
|
+
export const StylePanelDropdownPicker = React.memo(DropdownPickerInner) as <T extends string>(
|
|
118
|
+
props: StylePanelDropdownPickerProps<T>
|
|
119
|
+
) => React.JSX.Element
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** @public */
|
|
2
|
+
export interface StylePanelSubheadingProps {
|
|
3
|
+
children: React.ReactNode
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/** @public @react */
|
|
7
|
+
export function StylePanelSubheading({ children }: StylePanelSubheadingProps) {
|
|
8
|
+
return <h3 className="tlui-style-panel__subheading">{children}</h3>
|
|
9
|
+
}
|
|
@@ -13,7 +13,7 @@ export interface TLUiSliderProps {
|
|
|
13
13
|
label: string
|
|
14
14
|
title: string
|
|
15
15
|
onValueChange(value: number): void
|
|
16
|
-
onHistoryMark(id: string): void
|
|
16
|
+
onHistoryMark?(id: string): void
|
|
17
17
|
'data-testid'?: string
|
|
18
18
|
ariaValueModifier?: number
|
|
19
19
|
}
|
|
@@ -53,7 +53,7 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
|
|
|
53
53
|
|
|
54
54
|
const handlePointerDown = useCallback(() => {
|
|
55
55
|
tooltipManager.hideAllTooltips()
|
|
56
|
-
onHistoryMark('click slider')
|
|
56
|
+
onHistoryMark?.('click slider')
|
|
57
57
|
}, [onHistoryMark])
|
|
58
58
|
|
|
59
59
|
// N.B. This is a bit silly. The Radix slider auto-focuses which
|
|
@@ -94,6 +94,7 @@ export interface TLUiToolbarToggleGroupProps extends React.HTMLAttributes<HTMLDi
|
|
|
94
94
|
// TODO: fix up this type later
|
|
95
95
|
defaultValue?: any
|
|
96
96
|
type: 'single' | 'multiple'
|
|
97
|
+
asChild?: boolean
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
/** @public @react */
|
|
@@ -101,10 +102,12 @@ export const TldrawUiToolbarToggleGroup = ({
|
|
|
101
102
|
children,
|
|
102
103
|
className,
|
|
103
104
|
type,
|
|
105
|
+
asChild,
|
|
104
106
|
...props
|
|
105
107
|
}: TLUiToolbarToggleGroupProps) => {
|
|
106
108
|
return (
|
|
107
109
|
<_Toolbar.ToggleGroup
|
|
110
|
+
asChild={asChild}
|
|
108
111
|
type={type}
|
|
109
112
|
{...props}
|
|
110
113
|
// TODO: this fixes a bug in Radix until they fix it.
|
|
@@ -6,6 +6,7 @@ import React, {
|
|
|
6
6
|
ReactNode,
|
|
7
7
|
useContext,
|
|
8
8
|
useEffect,
|
|
9
|
+
useLayoutEffect,
|
|
9
10
|
useRef,
|
|
10
11
|
useState,
|
|
11
12
|
} from 'react'
|
|
@@ -24,18 +25,20 @@ export interface TldrawUiTooltipProps {
|
|
|
24
25
|
delayDuration?: number
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
interface CurrentTooltip {
|
|
29
|
+
id: string
|
|
30
|
+
content: ReactNode
|
|
31
|
+
side: 'top' | 'right' | 'bottom' | 'left'
|
|
32
|
+
sideOffset: number
|
|
33
|
+
showOnMobile: boolean
|
|
34
|
+
targetElement: HTMLElement
|
|
35
|
+
delayDuration: number
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
// Singleton tooltip manager
|
|
28
39
|
class TooltipManager {
|
|
29
40
|
private static instance: TooltipManager | null = null
|
|
30
|
-
private currentTooltip = atom<
|
|
31
|
-
id: string
|
|
32
|
-
content: ReactNode
|
|
33
|
-
side: 'top' | 'right' | 'bottom' | 'left'
|
|
34
|
-
sideOffset: number
|
|
35
|
-
showOnMobile: boolean
|
|
36
|
-
targetElement: HTMLElement
|
|
37
|
-
delayDuration: number
|
|
38
|
-
} | null>('current tooltip', null)
|
|
41
|
+
private currentTooltip = atom<CurrentTooltip | null>('current tooltip', null)
|
|
39
42
|
private destroyTimeoutId: number | null = null
|
|
40
43
|
|
|
41
44
|
static getInstance(): TooltipManager {
|
|
@@ -72,6 +75,15 @@ class TooltipManager {
|
|
|
72
75
|
})
|
|
73
76
|
}
|
|
74
77
|
|
|
78
|
+
updateCurrentTooltip(tooltipId: string, update: (tooltip: CurrentTooltip) => CurrentTooltip) {
|
|
79
|
+
this.currentTooltip.update((tooltip) => {
|
|
80
|
+
if (tooltip?.id === tooltipId) {
|
|
81
|
+
return update(tooltip)
|
|
82
|
+
}
|
|
83
|
+
return tooltip
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
75
87
|
hideTooltip(editor: Editor | null, tooltipId: string, instant: boolean = false) {
|
|
76
88
|
const hide = () => {
|
|
77
89
|
// Only hide if this is the current tooltip
|
|
@@ -142,6 +154,7 @@ function TooltipSingleton() {
|
|
|
142
154
|
const [isOpen, setIsOpen] = useState(false)
|
|
143
155
|
const triggerRef = useRef<HTMLDivElement>(null)
|
|
144
156
|
const isFirstShowRef = useRef(true)
|
|
157
|
+
const editor = useMaybeEditor()
|
|
145
158
|
|
|
146
159
|
const currentTooltip = useValue(
|
|
147
160
|
'current tooltip',
|
|
@@ -149,6 +162,15 @@ function TooltipSingleton() {
|
|
|
149
162
|
[]
|
|
150
163
|
)
|
|
151
164
|
|
|
165
|
+
const cameraState = useValue('camera state', () => editor?.getCameraState(), [editor])
|
|
166
|
+
|
|
167
|
+
// Hide tooltip when camera is moving (panning/zooming)
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
if (cameraState === 'moving' && isOpen && currentTooltip) {
|
|
170
|
+
tooltipManager.hideTooltip(editor, currentTooltip.id, true)
|
|
171
|
+
}
|
|
172
|
+
}, [cameraState, isOpen, currentTooltip, editor])
|
|
173
|
+
|
|
152
174
|
// Update open state and trigger position
|
|
153
175
|
useEffect(() => {
|
|
154
176
|
let timer: ReturnType<typeof setTimeout> | null = null
|
|
@@ -231,12 +253,11 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
|
|
|
231
253
|
const editor = useMaybeEditor()
|
|
232
254
|
const tooltipId = useRef<string>(uniqueId())
|
|
233
255
|
const hasProvider = useContext(TooltipSingletonContext)
|
|
256
|
+
const showUiLabels = useValue('showUiLabels', () => editor?.user.getShowUiLabels(), [editor])
|
|
234
257
|
|
|
235
258
|
const orientationCtx = useTldrawUiOrientation()
|
|
236
259
|
const sideToUse = side ?? orientationCtx.tooltipSide
|
|
237
260
|
|
|
238
|
-
const camera = useValue('camera', () => editor?.getCamera(), [])
|
|
239
|
-
|
|
240
261
|
useEffect(() => {
|
|
241
262
|
const currentTooltipId = tooltipId.current
|
|
242
263
|
return () => {
|
|
@@ -246,17 +267,30 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
|
|
|
246
267
|
}
|
|
247
268
|
}, [editor, hasProvider])
|
|
248
269
|
|
|
249
|
-
|
|
250
|
-
tooltipManager.
|
|
251
|
-
|
|
270
|
+
useLayoutEffect(() => {
|
|
271
|
+
if (hasProvider && tooltipManager.getCurrentTooltipData()?.id === tooltipId.current) {
|
|
272
|
+
tooltipManager.updateCurrentTooltip(tooltipId.current, (tooltip) => ({
|
|
273
|
+
...tooltip,
|
|
274
|
+
content,
|
|
275
|
+
side: sideToUse,
|
|
276
|
+
sideOffset,
|
|
277
|
+
showOnMobile,
|
|
278
|
+
}))
|
|
279
|
+
}
|
|
280
|
+
}, [content, sideToUse, sideOffset, showOnMobile, hasProvider])
|
|
252
281
|
|
|
253
282
|
// Don't show tooltip if disabled, no content, or UI labels are disabled
|
|
254
283
|
if (disabled || !content) {
|
|
255
284
|
return <>{children}</>
|
|
256
285
|
}
|
|
257
286
|
|
|
258
|
-
|
|
259
|
-
|
|
287
|
+
let delayDurationToUse
|
|
288
|
+
if (showUiLabels) {
|
|
289
|
+
delayDurationToUse = 0
|
|
290
|
+
} else {
|
|
291
|
+
delayDurationToUse =
|
|
292
|
+
delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
|
|
293
|
+
}
|
|
260
294
|
|
|
261
295
|
// Fallback to old behavior if no provider
|
|
262
296
|
if (!hasProvider) {
|
|
@@ -213,7 +213,7 @@ export function TldrawUiMenuItem<
|
|
|
213
213
|
icon={icon}
|
|
214
214
|
onSelect={onSelect}
|
|
215
215
|
onDragStart={onDragStart}
|
|
216
|
-
|
|
216
|
+
labelStr={labelStr}
|
|
217
217
|
titleStr={titleStr}
|
|
218
218
|
disabled={disabled}
|
|
219
219
|
isSelected={isSelected}
|
|
@@ -247,7 +247,7 @@ export function TldrawUiMenuItem<
|
|
|
247
247
|
icon={icon}
|
|
248
248
|
onSelect={onSelect}
|
|
249
249
|
onDragStart={onDragStart}
|
|
250
|
-
|
|
250
|
+
labelStr={labelStr}
|
|
251
251
|
titleStr={titleStr}
|
|
252
252
|
disabled={disabled}
|
|
253
253
|
isSelected={isSelected}
|
|
@@ -392,7 +392,7 @@ function useDraggableEvents(
|
|
|
392
392
|
|
|
393
393
|
function DraggableToolbarButton({
|
|
394
394
|
id,
|
|
395
|
-
|
|
395
|
+
labelStr,
|
|
396
396
|
titleStr,
|
|
397
397
|
disabled,
|
|
398
398
|
isSelected,
|
|
@@ -403,7 +403,7 @@ function DraggableToolbarButton({
|
|
|
403
403
|
}: {
|
|
404
404
|
id: string
|
|
405
405
|
disabled: boolean
|
|
406
|
-
|
|
406
|
+
labelStr?: string
|
|
407
407
|
titleStr?: string
|
|
408
408
|
isSelected?: boolean
|
|
409
409
|
icon: TLUiMenuItemProps['icon']
|
|
@@ -416,7 +416,7 @@ function DraggableToolbarButton({
|
|
|
416
416
|
if (overflow) {
|
|
417
417
|
return (
|
|
418
418
|
<TldrawUiToolbarButton
|
|
419
|
-
aria-label={
|
|
419
|
+
aria-label={labelStr}
|
|
420
420
|
aria-pressed={isSelected ? 'true' : 'false'}
|
|
421
421
|
isActive={isSelected}
|
|
422
422
|
className="tlui-button-grid__button"
|
|
@@ -434,7 +434,7 @@ function DraggableToolbarButton({
|
|
|
434
434
|
|
|
435
435
|
return (
|
|
436
436
|
<TldrawUiToolbarButton
|
|
437
|
-
aria-label={
|
|
437
|
+
aria-label={labelStr}
|
|
438
438
|
aria-pressed={isSelected ? 'true' : 'false'}
|
|
439
439
|
data-testid={`tools.${id}`}
|
|
440
440
|
data-value={id}
|
|
@@ -176,7 +176,7 @@ export function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {
|
|
|
176
176
|
editor.createShape({
|
|
177
177
|
id,
|
|
178
178
|
type: 'arrow',
|
|
179
|
-
props: { start: { x: 0, y:
|
|
179
|
+
props: { start: { x: 0, y: 200 }, end: { x: 200, y: 0 } },
|
|
180
180
|
}),
|
|
181
181
|
})
|
|
182
182
|
trackEvent('drag-tool', { source, id: 'arrow' })
|
|
@@ -92,9 +92,9 @@ export const DEFAULT_TRANSLATION = {
|
|
|
92
92
|
'action.toggle-wrap-mode': 'Toggle Select on wrap',
|
|
93
93
|
'action.toggle-reduce-motion.menu': 'Reduce motion',
|
|
94
94
|
'action.toggle-reduce-motion': 'Toggle reduce motion',
|
|
95
|
-
'action.toggle-keyboard-shortcuts.menu': '
|
|
95
|
+
'action.toggle-keyboard-shortcuts.menu': 'Enable keyboard shortcuts',
|
|
96
96
|
'action.toggle-keyboard-shortcuts': 'Toggle keyboard shortcuts',
|
|
97
|
-
'action.toggle-ui-labels.menu': 'UI labels',
|
|
97
|
+
'action.toggle-ui-labels.menu': 'Enable UI labels',
|
|
98
98
|
'action.toggle-ui-labels': 'Toggle UI labels',
|
|
99
99
|
'action.toggle-edge-scrolling.menu': 'Edge scrolling',
|
|
100
100
|
'action.toggle-edge-scrolling': 'Toggle edge scrolling',
|
package/src/lib/ui/version.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This file is automatically generated by internal/scripts/refresh-assets.ts.
|
|
2
2
|
// Do not edit manually. Or do, I'm a comment, not a cop.
|
|
3
3
|
|
|
4
|
-
export const version = '3.16.0-canary.
|
|
4
|
+
export const version = '3.16.0-canary.1e91d2e19e07'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-09-
|
|
8
|
-
patch: '2025-09-
|
|
7
|
+
minor: '2025-09-12T17:16:34.637Z',
|
|
8
|
+
patch: '2025-09-12T17:16:34.637Z',
|
|
9
9
|
}
|