tldraw 4.2.0-canary.e6ed9aee7fe4 → 4.2.0-canary.e7800b04c779

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 (75) hide show
  1. package/dist-cjs/index.d.ts +2 -1
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js +5 -2
  4. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js.map +2 -2
  5. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +63 -36
  6. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +2 -2
  7. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +3 -3
  8. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  9. package/dist-cjs/lib/shapes/shared/ShapeFill.js +3 -0
  10. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  11. package/dist-cjs/lib/ui/components/Dialogs.js +2 -14
  12. package/dist-cjs/lib/ui/components/Dialogs.js.map +2 -2
  13. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +5 -4
  14. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  15. package/dist-cjs/lib/ui/components/Toolbar/DefaultRichTextToolbarContent.js +2 -1
  16. package/dist-cjs/lib/ui/components/Toolbar/DefaultRichTextToolbarContent.js.map +2 -2
  17. package/dist-cjs/lib/ui/components/primitives/Button/TldrawUiButton.js +2 -2
  18. package/dist-cjs/lib/ui/components/primitives/Button/TldrawUiButton.js.map +2 -2
  19. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +2 -1
  20. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  21. package/dist-cjs/lib/ui/context/actions.js +16 -0
  22. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  23. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  24. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +1 -0
  25. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  26. package/dist-cjs/lib/ui/hooks/useTranslation/useTranslation.js +1 -0
  27. package/dist-cjs/lib/ui/hooks/useTranslation/useTranslation.js.map +2 -2
  28. package/dist-cjs/lib/ui/version.js +3 -3
  29. package/dist-cjs/lib/ui/version.js.map +1 -1
  30. package/dist-esm/index.d.mts +2 -1
  31. package/dist-esm/index.mjs +1 -1
  32. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs +6 -2
  33. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs.map +2 -2
  34. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +65 -38
  35. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
  36. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +5 -5
  37. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  38. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +3 -0
  39. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  40. package/dist-esm/lib/ui/components/Dialogs.mjs +2 -14
  41. package/dist-esm/lib/ui/components/Dialogs.mjs.map +2 -2
  42. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +5 -5
  43. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  44. package/dist-esm/lib/ui/components/Toolbar/DefaultRichTextToolbarContent.mjs +2 -1
  45. package/dist-esm/lib/ui/components/Toolbar/DefaultRichTextToolbarContent.mjs.map +2 -2
  46. package/dist-esm/lib/ui/components/primitives/Button/TldrawUiButton.mjs +2 -2
  47. package/dist-esm/lib/ui/components/primitives/Button/TldrawUiButton.mjs.map +2 -2
  48. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +2 -1
  49. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  50. package/dist-esm/lib/ui/context/actions.mjs +16 -0
  51. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  52. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +1 -0
  53. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  54. package/dist-esm/lib/ui/hooks/useTranslation/useTranslation.mjs +1 -0
  55. package/dist-esm/lib/ui/hooks/useTranslation/useTranslation.mjs.map +2 -2
  56. package/dist-esm/lib/ui/version.mjs +3 -3
  57. package/dist-esm/lib/ui/version.mjs.map +1 -1
  58. package/package.json +3 -3
  59. package/src/lib/canvas/TldrawSelectionForeground.tsx +18 -2
  60. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +48 -24
  61. package/src/lib/shapes/note/NoteShapeUtil.tsx +6 -5
  62. package/src/lib/shapes/shared/ShapeFill.tsx +3 -0
  63. package/src/lib/ui/components/Dialogs.tsx +2 -14
  64. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +6 -5
  65. package/src/lib/ui/components/Toolbar/DefaultRichTextToolbarContent.tsx +4 -1
  66. package/src/lib/ui/components/primitives/Button/TldrawUiButton.tsx +3 -2
  67. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +1 -0
  68. package/src/lib/ui/context/actions.tsx +16 -0
  69. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +1 -0
  70. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +1 -0
  71. package/src/lib/ui/hooks/useTranslation/useTranslation.tsx +2 -1
  72. package/src/lib/ui/version.ts +3 -3
  73. package/src/lib/ui.css +4 -6
  74. package/src/test/TldrawEditor.test.tsx +74 -29
  75. package/tldraw.css +4 -6
@@ -1495,6 +1495,22 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
1495
1495
  trackEvent('set-style', { source, id: style.id, value: 'fill' })
1496
1496
  },
1497
1497
  },
