tldraw 3.16.0-canary.5170ef6b6e20 → 3.16.0-canary.54408756ac9c
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 +131 -100
- package/dist-cjs/index.js +25 -14
- 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/shared/PlainTextLabel.js +1 -3
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +0 -2
- package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
- package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.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/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 +7 -4
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +7 -8
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
- package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
- 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/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-cjs/lib/utils/export/copyAs.js +1 -2
- package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
- package/dist-cjs/lib/utils/export/export.js +0 -20
- package/dist-cjs/lib/utils/export/export.js.map +2 -2
- package/dist-cjs/lib/utils/export/exportAs.js +1 -2
- package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
- package/dist-esm/index.d.mts +131 -100
- package/dist-esm/index.mjs +51 -28
- 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/shared/PlainTextLabel.mjs +1 -3
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +0 -2
- package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
- package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.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/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 +7 -4
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +7 -8
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
- package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
- 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/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
- package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
- package/dist-esm/lib/utils/export/export.mjs +0 -20
- package/dist-esm/lib/utils/export/export.mjs.map +2 -2
- package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
- package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
- package/package.json +3 -3
- package/src/index.ts +38 -21
- package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
- package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
- package/src/lib/shapes/shared/useEditablePlainText.ts +0 -6
- package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
- 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/TldrawUiToolbar.tsx +3 -0
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +10 -6
- package/src/lib/ui/context/actions.tsx +7 -8
- package/src/lib/ui/hooks/useExportAs.ts +3 -2
- package/src/lib/ui/hooks/useTools.tsx +1 -1
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +16 -2
- package/src/lib/utils/export/copyAs.ts +1 -24
- package/src/lib/utils/export/export.ts +0 -36
- package/src/lib/utils/export/exportAs.ts +1 -32
- 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
|
+
}
|
|
@@ -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.
|
|
@@ -142,6 +142,7 @@ function TooltipSingleton() {
|
|
|
142
142
|
const [isOpen, setIsOpen] = useState(false)
|
|
143
143
|
const triggerRef = useRef<HTMLDivElement>(null)
|
|
144
144
|
const isFirstShowRef = useRef(true)
|
|
145
|
+
const editor = useMaybeEditor()
|
|
145
146
|
|
|
146
147
|
const currentTooltip = useValue(
|
|
147
148
|
'current tooltip',
|
|
@@ -149,6 +150,15 @@ function TooltipSingleton() {
|
|
|
149
150
|
[]
|
|
150
151
|
)
|
|
151
152
|
|
|
153
|
+
const cameraState = useValue('camera state', () => editor?.getCameraState(), [editor])
|
|
154
|
+
|
|
155
|
+
// Hide tooltip when camera is moving (panning/zooming)
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (cameraState === 'moving' && isOpen && currentTooltip) {
|
|
158
|
+
tooltipManager.hideTooltip(editor, currentTooltip.id, true)
|
|
159
|
+
}
|
|
160
|
+
}, [cameraState, isOpen, currentTooltip, editor])
|
|
161
|
+
|
|
152
162
|
// Update open state and trigger position
|
|
153
163
|
useEffect(() => {
|
|
154
164
|
let timer: ReturnType<typeof setTimeout> | null = null
|
|
@@ -235,8 +245,6 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
|
|
|
235
245
|
const orientationCtx = useTldrawUiOrientation()
|
|
236
246
|
const sideToUse = side ?? orientationCtx.tooltipSide
|
|
237
247
|
|
|
238
|
-
const camera = useValue('camera', () => editor?.getCamera(), [])
|
|
239
|
-
|
|
240
248
|
useEffect(() => {
|
|
241
249
|
const currentTooltipId = tooltipId.current
|
|
242
250
|
return () => {
|
|
@@ -246,10 +254,6 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
|
|
|
246
254
|
}
|
|
247
255
|
}, [editor, hasProvider])
|
|
248
256
|
|
|
249
|
-
useEffect(() => {
|
|
250
|
-
tooltipManager.hideTooltip(editor, tooltipId.current, true)
|
|
251
|
-
}, [editor, camera])
|
|
252
|
-
|
|
253
257
|
// Don't show tooltip if disabled, no content, or UI labels are disabled
|
|
254
258
|
if (disabled || !content) {
|
|
255
259
|
return <>{children}</>
|
|
@@ -225,7 +225,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
225
225
|
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
|
226
226
|
if (ids.length === 0) return
|
|
227
227
|
trackEvent('export-as', { format: 'svg', source })
|
|
228
|
-
helpers.exportAs(ids, 'svg', getExportName(editor, defaultDocumentName))
|
|
228
|
+
helpers.exportAs(ids, { format: 'svg', name: getExportName(editor, defaultDocumentName) })
|
|
229
229
|
},
|
|
230
230
|
},
|
|
231
231
|
{
|
|
@@ -241,7 +241,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
241
241
|
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
|
242
242
|
if (ids.length === 0) return
|
|
243
243
|
trackEvent('export-as', { format: 'png', source })
|
|
244
|
-
helpers.exportAs(ids, 'png', getExportName(editor, defaultDocumentName))
|
|
244
|
+
helpers.exportAs(ids, { format: 'png', name: getExportName(editor, defaultDocumentName) })
|
|
245
245
|
},
|
|
246
246
|
},
|
|
247
247
|
{
|
|
@@ -257,11 +257,10 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
257
257
|
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
|
258
258
|
if (ids.length === 0) return
|
|
259
259
|
trackEvent('export-all-as', { format: 'svg', source })
|
|
260
|
-
helpers.exportAs(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
)
|
|
260
|
+
helpers.exportAs(Array.from(editor.getCurrentPageShapeIds()), {
|
|
261
|
+
format: 'svg',
|
|
262
|
+
name: getExportName(editor, defaultDocumentName),
|
|
263
|
+
})
|
|
265
264
|
},
|
|
266
265
|
},
|
|
267
266
|
{
|
|
@@ -276,7 +275,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
276
275
|
const ids = Array.from(editor.getCurrentPageShapeIds().values())
|
|
277
276
|
if (ids.length === 0) return
|
|
278
277
|
trackEvent('export-all-as', { format: 'png', source })
|
|
279
|
-
helpers.exportAs(ids, 'png', getExportName(editor, defaultDocumentName))
|
|
278
|
+
helpers.exportAs(ids, { format: 'png', name: getExportName(editor, defaultDocumentName) })
|
|
280
279
|
},
|
|
281
280
|
},
|
|
282
281
|
{
|
|
@@ -11,12 +11,13 @@ export function useExportAs() {
|
|
|
11
11
|
const msg = useTranslation()
|
|
12
12
|
|
|
13
13
|
return useCallback(
|
|
14
|
-
(ids: TLShapeId[],
|
|
14
|
+
(ids: TLShapeId[], opts: { format?: TLExportType; name?: string; scale?: number } = {}) => {
|
|
15
15
|
assert(editor, 'useExportAs: editor is required')
|
|
16
|
+
const { format = 'png', name, scale = 1 } = opts
|
|
16
17
|
exportAs(editor, ids, {
|
|
17
18
|
format,
|
|
18
19
|
name,
|
|
19
|
-
scale
|
|
20
|
+
scale,
|
|
20
21
|
}).catch((e) => {
|
|
21
22
|
console.error(e.message)
|
|
22
23
|
addToast({
|
|
@@ -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' })
|
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.54408756ac9c'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-
|
|
8
|
-
patch: '2025-
|
|
7
|
+
minor: '2025-09-09T16:35:13.062Z',
|
|
8
|
+
patch: '2025-09-09T16:35:13.062Z',
|
|
9
9
|
}
|
package/src/lib/ui.css
CHANGED
|
@@ -1007,9 +1007,23 @@
|
|
|
1007
1007
|
flex-direction: column;
|
|
1008
1008
|
}
|
|
1009
1009
|
|
|
1010
|
-
|
|
1010
|
+
/*
|
|
1011
|
+
add a border to the bottom of all but the last section. we have to handle empty sections too, which
|
|
1012
|
+
are hidden and shouldn't be counted
|
|
1013
|
+
*/
|
|
1014
|
+
.tlui-style-panel__section:not(:nth-last-child(-n + 1 of .tlui-style-panel__section:not(:empty))) {
|
|
1011
1015
|
border-bottom: 1px solid var(--tl-color-divider);
|
|
1012
1016
|
}
|
|
1017
|
+
/*
|
|
1018
|
+
if a section ends with a slider and we're adding a border, we need some extra space for visual
|
|
1019
|
+
balance. we need to handle empty sections as above. is this the most complex css selector in all of
|
|
1020
|
+
tldraw? probably.
|
|
1021
|
+
*/
|
|
1022
|
+
.tlui-style-panel__section:has(.tlui-slider__container:last-child):not(
|
|
1023
|
+
:nth-last-child(-n + 1 of .tlui-style-panel__section:not(:empty))
|
|
1024
|
+
) {
|
|
1025
|
+
margin-bottom: 7px;
|
|
1026
|
+
}
|
|
1013
1027
|
|
|
1014
1028
|
.tlui-style-panel__section:empty {
|
|
1015
1029
|
display: none;
|
|
@@ -1021,7 +1035,7 @@
|
|
|
1021
1035
|
}
|
|
1022
1036
|
|
|
1023
1037
|
.tlui-style-panel__dropdown-picker:only-child {
|
|
1024
|
-
|
|
1038
|
+
flex: 1;
|
|
1025
1039
|
}
|
|
1026
1040
|
|
|
1027
1041
|
.tlui-style-panel__double-select-picker {
|
|
@@ -31,30 +31,7 @@ export interface CopyAsOptions extends TLImageExportOptions {
|
|
|
31
31
|
*
|
|
32
32
|
* @public
|
|
33
33
|
*/
|
|
34
|
-
export function copyAs(editor: Editor, ids: TLShapeId[], opts: CopyAsOptions): Promise<void>
|
|
35
|
-
/**
|
|
36
|
-
* @deprecated The format parameter is now part of the opts object.
|
|
37
|
-
* @public
|
|
38
|
-
*/
|
|
39
|
-
export function copyAs(
|
|
40
|
-
editor: Editor,
|
|
41
|
-
ids: TLShapeId[],
|
|
42
|
-
format: TLCopyType,
|
|
43
|
-
opts?: TLImageExportOptions & { format?: undefined }
|
|
44
|
-
): Promise<void>
|
|
45
|
-
export function copyAs(
|
|
46
|
-
...args:
|
|
47
|
-
| [editor: Editor, ids: TLShapeId[], opts: TLImageExportOptions & { format: TLCopyType }]
|
|
48
|
-
| [
|
|
49
|
-
editor: Editor,
|
|
50
|
-
ids: TLShapeId[],
|
|
51
|
-
format: TLCopyType,
|
|
52
|
-
opts?: TLImageExportOptions & { format?: undefined },
|
|
53
|
-
]
|
|
54
|
-
) {
|
|
55
|
-
const [editor, ids, opts] =
|
|
56
|
-
typeof args[2] === 'string' ? [args[0], args[1], { ...args[3], format: args[2] }] : args
|
|
57
|
-
|
|
34
|
+
export function copyAs(editor: Editor, ids: TLShapeId[], opts: CopyAsOptions): Promise<void> {
|
|
58
35
|
// Note: it's important that this function itself isn't async and doesn't really use promises -
|
|
59
36
|
// we need to create the relevant `ClipboardItem`s and call navigator.clipboard.write
|
|
60
37
|
// synchronously to make sure safari knows that the user _wants_ to copy See
|