tldraw 3.16.0-canary.f60032f16651 → 3.16.0-canary.ffdf566dd0a8

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.
Files changed (98) hide show
  1. package/dist-cjs/index.d.ts +32 -34
  2. package/dist-cjs/index.js +7 -2
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js +10 -1
  5. package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js.map +2 -2
  6. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  7. package/dist-cjs/lib/ui/components/AccessibilityMenu.js +35 -0
  8. package/dist-cjs/lib/ui/components/AccessibilityMenu.js.map +7 -0
  9. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js +3 -3
  10. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js.map +2 -2
  11. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +2 -0
  12. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  13. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +168 -137
  14. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  15. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +3 -3
  16. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +2 -2
  17. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +3 -2
  18. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  19. package/dist-cjs/lib/ui/components/menu-items.js +6 -0
  20. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  21. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +11 -3
  22. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  23. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +267 -0
  24. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +7 -0
  25. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +1 -149
  26. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  27. package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js +3 -2
  28. package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js.map +2 -2
  29. package/dist-cjs/lib/ui/context/actions.js +15 -0
  30. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  31. package/dist-cjs/lib/ui/context/events.js.map +1 -1
  32. package/dist-cjs/lib/ui/hooks/useTools.js +9 -76
  33. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  34. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  35. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +3 -0
  36. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  37. package/dist-cjs/lib/ui/version.js +3 -3
  38. package/dist-cjs/lib/ui/version.js.map +1 -1
  39. package/dist-esm/index.d.mts +32 -34
  40. package/dist-esm/index.mjs +11 -3
  41. package/dist-esm/index.mjs.map +2 -2
  42. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs +10 -1
  43. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs.map +2 -2
  44. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  45. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs +19 -0
  46. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs.map +7 -0
  47. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs +3 -5
  48. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs.map +2 -2
  49. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +3 -1
  50. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  51. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +168 -137
  52. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  53. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +3 -3
  54. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +2 -2
  55. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +3 -2
  56. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  57. package/dist-esm/lib/ui/components/menu-items.mjs +6 -0
  58. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  59. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +11 -3
  60. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  61. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +237 -0
  62. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +7 -0
  63. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +3 -157
  64. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  65. package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs +3 -2
  66. package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs.map +2 -2
  67. package/dist-esm/lib/ui/context/actions.mjs +15 -0
  68. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  69. package/dist-esm/lib/ui/context/events.mjs.map +1 -1
  70. package/dist-esm/lib/ui/hooks/useTools.mjs +10 -83
  71. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  72. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +3 -0
  73. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  74. package/dist-esm/lib/ui/version.mjs +3 -3
  75. package/dist-esm/lib/ui/version.mjs.map +1 -1
  76. package/package.json +3 -3
  77. package/src/index.ts +8 -2
  78. package/src/lib/shapes/shared/usePrefersReducedMotion.tsx +11 -1
  79. package/src/lib/tools/SelectTool/childStates/Translating.ts +1 -0
  80. package/src/lib/ui/components/AccessibilityMenu.tsx +20 -0
  81. package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -4
  82. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +3 -1
  83. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +171 -128
  84. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +3 -3
  85. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +14 -11
  86. package/src/lib/ui/components/menu-items.tsx +8 -0
  87. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +19 -3
  88. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +313 -0
  89. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +2 -213
  90. package/src/lib/ui/context/TldrawUiContextProvider.tsx +23 -20
  91. package/src/lib/ui/context/actions.tsx +15 -0
  92. package/src/lib/ui/context/events.tsx +1 -1
  93. package/src/lib/ui/hooks/useTools.tsx +10 -118
  94. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +3 -0
  95. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +3 -0
  96. package/src/lib/ui/version.ts +3 -3
  97. package/src/lib/ui.css +57 -1
  98. package/tldraw.css +59 -1