1498
+ {
1499
+ id: 'select-fill-lined-fill',
1500
+ label: 'fill-style.lined-fill',
1501
+ kbd: 'alt+shift+f',
1502
+ onSelect(source) {
1503
+ const style = DefaultFillStyle
1504
+ editor.run(() => {
1505
+ editor.markHistoryStoppingPoint('change-fill')
1506
+ if (editor.isIn('select')) {
1507
+ editor.setStyleForSelectedShapes(style, 'lined-fill')
1508
+ }
1509
+ editor.setStyleForNextShapes(style, 'lined-fill')
1510
+ })
1511
+ trackEvent('set-style', { source, id: style.id, value: 'lined-fill' })
1512
+ },
1513
+ },
1498
1514
  {
1499
1515
  id: 'flatten-to-image',
1500
1516
  label: 'action.flatten-to-image',
@@ -154,6 +154,7 @@ export type TLUiTranslationKey =
154
154
  | 'fill-style.solid'
155
155
  | 'fill-style.pattern'
156
156
  | 'fill-style.fill'
157
+ | 'fill-style.lined-fill'
157
158
  | 'dash-style.dashed'
158
159
  | 'dash-style.dotted'
159
160
  | 'dash-style.draw'
@@ -155,6 +155,7 @@ export const DEFAULT_TRANSLATION = {
155
155
  'fill-style.solid': 'Solid',
156
156
  'fill-style.pattern': 'Pattern',
157
157
  'fill-style.fill': 'Fill',
158
+ 'fill-style.lined-fill': 'Lined fill',
158
159
  'dash-style.dashed': 'Dashed',
159
160
  'dash-style.dotted': 'Dotted',
160
161
  'dash-style.draw': 'Draw',
@@ -23,7 +23,8 @@ export interface TLUiTranslationProviderProps {
23
23
  /** @public */
24
24
  export type TLUiTranslationContextType = TLUiTranslation
25
25
 
26
- const TranslationsContext = React.createContext<TLUiTranslationContextType | null>(null)
26
+ /** @internal */
27
+ export const TranslationsContext = React.createContext<TLUiTranslationContextType | null>(null)
27
28
 
28
29
  /** @public */
29
30
  export function useCurrentTranslation() {
@@ -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 = '4.2.0-canary.e6ed9aee7fe4'
4
+ export const version = '4.2.0-canary.e7800b04c779'
5
5
  export const publishDates = {
6
6
  major: '2025-09-18T14:39:22.803Z',
7
- minor: '2025-10-30T15:48:19.323Z',
8
- patch: '2025-10-30T15:48:19.323Z',
7
+ minor: '2025-11-14T14:34:54.102Z',
8
+ patch: '2025-11-14T14:34:54.102Z',
9
9
  }
package/src/lib/ui.css CHANGED
@@ -514,12 +514,10 @@
514
514
  /* If mobile use 16px as font size */
515
515
  /* On iOS, font size under 16px in an input will make the page zoom into the input 🤦‍♂️ */
516
516
  /* https://css-tricks.com/16px-or-larger-text-prevents-ios-form-zoom/ */
517
- @media (max-width: 600px) {
518
- @supports (-webkit-touch-callout: none) {
519
- /* CSS specific to iOS devices */
520
- .tlui-input {
521
- font-size: 16px;
522
- }
517
+ @supports (-webkit-touch-callout: none) {
518
+ /* CSS specific to iOS devices */
519
+ .tlui-input {
520
+ font-size: 16px;
523
521
  }
524
522
  }
525
523
 
@@ -6,16 +6,17 @@ import {
6
6
  HTMLContainer,
7
7
  TLAssetStore,
8
8
  TLBaseShape,
9
+ TLShapeId,
9
10
  TldrawEditor,
10
11
  createShapeId,
11
12
  createTLStore,
12
13
  noop,
14
+ toRichText,
13
15
  } from '@tldraw/editor'
14
16
  import { StrictMode } from 'react'
15
17
  import { vi } from 'vitest'
16
18
  import { defaultShapeUtils } from '../lib/defaultShapeUtils'
17
19
  import { defaultTools } from '../lib/defaultTools'
18
- import { GeoShapeUtil } from '../lib/shapes/geo/GeoShapeUtil'
19
20
  import { defaultAddFontsFromNode, tipTapDefaultExtensions } from '../lib/utils/text/richText'
20
21
  import {
21
22
  renderTldrawComponent,
@@ -169,7 +170,7 @@ describe('<TldrawEditor />', () => {
169
170
  let editor = {} as Editor
170
171
  await renderTldrawComponent(
171
172
  <TldrawEditor
172
- shapeUtils={[GeoShapeUtil]}
173
+ shapeUtils={defaultShapeUtils}
173
174
  initialState="select"
174
175
  tools={defaultTools}
175
176
  onMount={(editorApp) => {
@@ -185,39 +186,83 @@ describe('<TldrawEditor />', () => {
185
186
  editor.updateInstanceState({ screenBounds: { x: 0, y: 0, w: 1080, h: 720 } })
186
187
  })
187
188
 
188
- const id = createShapeId()
189
-
190
- await act(async () => {
191
- editor.createShapes([
192
- {
193
- id,
194
- type: 'geo',
195
- props: { w: 100, h: 100 },
189
+ // Test all shape types except group
190
+ const shapeTypesToTest = [
191
+ { type: 'arrow' as const, props: { start: { x: 0, y: 0 }, end: { x: 100, y: 100 } } },
192
+ { type: 'bookmark' as const, props: { w: 100, h: 100, url: 'https://example.com' } },
193
+ {
194
+ type: 'draw' as const,
195
+ props: { segments: [{ type: 'free' as const, points: [{ x: 0, y: 0, z: 0.5 }] }] },
196
+ },
197
+ { type: 'embed' as const, props: { w: 100, h: 100, url: 'https://example.com' } },
198
+ { type: 'frame' as const, props: { w: 100, h: 100 } },
199
+ { type: 'geo' as const, props: { w: 100, h: 100, geo: 'rectangle' } },
200
+ {
201
+ type: 'highlight' as const,
202
+ props: { segments: [{ type: 'free' as const, points: [{ x: 0, y: 0, z: 0.5 }] }] },
203
+ },
204
+ { type: 'image' as const, props: { w: 100, h: 100 } },
205
+ {
206
+ type: 'line' as const,
207
+ props: {
208
+ points: {
209
+ a1: { id: 'a1', index: 'a1', x: 0, y: 0 },
210
+ a2: { id: 'a2', index: 'a2', x: 100, y: 100 },
211
+ },
196
212
  },
197
- ])
198
- })
213
+ },
214
+ { type: 'note' as const, props: { richText: toRichText('test') } },
215
+ { type: 'text' as const, props: { w: 100, richText: toRichText('test') } },
216
+ { type: 'video' as const, props: { w: 100, h: 100 } },
217
+ ]
218
+
219
+ const shapeIds: TLShapeId[] = []
220
+
221
+ for (let i = 0; i < shapeTypesToTest.length; i++) {
222
+ const shapeConfig = shapeTypesToTest[i]
223
+ const id = createShapeId()
224
+ shapeIds.push(id)
225
+
226
+ await act(async () => {
227
+ editor.createShapes([
228
+ {
229
+ id,
230
+ type: shapeConfig.type,
231
+ x: i * 150, // Space them out horizontally
232
+ y: 0,
233
+ props: shapeConfig.props,
234
+ },
235
+ ])
236
+ })
237
+
238
+ // Does the shape exist?
239
+ const shape = editor.getShape(id)
240
+ expect(shape).toBeTruthy()
241
+ expect(shape?.type).toBe(shapeConfig.type)
242
+
243
+ // Check that all shapes rendered without error boundaries
244
+ expect(
245
+ document.querySelectorAll('.tl-shape-error-boundary'),
246
+ `${shapeConfig.type} had an error while rendering`
247
+ ).toHaveLength(0)
248
+ }
199
249
 
200
- // Does the shape exist?
201
- expect(editor.getShape(id)).toMatchObject({
202
- id,
203
- type: 'geo',
204
- x: 0,
205
- y: 0,
206
- opacity: 1,
207
- props: { geo: 'rectangle', w: 100, h: 100 },
208
- })
250
+ // Check that all shape components are rendering
251
+ expect(document.querySelectorAll('.tl-shape').length).toBeGreaterThanOrEqual(
252
+ shapeTypesToTest.length
253
+ )
209
254
 
210
- // Is the shape's component rendering?
211
- expect(document.querySelectorAll('.tl-shape')).toHaveLength(1)
212
- // though indicator should be display none
213
- expect(document.querySelectorAll('.tl-shape-indicator')).toHaveLength(1)
255
+ // Check that all shape indicators are present
256
+ expect(document.querySelectorAll('.tl-shape-indicator').length).toBeGreaterThanOrEqual(
257
+ shapeTypesToTest.length
258
+ )
214
259
 
215
- // Select the shape
216
- await act(async () => editor.select(id))
260
+ // Select one of the shapes (the note shape)
261
+ const noteShapeId = shapeIds[9] // note is at index 9
262
+ await act(async () => editor.select(noteShapeId))
217
263
 
218
264
  expect(editor.getSelectedShapeIds().length).toBe(1)
219
- // though indicator it should be visible
220
- expect(document.querySelectorAll('.tl-shape-indicator')).toHaveLength(1)
265
+ expect(editor.getSelectedShapeIds()[0]).toBe(noteShapeId)
221
266
 
222
267
  // Select the eraser tool...
223
268
  await act(async () => editor.setCurrentTool('eraser'))
package/tldraw.css CHANGED
@@ -2315,12 +2315,10 @@ it from receiving any pointer events or affecting the cursor. */
2315
2315
  /* If mobile use 16px as font size */
2316
2316
  /* On iOS, font size under 16px in an input will make the page zoom into the input 🤦‍♂️ */
2317
2317
  /* https://css-tricks.com/16px-or-larger-text-prevents-ios-form-zoom/ */
2318
- @media (max-width: 600px) {
2319
- @supports (-webkit-touch-callout: none) {
2320
- /* CSS specific to iOS devices */
2321
- .tlui-input {
2322
- font-size: 16px;
2323
- }
2318
+ @supports (-webkit-touch-callout: none) {
2319
+ /* CSS specific to iOS devices */
2320
+ .tlui-input {
2321
+ font-size: 16px;
2324
2322
  }
2325
2323
  }
2326
2324