@@ -1,4 +1,4 @@
1
- import { useEditor, usePassThroughWheelEvents } from '@tldraw/editor'
1
+ import { useEditor, usePassThroughWheelEvents, useValue } from '@tldraw/editor'
2
2
  import classNames from 'classnames'
3
3
  import { ReactNode, memo, useCallback, useEffect, useRef } from 'react'
4
4
  import { useRelevantStyles } from '../../hooks/useRelevantStyles'
@@ -16,6 +16,7 @@ export const DefaultStylePanel = memo(function DefaultStylePanel({
16
16
  children,
17
17
  }: TLUiStylePanelProps) {
18
18
  const editor = useEditor()
19
+ const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
19
20
 
20
21
  const ref = useRef<HTMLDivElement>(null)
21
22
  usePassThroughWheelEvents(ref)
@@ -50,6 +51,7 @@ export const DefaultStylePanel = memo(function DefaultStylePanel({
50
51
  ref={ref}
51
52
  className={classNames('tlui-style-panel', { 'tlui-style-panel__wrapper': !isMobile })}
52
53
  data-ismobile={isMobile}
54
+ data-show-ui-labels={showUiLabels}
53
55
  onPointerLeave={handlePointerOut}
54
56
  >
55
57
  {content}
@@ -35,6 +35,11 @@ import { TldrawUiToolbar, TldrawUiToolbarButton } from '../primitives/TldrawUiTo
35
35
  import { DoubleDropdownPicker } from './DoubleDropdownPicker'
36
36
  import { DropdownPicker } from './DropdownPicker'
37
37
 
38
+ // Local component for style panel subheadings
39
+ function StylePanelSubheading({ children }: { children: React.ReactNode }) {
40
+ return <h3 className="tlui-style-panel__subheading">{children}</h3>
41
+ }
42
+
38
43
  /** @public */
39
44
  export interface TLUiStylePanelContentProps {
40
45
  styles: ReturnType<typeof useRelevantStyles>
@@ -115,6 +120,7 @@ export function CommonStylePickerSet({ styles, theme }: ThemeStylePickerSetProps
115
120
  const editor = useEditor()
116
121
 
117
122
  const onHistoryMark = useCallback((id: string) => editor.markHistoryStoppingPoint(id), [editor])
123
+ const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
118
124
 
119
125
  const handleValueChange = useStyleChangeCallback()
120
126
 
@@ -129,70 +135,90 @@ export function CommonStylePickerSet({ styles, theme }: ThemeStylePickerSetProps
129
135
  <>
130
136
  <div className="tlui-style-panel__section__common" data-testid="style.panel">
131
137
  {color === undefined ? null : (
132
- <TldrawUiToolbar label={msg('style-panel.color')}>
133
- <TldrawUiButtonPicker
134
- title={msg('style-panel.color')}
135
- uiType="color"
136
- style={DefaultColorStyle}
137
- items={STYLES.color}
138
- value={color}
139
- onValueChange={handleValueChange}
140
- theme={theme}
141
- onHistoryMark={onHistoryMark}
142
- />
143
- </TldrawUiToolbar>
144
- )}
145
- <OpacitySlider />
146
- </div>
147
- {showPickers && (
148
- <div className="tlui-style-panel__section">
149
- {fill === undefined ? null : (
150
- <TldrawUiToolbar label={msg('style-panel.fill')}>
138
+ <>
139
+ {showUiLabels && (
140
+ <StylePanelSubheading>{msg('style-panel.color')}</StylePanelSubheading>
141
+ )}
142
+ <TldrawUiToolbar label={msg('style-panel.color')}>
151
143
  <TldrawUiButtonPicker
152
- title={msg('style-panel.fill')}
153
- uiType="fill"
154
- style={DefaultFillStyle}
155
- items={STYLES.fill}
156
- value={fill}
144
+ title={msg('style-panel.color')}
145
+ uiType="color"
146
+ style={DefaultColorStyle}
147
+ items={STYLES.color}
148
+ value={color}
157
149
  onValueChange={handleValueChange}
158
150
  theme={theme}
159
151
  onHistoryMark={onHistoryMark}
160
152
  />
161
153
  </TldrawUiToolbar>
154
+ </>
155
+ )}
156
+ <OpacitySlider />
157
+ </div>
158
+ {showPickers && (
159
+ <div className="tlui-style-panel__section">
160
+ {fill === undefined ? null : (
161
+ <>
162
+ {showUiLabels && (
163
+ <StylePanelSubheading>{msg('style-panel.fill')}</StylePanelSubheading>
164
+ )}
165
+ <TldrawUiToolbar label={msg('style-panel.fill')}>
166
+ <TldrawUiButtonPicker
167
+ title={msg('style-panel.fill')}
168
+ uiType="fill"
169
+ style={DefaultFillStyle}
170
+ items={STYLES.fill}
171
+ value={fill}
172
+ onValueChange={handleValueChange}
173
+ theme={theme}
174
+ onHistoryMark={onHistoryMark}
175
+ />
176
+ </TldrawUiToolbar>
177
+ </>
162
178
  )}
163
179
  {dash === undefined ? null : (
164
- <TldrawUiToolbar label={msg('style-panel.dash')}>
165
- <TldrawUiButtonPicker
166
- title={msg('style-panel.dash')}
167
- uiType="dash"
168
- style={DefaultDashStyle}
169
- items={STYLES.dash}
170
- value={dash}
171
- onValueChange={handleValueChange}
172
- theme={theme}
173
- onHistoryMark={onHistoryMark}
174
- />
175
- </TldrawUiToolbar>
180
+ <>
181
+ {showUiLabels && (
182
+ <StylePanelSubheading>{msg('style-panel.dash')}</StylePanelSubheading>
183
+ )}
184
+ <TldrawUiToolbar label={msg('style-panel.dash')}>
185
+ <TldrawUiButtonPicker
186
+ title={msg('style-panel.dash')}
187
+ uiType="dash"
188
+ style={DefaultDashStyle}
189
+ items={STYLES.dash}
190
+ value={dash}
191
+ onValueChange={handleValueChange}
192
+ theme={theme}
193
+ onHistoryMark={onHistoryMark}
194
+ />
195
+ </TldrawUiToolbar>
196
+ </>
176
197
  )}
177
198
  {size === undefined ? null : (
178
- <TldrawUiToolbar label={msg('style-panel.size')}>
179
- <TldrawUiButtonPicker
180
- title={msg('style-panel.size')}
181
- uiType="size"
182
- style={DefaultSizeStyle}
183
- items={STYLES.size}
184
- value={size}
185
- onValueChange={(style, value) => {
186
- handleValueChange(style, value)
187
- const selectedShapeIds = editor.getSelectedShapeIds()
188
- if (selectedShapeIds.length > 0) {
189
- kickoutOccludedShapes(editor, selectedShapeIds)
190
- }
191
- }}
192
- theme={theme}
193
- onHistoryMark={onHistoryMark}
194
- />
195
- </TldrawUiToolbar>
199
+ <>
200
+ {showUiLabels && (
201
+ <StylePanelSubheading>{msg('style-panel.size')}</StylePanelSubheading>
202
+ )}
203
+ <TldrawUiToolbar label={msg('style-panel.size')}>
204
+ <TldrawUiButtonPicker
205
+ title={msg('style-panel.size')}
206
+ uiType="size"
207
+ style={DefaultSizeStyle}
208
+ items={STYLES.size}
209
+ value={size}
210
+ onValueChange={(style, value) => {
211
+ handleValueChange(style, value)
212
+ const selectedShapeIds = editor.getSelectedShapeIds()
213
+ if (selectedShapeIds.length > 0) {
214
+ kickoutOccludedShapes(editor, selectedShapeIds)
215
+ }
216
+ }}
217
+ theme={theme}
218
+ onHistoryMark={onHistoryMark}
219
+ />
220
+ </TldrawUiToolbar>
221
+ </>
196
222
  )}
197
223
  </div>
198
224
  )}
@@ -207,6 +233,8 @@ export function TextStylePickerSet({ theme, styles }: ThemeStylePickerSetProps)
207
233
 
208
234
  const editor = useEditor()
209
235
  const onHistoryMark = useCallback((id: string) => editor.markHistoryStoppingPoint(id), [editor])
236
+ const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
237
+ const labelStr = showUiLabels && msg('style-panel.font')
210
238
 
211
239
  const font = styles.get(DefaultFontStyle)
212
240
  const textAlign = styles.get(DefaultTextAlignStyle)
@@ -219,59 +247,38 @@ export function TextStylePickerSet({ theme, styles }: ThemeStylePickerSetProps)
219
247
  return (
220
248
  <div className="tlui-style-panel__section">
221
249
  {font === undefined ? null : (
222
- <TldrawUiToolbar label={msg('style-panel.font')}>
223
- <TldrawUiButtonPicker
224
- title={msg('style-panel.font')}
225
- uiType="font"
226
- style={DefaultFontStyle}
227
- items={STYLES.font}
228
- value={font}
229
- onValueChange={handleValueChange}
230
- theme={theme}
231
- onHistoryMark={onHistoryMark}
232
- />
233
- </TldrawUiToolbar>
250
+ <>
251
+ {labelStr && <StylePanelSubheading>{labelStr}</StylePanelSubheading>}
252
+ <TldrawUiToolbar label={msg('style-panel.font')}>
253
+ <TldrawUiButtonPicker
254
+ title={msg('style-panel.font')}
255
+ uiType="font"
256
+ style={DefaultFontStyle}
257
+ items={STYLES.font}
258
+ value={font}
259
+ onValueChange={handleValueChange}
260
+ theme={theme}
261
+ onHistoryMark={onHistoryMark}
262
+ />
263
+ </TldrawUiToolbar>
264
+ </>
234
265
  )}
235
266
 
236
267
  {textAlign === undefined ? null : (
237
- <TldrawUiToolbar label={msg('style-panel.align')} className="tlui-style-panel__row">
238
- <TldrawUiButtonPicker
239
- title={msg('style-panel.align')}
240
- uiType="align"
241
- style={DefaultTextAlignStyle}
242
- items={STYLES.textAlign}
243
- value={textAlign}
244
- onValueChange={handleValueChange}
245
- theme={theme}
246
- onHistoryMark={onHistoryMark}
247
- />
248
- <div className="tlui-style-panel__row__extra-button">
249
- <TldrawUiToolbarButton
250
- type="icon"
251
- title={msg('style-panel.vertical-align')}
252
- data-testid="vertical-align"
253
- disabled
254
- >
255
- <TldrawUiButtonIcon icon="vertical-align-middle" />
256
- </TldrawUiToolbarButton>
257
- </div>
258
- </TldrawUiToolbar>
259
- )}
260
-
261
- {labelAlign === undefined ? null : (
262
- <TldrawUiToolbar label={msg('style-panel.label-align')} className="tlui-style-panel__row">
263
- <TldrawUiButtonPicker
264
- title={msg('style-panel.label-align')}
265
- uiType="align"
266
- style={DefaultHorizontalAlignStyle}
267
- items={STYLES.horizontalAlign}
268
- value={labelAlign}
269
- onValueChange={handleValueChange}
270
- theme={theme}
271
- onHistoryMark={onHistoryMark}
272
- />
273
- <div className="tlui-style-panel__row__extra-button">
274
- {verticalLabelAlign === undefined ? (
268
+ <>
269
+ {showUiLabels && <StylePanelSubheading>{msg('style-panel.align')}</StylePanelSubheading>}
270
+ <TldrawUiToolbar label={msg('style-panel.align')} className="tlui-style-panel__row">
271
+ <TldrawUiButtonPicker
272
+ title={msg('style-panel.align')}
273
+ uiType="align"
274
+ style={DefaultTextAlignStyle}
275
+ items={STYLES.textAlign}
276
+ value={textAlign}
277
+ onValueChange={handleValueChange}
278
+ theme={theme}
279
+ onHistoryMark={onHistoryMark}
280
+ />
281
+ <div className="tlui-style-panel__row__extra-button">
275
282
  <TldrawUiToolbarButton
276
283
  type="icon"
277
284
  title={msg('style-panel.vertical-align')}
@@ -280,20 +287,52 @@ export function TextStylePickerSet({ theme, styles }: ThemeStylePickerSetProps)
280
287
  >
281
288
  <TldrawUiButtonIcon icon="vertical-align-middle" />
282
289
  </TldrawUiToolbarButton>
283
- ) : (
284
- <DropdownPicker
285
- type="icon"
286
- id="geo-vertical-alignment"
287
- uiType="verticalAlign"
288
- stylePanelType="vertical-align"
289
- style={DefaultVerticalAlignStyle}
290
- items={STYLES.verticalAlign}
291
- value={verticalLabelAlign}
292
- onValueChange={handleValueChange}
293
- />
294
- )}
295
- </div>
296
- </TldrawUiToolbar>
290
+ </div>
291
+ </TldrawUiToolbar>
292
+ </>
293
+ )}
294
+
295
+ {labelAlign === undefined ? null : (
296
+ <>
297
+ {showUiLabels && (
298
+ <StylePanelSubheading>{msg('style-panel.label-align')}</StylePanelSubheading>
299
+ )}
300
+ <TldrawUiToolbar label={msg('style-panel.label-align')} className="tlui-style-panel__row">
301
+ <TldrawUiButtonPicker
302
+ title={msg('style-panel.label-align')}
303
+ uiType="align"
304
+ style={DefaultHorizontalAlignStyle}
305
+ items={STYLES.horizontalAlign}
306
+ value={labelAlign}
307
+ onValueChange={handleValueChange}
308
+ theme={theme}
309
+ onHistoryMark={onHistoryMark}
310
+ />
311
+ <div className="tlui-style-panel__row__extra-button">
312
+ {verticalLabelAlign === undefined ? (
313
+ <TldrawUiToolbarButton
314
+ type="icon"
315
+ title={msg('style-panel.vertical-align')}
316
+ data-testid="vertical-align"
317
+ disabled
318
+ >
319
+ <TldrawUiButtonIcon icon="vertical-align-middle" />
320
+ </TldrawUiToolbarButton>
321
+ ) : (
322
+ <DropdownPicker
323
+ type="icon"
324
+ id="geo-vertical-alignment"
325
+ uiType="verticalAlign"
326
+ stylePanelType="vertical-align"
327
+ style={DefaultVerticalAlignStyle}
328
+ items={STYLES.verticalAlign}
329
+ value={verticalLabelAlign}
330
+ onValueChange={handleValueChange}
331
+ />
332
+ )}
333
+ </div>
334
+ </TldrawUiToolbar>
335
+ </>
297
336
  )}
298
337
  </div>
299
338
  )
@@ -410,6 +449,7 @@ export function OpacitySlider() {
410
449
  const editor = useEditor()
411
450
 
412
451
  const onHistoryMark = useCallback((id: string) => editor.markHistoryStoppingPoint(id), [editor])
452
+ const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
413
453
 
414
454
  const opacity = useValue('opacity', () => editor.getSharedOpacity(), [editor])
415
455
  const trackEvent = useUiEvents()
@@ -443,15 +483,18 @@ export function OpacitySlider() {
443
483
  )
444
484
 
445
485
  return (
446
- <TldrawUiSlider
447
- data-testid="style.opacity"
448
- value={opacityIndex >= 0 ? opacityIndex : tldrawSupportedOpacities.length - 1}
449
- label={opacity.type === 'mixed' ? 'style-panel.mixed' : `opacity-style.${opacity.value}`}
450
- onValueChange={handleOpacityValueChange}
451
- steps={tldrawSupportedOpacities.length - 1}
452
- title={msg('style-panel.opacity')}
453
- onHistoryMark={onHistoryMark}
454
- ariaValueModifier={25}
455
- />
486
+ <>
487
+ {showUiLabels && <StylePanelSubheading>{msg('style-panel.opacity')}</StylePanelSubheading>}
488
+ <TldrawUiSlider
489
+ data-testid="style.opacity"
490
+ value={opacityIndex >= 0 ? opacityIndex : tldrawSupportedOpacities.length - 1}
491
+ label={opacity.type === 'mixed' ? 'style-panel.mixed' : `opacity-style.${opacity.value}`}
492
+ onValueChange={handleOpacityValueChange}
493
+ steps={tldrawSupportedOpacities.length - 1}
494
+ title={msg('style-panel.opacity')}
495
+ onHistoryMark={onHistoryMark}
496
+ ariaValueModifier={25}
497
+ />
498
+ </>
456
499
  )
457
500
  }
@@ -61,13 +61,13 @@ export function OverflowingToolbar({ children }: OverflowingToolbarProps) {
61
61
  const activeCss = lastActiveOverflowItem ? `:not([data-value="${lastActiveOverflowItem}"])` : ''
62
62
 
63
63
  return `
64
- #${id}_main > *:nth-child(n + ${overflowIndex + (lastActiveOverflowItem ? 1 : 2)})${activeCss} {
64
+ #${id}_main > *:nth-of-type(n + ${overflowIndex + (lastActiveOverflowItem ? 1 : 2)}):not([data-radix-popper-content-wrapper])${activeCss} {
65
65
  display: none;
66
66
  }
67
- #${id}_more > *:nth-child(-n + ${overflowIndex}) {
67
+ #${id}_more > *:nth-of-type(-n + ${overflowIndex}):not([data-radix-popper-content-wrapper]) {
68
68
  display: none;
69
69
  }
70
- #${id}_more > *:nth-child(-n + ${overflowIndex + 4}) {
70
+ #${id}_more > *:nth-of-type(-n + ${overflowIndex + 4}):not([data-radix-popper-content-wrapper]) {
71
71
  margin-top: 0;
72
72
  }
73
73
  `
@@ -5,6 +5,7 @@ import { useBreakpoint } from '../../context/breakpoints'
5
5
  import { useTranslation } from '../../hooks/useTranslation/useTranslation'
6
6
  import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
7
7
  import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
8
+ import { TldrawUiTooltip } from '../primitives/TldrawUiTooltip'
8
9
 
9
10
  /** @public */
10
11
  export interface ToggleToolLockedButtonProps {
@@ -25,16 +26,18 @@ export function ToggleToolLockedButton({ activeToolId }: ToggleToolLockedButtonP
25
26
  if (!activeToolId || !tool.isLockable) return null
26
27
 
27
28
  return (
28
- <TldrawUiButton
29
- type="normal"
30
- title={msg('action.toggle-tool-lock')}
31
- data-testid="tool-lock"
32
- className={classNames('tlui-toolbar__lock-button', {
33
- 'tlui-toolbar__lock-button__mobile': breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM,
34
- })}
35
- onClick={() => editor.updateInstanceState({ isToolLocked: !isToolLocked })}
36
- >
37
- <TldrawUiButtonIcon icon={isToolLocked ? 'lock' : 'unlock'} small />
38
- </TldrawUiButton>
29
+ <TldrawUiTooltip content={msg('action.toggle-tool-lock')}>
30
+ <TldrawUiButton
31
+ type="normal"
32
+ title={msg('action.toggle-tool-lock')}
33
+ data-testid="tool-lock"
34
+ className={classNames('tlui-toolbar__lock-button', {
35
+ 'tlui-toolbar__lock-button__mobile': breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM,
36
+ })}
37
+ onClick={() => editor.updateInstanceState({ isToolLocked: !isToolLocked })}
38
+ >
39
+ <TldrawUiButtonIcon icon={isToolLocked ? 'lock' : 'unlock'} small />
40
+ </TldrawUiButton>
41
+ </TldrawUiTooltip>
39
42
  )
40
43
  }
@@ -651,6 +651,14 @@ export function ToggleKeyboardShortcutsItem() {
651
651
  )
652
652
  }
653
653
 
654
+ /** @public @react */
655
+ export function ToggleUiLabelsItem() {
656
+ const editor = useEditor()
657
+ const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
658
+
659
+ return <TldrawUiMenuActionCheckboxItem actionId="toggle-ui-labels" checked={showUiLabels} />
660
+ }
661
+
654
662
  /** @public @react */
655
663
  export function ToggleDebugModeItem() {
656
664
  const editor = useEditor()
@@ -1,6 +1,7 @@
1
1
  import classnames from 'classnames'
2
2
  import { Toolbar as _Toolbar } from 'radix-ui'
3
3
  import React from 'react'
4
+ import { TldrawUiTooltip } from './TldrawUiTooltip'
4
5
 
5
6
  /** @public */
6
7
  export interface TLUiToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -34,23 +35,30 @@ export interface TLUiToolbarButtonProps extends React.HTMLAttributes<HTMLButtonE
34
35
  disabled?: boolean
35
36
  isActive?: boolean
36
37
  type: 'icon' | 'tool' | 'menu'
38
+ tooltip?: string
37
39
  }
38
40
 
39
41
  /** @public @react */
40
42
  export const TldrawUiToolbarButton = React.forwardRef<HTMLButtonElement, TLUiToolbarButtonProps>(
41
- ({ asChild, children, type, isActive, ...props }: TLUiToolbarButtonProps, ref) => {
42
- return (
43
+ ({ asChild, children, type, isActive, tooltip, ...props }: TLUiToolbarButtonProps, ref) => {
44
+ const button = (
43
45
  <_Toolbar.Button
44
46
  ref={ref}
45
47
  asChild={asChild}
46
48
  draggable={false}
47
49
  data-isactive={isActive}
48
50
  {...props}
51
+ // The tooltip takes care of this.
52
+ title={undefined}
49
53
  className={classnames('tlui-button', `tlui-button__${type}`, props.className)}
50
54
  >
51
55
  {children}
52
56
  </_Toolbar.Button>
53
57
  )
58
+
59
+ const tooltipContent = tooltip || props.title
60
+
61
+ return <TldrawUiTooltip content={tooltipContent}>{button}</TldrawUiTooltip>
54
62
  }
55
63
  )
56
64
 
@@ -93,6 +101,7 @@ export interface TLUiToolbarToggleItemProps extends React.HTMLAttributes<HTMLBut
93
101
  className?: string
94
102
  type: 'icon' | 'tool'
95
103
  value: string
104
+ tooltip?: string
96
105
  }
97
106
 
98
107
  /** @public @react */
@@ -101,11 +110,14 @@ export const TldrawUiToolbarToggleItem = ({
101
110
  className,
102
111
  type,
103
112
  value,
113
+ tooltip,
104
114
  ...props
105
115
  }: TLUiToolbarToggleItemProps) => {
106
- return (
116
+ const toggleItem = (
107
117
  <_Toolbar.ToggleItem
108
118
  {...props}
119
+ // The tooltip takes care of this.
120
+ title={undefined}
109
121
  className={classnames(
110
122
  'tlui-button',
111
123
  `tlui-button__${type}`,
@@ -117,4 +129,8 @@ export const TldrawUiToolbarToggleItem = ({
117
129
  {children}
118
130
  </_Toolbar.ToggleItem>
119
131
  )
132
+
133
+ const tooltipContent = tooltip || props.title
134
+
135
+ return <TldrawUiTooltip content={tooltipContent}>{toggleItem}</TldrawUiTooltip>
120
136
  }