@tldraw/editor 3.8.0-canary.c5d6281c3fdd → 3.8.0-canary.c738f8c4d6db

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 (66) hide show
  1. package/dist-cjs/index.d.ts +114 -56
  2. package/dist-cjs/index.js +9 -8
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/config/TLSessionStateSnapshot.js.map +2 -2
  5. package/dist-cjs/lib/editor/Editor.js +6 -3
  6. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  7. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +2 -2
  8. package/dist-cjs/lib/editor/managers/TextManager.js +1 -0
  9. package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
  10. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +13 -0
  11. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  13. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  14. package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
  15. package/dist-cjs/lib/hooks/useCanvasEvents.js +19 -8
  16. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  17. package/dist-cjs/lib/hooks/useDocumentEvents.js +1 -3
  18. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  19. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +4 -0
  20. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +3 -3
  21. package/dist-cjs/lib/options.js +1 -2
  22. package/dist-cjs/lib/options.js.map +2 -2
  23. package/dist-cjs/lib/utils/dom.js +6 -0
  24. package/dist-cjs/lib/utils/dom.js.map +2 -2
  25. package/dist-cjs/version.js +3 -3
  26. package/dist-cjs/version.js.map +1 -1
  27. package/dist-esm/index.d.mts +114 -56
  28. package/dist-esm/index.mjs +3 -1
  29. package/dist-esm/index.mjs.map +2 -2
  30. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs.map +2 -2
  31. package/dist-esm/lib/editor/Editor.mjs +6 -3
  32. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  33. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +2 -2
  34. package/dist-esm/lib/editor/managers/TextManager.mjs +1 -0
  35. package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
  36. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +13 -0
  37. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  38. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
  39. package/dist-esm/lib/hooks/useCanvasEvents.mjs +19 -8
  40. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  41. package/dist-esm/lib/hooks/useDocumentEvents.mjs +2 -4
  42. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  43. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +4 -0
  44. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +3 -3
  45. package/dist-esm/lib/options.mjs +1 -2
  46. package/dist-esm/lib/options.mjs.map +2 -2
  47. package/dist-esm/lib/utils/dom.mjs +6 -0
  48. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  49. package/dist-esm/version.mjs +3 -3
  50. package/dist-esm/version.mjs.map +1 -1
  51. package/package.json +20 -20
  52. package/src/index.ts +16 -1
  53. package/src/lib/config/TLSessionStateSnapshot.ts +3 -1
  54. package/src/lib/editor/Editor.ts +22 -20
  55. package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +4 -4
  56. package/src/lib/editor/managers/TextManager.ts +1 -0
  57. package/src/lib/editor/shapes/ShapeUtil.ts +19 -0
  58. package/src/lib/editor/types/emit-types.ts +1 -0
  59. package/src/lib/editor/types/external-content.ts +104 -50
  60. package/src/lib/exports/StyleEmbedder.ts +1 -1
  61. package/src/lib/hooks/useCanvasEvents.ts +20 -8
  62. package/src/lib/hooks/useDocumentEvents.ts +2 -11
  63. package/src/lib/hooks/usePassThroughWheelEvents.ts +7 -0
  64. package/src/lib/options.ts +3 -6
  65. package/src/lib/utils/dom.ts +12 -0
  66. package/src/version.ts +3 -3
@@ -155,7 +155,7 @@ import {
155
155
  TLPointerEventInfo,
156
156
  TLWheelEventInfo,
157
157
  } from './types/event-types'
158
- import { TLExternalAssetContent, TLExternalContent } from './types/external-content'
158
+ import { TLExternalAsset, TLExternalContent } from './types/external-content'
159
159
  import { TLHistoryBatchOptions } from './types/history-types'
160
160
  import {
161
161
  OptionalKeys,
@@ -1400,8 +1400,8 @@ export class Editor extends EventEmitter<TLEventMap> {
1400
1400
  *
1401
1401
  * @example
1402
1402
  * ```ts
1403
- * state.getStateDescendant('select')
1404
- * state.getStateDescendant('select.brushing')
1403
+ * editor.getStateDescendant('select')
1404
+ * editor.getStateDescendant('select.brushing')
1405
1405
  * ```
1406
1406
  *
1407
1407
  * @param path - The descendant's path of state ids, separated by periods.
@@ -1681,7 +1681,7 @@ export class Editor extends EventEmitter<TLEventMap> {
1681
1681
  * @public
1682
1682
  */
1683
1683
  isAncestorSelected(shape: TLShape | TLShapeId): boolean {
1684
- const id = typeof shape === 'string' ? shape : shape?.id ?? null
1684
+ const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
1685
1685
  const _shape = this.getShape(id)
1686
1686
  if (!_shape) return false
1687
1687
  const selectedShapeIds = this.getSelectedShapeIds()
@@ -1938,7 +1938,7 @@ export class Editor extends EventEmitter<TLEventMap> {
1938
1938
  * @public
1939
1939
  */
1940
1940
  setFocusedGroup(shape: TLShapeId | TLGroupShape | null): this {
1941
- const id = typeof shape === 'string' ? shape : shape?.id ?? null
1941
+ const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
1942
1942
 
1943
1943
  if (id !== null) {
1944
1944
  const shape = this.getShape(id)
@@ -2021,7 +2021,7 @@ export class Editor extends EventEmitter<TLEventMap> {
2021
2021
  * @public
2022
2022
  */
2023
2023
  setEditingShape(shape: TLShapeId | TLShape | null): this {
2024
- const id = typeof shape === 'string' ? shape : shape?.id ?? null
2024
+ const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
2025
2025
  if (id !== this.getEditingShapeId()) {
2026
2026
  if (id) {
2027
2027
  const shape = this.getShape(id)
@@ -2082,7 +2082,7 @@ export class Editor extends EventEmitter<TLEventMap> {
2082
2082
  * @public
2083
2083
  */
2084
2084
  setHoveredShape(shape: TLShapeId | TLShape | null): this {
2085
- const id = typeof shape === 'string' ? shape : shape?.id ?? null
2085
+ const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
2086
2086
  if (id === this.getHoveredShapeId()) return this
2087
2087
  this.run(
2088
2088
  () => {
@@ -2231,7 +2231,7 @@ export class Editor extends EventEmitter<TLEventMap> {
2231
2231
  * @public
2232
2232
  */
2233
2233
  setCroppingShape(shape: TLShapeId | TLShape | null): this {
2234
- const id = typeof shape === 'string' ? shape : shape?.id ?? null
2234
+ const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
2235
2235
  if (id !== this.getCroppingShapeId()) {
2236
2236
  this.run(
2237
2237
  () => {
@@ -7975,10 +7975,8 @@ export class Editor extends EventEmitter<TLEventMap> {
7975
7975
 
7976
7976
  /** @internal */
7977
7977
  externalAssetContentHandlers: {
7978
- [K in TLExternalAssetContent['type']]: {
7979
- [Key in K]:
7980
- | null
7981
- | ((info: TLExternalAssetContent & { type: Key }) => Promise<TLAsset | undefined>)
7978
+ [K in TLExternalAsset['type']]: {
7979
+ [Key in K]: null | ((info: TLExternalAsset & { type: Key }) => Promise<TLAsset | undefined>)
7982
7980
  }[K]
7983
7981
  } = {
7984
7982
  file: null,
@@ -8007,9 +8005,9 @@ export class Editor extends EventEmitter<TLEventMap> {
8007
8005
  *
8008
8006
  * @public
8009
8007
  */
8010
- registerExternalAssetHandler<T extends TLExternalAssetContent['type']>(
8008
+ registerExternalAssetHandler<T extends TLExternalAsset['type']>(
8011
8009
  type: T,
8012
- handler: null | ((info: TLExternalAssetContent & { type: T }) => Promise<TLAsset>)
8010
+ handler: null | ((info: TLExternalAsset & { type: T }) => Promise<TLAsset>)
8013
8011
  ): this {
8014
8012
  this.externalAssetContentHandlers[type] = handler as any
8015
8013
  return this
@@ -8077,18 +8075,18 @@ export class Editor extends EventEmitter<TLEventMap> {
8077
8075
  * @param info - Info about the external content.
8078
8076
  * @returns The asset.
8079
8077
  */
8080
- async getAssetForExternalContent(info: TLExternalAssetContent): Promise<TLAsset | undefined> {
8078
+ async getAssetForExternalContent(info: TLExternalAsset): Promise<TLAsset | undefined> {
8081
8079
  return await this.externalAssetContentHandlers[info.type]?.(info as any)
8082
8080
  }
8083
8081
 
8084
- hasExternalAssetHandler(type: TLExternalAssetContent['type']): boolean {
8082
+ hasExternalAssetHandler(type: TLExternalAsset['type']): boolean {
8085
8083
  return !!this.externalAssetContentHandlers[type]
8086
8084
  }
8087
8085
 
8088
8086
  /** @internal */
8089
8087
  externalContentHandlers: {
8090
8088
  [K in TLExternalContent<any>['type']]: {
8091
- [Key in K]: null | ((info: TLExternalContent<any> & { type: Key }) => void)
8089
+ [Key in K]: null | ((info: Extract<TLExternalContent<any>, { type: Key }>) => void)
8092
8090
  }[K]
8093
8091
  } = {
8094
8092
  text: null,
@@ -8096,6 +8094,8 @@ export class Editor extends EventEmitter<TLEventMap> {
8096
8094
  embed: null,
8097
8095
  'svg-text': null,
8098
8096
  url: null,
8097
+ tldraw: null,
8098
+ excalidraw: null,
8099
8099
  }
8100
8100
 
8101
8101
  /**
@@ -8123,7 +8123,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8123
8123
  | null
8124
8124
  | ((
8125
8125
  info: T extends TLExternalContent<E>['type']
8126
- ? TLExternalContent<E> & { type: T }
8126
+ ? Extract<TLExternalContent<E>, { type: T }>
8127
8127
  : TLExternalContent<E>
8128
8128
  ) => void)
8129
8129
  ): this {
@@ -8803,8 +8803,8 @@ export class Editor extends EventEmitter<TLEventMap> {
8803
8803
  // If our pointer moved only because we're following some other user, then don't
8804
8804
  // update our last activity timestamp; otherwise, update it to the current timestamp.
8805
8805
  info.type === 'pointer' && info.pointerId === INTERNAL_POINTER_IDS.CAMERA_MOVE
8806
- ? this.store.unsafeGetWithoutCapture(TLPOINTER_ID)?.lastActivityTimestamp ??
8807
- this._tickManager.now
8806
+ ? (this.store.unsafeGetWithoutCapture(TLPOINTER_ID)?.lastActivityTimestamp ??
8807
+ this._tickManager.now)
8808
8808
  : this._tickManager.now,
8809
8809
  meta: {},
8810
8810
  },
@@ -9369,6 +9369,8 @@ export class Editor extends EventEmitter<TLEventMap> {
9369
9369
  // todo: replace with new readonly mode?
9370
9370
  if (this.getCrashingError()) return this
9371
9371
 
9372
+ this.emit('before-event', info)
9373
+
9372
9374
  const { inputs } = this
9373
9375
  const { type } = info
9374
9376
 
@@ -390,8 +390,8 @@ export class BoundsSnaps {
390
390
 
391
391
  // at the same time, calculate how far we need to nudge the shape to 'snap' to the target point(s)
392
392
  const nudge = new Vec(
393
- lockedAxis === 'x' ? 0 : nearestSnapsX[0]?.nudge ?? 0,
394
- lockedAxis === 'y' ? 0 : nearestSnapsY[0]?.nudge ?? 0
393
+ lockedAxis === 'x' ? 0 : (nearestSnapsX[0]?.nudge ?? 0),
394
+ lockedAxis === 'y' ? 0 : (nearestSnapsY[0]?.nudge ?? 0)
395
395
  )
396
396
 
397
397
  // ok we've figured out how much the box should be nudged, now let's find all the snap points
@@ -504,8 +504,8 @@ export class BoundsSnaps {
504
504
 
505
505
  // at the same time, calculate how far we need to nudge the shape to 'snap' to the target point(s)
506
506
  const nudge = new Vec(
507
- isXLocked ? 0 : nearestSnapsX[0]?.nudge ?? 0,
508
- isYLocked ? 0 : nearestSnapsY[0]?.nudge ?? 0
507
+ isXLocked ? 0 : (nearestSnapsX[0]?.nudge ?? 0),
508
+ isYLocked ? 0 : (nearestSnapsY[0]?.nudge ?? 0)
509
509
  )
510
510
 
511
511
  if (isAspectRatioLocked && isSelectionCorner(handle) && nudge.len() !== 0) {
@@ -230,6 +230,7 @@ export class TextManager {
230
230
  elm.style.setProperty('font-weight', opts.fontWeight)
231
231
  elm.style.setProperty('line-height', `${opts.lineHeight * opts.fontSize}px`)
232
232
  elm.style.setProperty('text-align', textAlignmentsForLtr[opts.textAlign])
233
+ elm.style.setProperty('font-style', opts.fontStyle)
233
234
 
234
235
  const shouldTruncateToFirstLine =
235
236
  opts.overflow === 'truncate-ellipsis' || opts.overflow === 'truncate-clip'
@@ -53,8 +53,27 @@ export interface TLShapeUtilCanvasSvgDef {
53
53
 
54
54
  /** @public */
55
55
  export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
56
+ /** Configure this shape utils {@link ShapeUtil.options | `options`}. */
57
+ static configure<T extends TLShapeUtilConstructor<any, any>>(
58
+ this: T,
59
+ options: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never
60
+ ): T {
61
+ // @ts-expect-error -- typescript has no idea what's going on here but it's fine
62
+ return class extends this {
63
+ // @ts-expect-error
64
+ options = { ...this.options, ...options }
65
+ }
66
+ }
67
+
56
68
  constructor(public editor: Editor) {}
57
69
 
70
+ /**
71
+ * Options for this shape util. If you're implementing a custom shape util, you can override
72
+ * this to provide customization options for your shape. If using an existing shape util, you
73
+ * can customizing this by calling {@link ShapeUtil.configure}.
74
+ */
75
+ options = {}
76
+
58
77
  /**
59
78
  * Props allow you to define the shape's properties in a way that the editor can understand.
60
79
  * This has two main uses:
@@ -12,6 +12,7 @@ export interface TLEventMap {
12
12
  crash: [{ error: unknown }]
13
13
  'stop-camera-animation': []
14
14
  'stop-following': []
15
+ 'before-event': [TLEventInfo]
15
16
  event: [TLEventInfo]
16
17
  tick: [number]
17
18
  frame: [number]
@@ -2,57 +2,111 @@ import { TLAssetId } from '@tldraw/tlschema'
2
2
  import { VecLike } from '../../primitives/Vec'
3
3
  import { TLContent } from './clipboard-types'
4
4
 
5
+ /** @public */
6
+ export interface TLTldrawExternalContentSource {
7
+ type: 'tldraw'
8
+ data: TLContent
9
+ }
10
+
11
+ /** @public */
12
+ export interface TLExcalidrawExternalContentSource {
13
+ type: 'excalidraw'
14
+ data: any
15
+ }
16
+
17
+ /** @public */
18
+ export interface TLTextExternalContentSource {
19
+ type: 'text'
20
+ data: string
21
+ subtype: 'json' | 'html' | 'text' | 'url'
22
+ }
23
+
24
+ /** @public */
25
+ export interface TLErrorExternalContentSource {
26
+ type: 'error'
27
+ data: string | null
28
+ reason: string
29
+ }
30
+
5
31
  /** @public */
6
32
  export type TLExternalContentSource =
7
- | {
8
- type: 'tldraw'
9
- data: TLContent
10
- }
11
- | {
12
- type: 'excalidraw'
13
- data: any
14
- }
15
- | {
16
- type: 'text'
17
- data: string
18
- subtype: 'json' | 'html' | 'text' | 'url'
19
- }
20
- | {
21
- type: 'error'
22
- data: string | null
23
- reason: string
24
- }
25
-
26
- /** @public */
27
- export type TLExternalContent<EmbedDefinition> = {
33
+ | TLTldrawExternalContentSource
34
+ | TLExcalidrawExternalContentSource
35
+ | TLTextExternalContentSource
36
+ | TLErrorExternalContentSource
37
+
38
+ /** @public */
39
+ export interface TLBaseExternalContent {
28
40
  sources?: TLExternalContentSource[]
29
41
  point?: VecLike
30
- } & (
31
- | {
32
- type: 'text'
33
- text: string
34
- }
35
- | {
36
- type: 'files'
37
- files: File[]
38
- ignoreParent: boolean
39
- }
40
- | {
41
- type: 'url'
42
- url: string
43
- }
44
- | {
45
- type: 'svg-text'
46
- text: string
47
- }
48
- | {
49
- type: 'embed'
50
- url: string
51
- embed: EmbedDefinition
52
- }
53
- )
54
-
55
- /** @public */
56
- export type TLExternalAssetContent =
57
- | { type: 'file'; file: File; assetId?: TLAssetId }
58
- | { type: 'url'; url: string }
42
+ }
43
+
44
+ /** @public */
45
+ export interface TLTextExternalContent extends TLBaseExternalContent {
46
+ type: 'text'
47
+ text: string
48
+ }
49
+
50
+ /** @public */
51
+ export interface TLFilesExternalContent extends TLBaseExternalContent {
52
+ type: 'files'
53
+ files: File[]
54
+ ignoreParent: boolean
55
+ }
56
+
57
+ /** @public */
58
+ export interface TLUrlExternalContent extends TLBaseExternalContent {
59
+ type: 'url'
60
+ url: string
61
+ }
62
+
63
+ /** @public */
64
+ export interface TLSvgTextExternalContent extends TLBaseExternalContent {
65
+ type: 'svg-text'
66
+ text: string
67
+ }
68
+
69
+ /** @public */
70
+ export interface TLEmbedExternalContent<EmbedDefinition> extends TLBaseExternalContent {
71
+ type: 'embed'
72
+ url: string
73
+ embed: EmbedDefinition
74
+ }
75
+
76
+ /** @public */
77
+ export interface TLTldrawExternalContent extends TLBaseExternalContent {
78
+ type: 'tldraw'
79
+ content: TLContent
80
+ }
81
+
82
+ /** @public */
83
+ export interface TLExcalidrawExternalContent extends TLBaseExternalContent {
84
+ type: 'excalidraw'
85
+ content: any
86
+ }
87
+
88
+ /** @public */
89
+ export type TLExternalContent<EmbedDefinition> =
90
+ | TLTextExternalContent
91
+ | TLFilesExternalContent
92
+ | TLUrlExternalContent
93
+ | TLSvgTextExternalContent
94
+ | TLEmbedExternalContent<EmbedDefinition>
95
+ | TLTldrawExternalContent
96
+ | TLExcalidrawExternalContent
97
+
98
+ /** @public */
99
+ export interface TLFileExternalAsset {
100
+ type: 'file'
101
+ file: File
102
+ assetId?: TLAssetId
103
+ }
104
+
105
+ /** @public */
106
+ export interface TLUrlExternalAsset {
107
+ type: 'url'
108
+ url: string
109
+ }
110
+
111
+ /** @public */
112
+ export type TLExternalAsset = TLFileExternalAsset | TLUrlExternalAsset
@@ -54,7 +54,7 @@ export class StyleEmbedder {
54
54
  : NO_STYLES
55
55
 
56
56
  const parentStyles = shouldSkipInheritedParentStyles
57
- ? this.styles.get(element.parentElement as Element)?.self ?? NO_STYLES
57
+ ? (this.styles.get(element.parentElement as Element)?.self ?? NO_STYLES)
58
58
  : NO_STYLES
59
59
 
60
60
  const info: ElementStyleInfo = {
@@ -117,16 +117,28 @@ export function useCanvasEvents() {
117
117
  async function onDrop(e: React.DragEvent<Element>) {
118
118
  preventDefault(e)
119
119
  stopEventPropagation(e)
120
- if (!e.dataTransfer?.files?.length) return
121
120
 
122
- const files = Array.from(e.dataTransfer.files)
121
+ if (e.dataTransfer?.files?.length) {
122
+ const files = Array.from(e.dataTransfer.files)
123
123
 
124
- await editor.putExternalContent({
125
- type: 'files',
126
- files,
127
- point: editor.screenToPage({ x: e.clientX, y: e.clientY }),
128
- ignoreParent: false,
129
- })
124
+ await editor.putExternalContent({
125
+ type: 'files',
126
+ files,
127
+ point: editor.screenToPage({ x: e.clientX, y: e.clientY }),
128
+ ignoreParent: false,
129
+ })
130
+ return
131
+ }
132
+
133
+ const url = e.dataTransfer.getData('url')
134
+ if (url) {
135
+ await editor.putExternalContent({
136
+ type: 'url',
137
+ url,
138
+ point: editor.screenToPage({ x: e.clientX, y: e.clientY }),
139
+ })
140
+ return
141
+ }
130
142
  }
131
143
 
132
144
  function onClick(e: React.MouseEvent) {
@@ -2,7 +2,7 @@ import { useValue } from '@tldraw/state-react'
2
2
  import { useEffect } from 'react'
3
3
  import { Editor } from '../editor/Editor'
4
4
  import { TLKeyboardEventInfo } from '../editor/types/event-types'
5
- import { preventDefault, stopEventPropagation } from '../utils/dom'
5
+ import { activeElementShouldCaptureKeys, preventDefault, stopEventPropagation } from '../utils/dom'
6
6
  import { isAccelKey } from '../utils/keyboard'
7
7
  import { useContainer } from './useContainer'
8
8
  import { useEditor } from './useEditor'
@@ -274,15 +274,6 @@ export function useDocumentEvents() {
274
274
  }, [editor, container, isAppFocused])
275
275
  }
276
276
 
277
- const INPUTS = ['input', 'select', 'button', 'textarea']
278
-
279
277
  function areShortcutsDisabled(editor: Editor) {
280
- const { activeElement } = document
281
-
282
- return (
283
- editor.menus.hasOpenMenus() ||
284
- (activeElement &&
285
- (activeElement.getAttribute('contenteditable') ||
286
- INPUTS.indexOf(activeElement.tagName.toLowerCase()) > -1))
287
- )
278
+ return editor.menus.hasOpenMenus() || activeElementShouldCaptureKeys()
288
279
  }
@@ -11,6 +11,13 @@ export function usePassThroughWheelEvents(ref: RefObject<HTMLElement>) {
11
11
  useEffect(() => {
12
12
  function onWheel(e: WheelEvent) {
13
13
  if ((e as any).isSpecialRedispatchedEvent) return
14
+
15
+ // if the element is scrollable, don't redispatch the event
16
+ const elm = ref.current
17
+ if (elm && elm.scrollHeight > elm.clientHeight) {
18
+ return
19
+ }
20
+
14
21
  preventDefault(e)
15
22
  const cvs = container.querySelector('.tl-canvas')
16
23
  if (!cvs) return
@@ -29,7 +29,6 @@ export interface TldrawOptions {
29
29
  readonly dragDistanceSquared: number
30
30
  readonly defaultSvgPadding: number
31
31
  readonly cameraSlideFriction: number
32
- readonly maxPointsPerDrawShape: number
33
32
  readonly gridSteps: readonly {
34
33
  readonly min: number
35
34
  readonly mid: number
@@ -67,10 +66,9 @@ export interface TldrawOptions {
67
66
  */
68
67
  readonly exportProvider: ComponentType<{ children: React.ReactNode }>
69
68
  /**
70
- * How should the note shape resize? By default it does not resize (except automatically based on its text content),
71
- * but you can set it to be user-resizable using scale.
69
+ * By default, the toolbar items are accessible via number shortcuts according to their order. To disable this, set this option to false.
72
70
  */
73
- readonly noteShapeResizeMode: 'none' | 'scale'
71
+ readonly enableToolbarKeyboardShortcuts: boolean
74
72
  }
75
73
 
76
74
  /** @public */
@@ -86,7 +84,6 @@ export const defaultTldrawOptions = {
86
84
  dragDistanceSquared: 16, // 4 squared
87
85
  defaultSvgPadding: 32,
88
86
  cameraSlideFriction: 0.09,
89
- maxPointsPerDrawShape: 500,
90
87
  gridSteps: [
91
88
  { min: -1, mid: 0.15, step: 64 },
92
89
  { min: 0.05, mid: 0.375, step: 16 },
@@ -116,5 +113,5 @@ export const defaultTldrawOptions = {
116
113
  actionShortcutsLocation: 'swap',
117
114
  createTextOnCanvasDoubleClick: true,
118
115
  exportProvider: Fragment,
119
- noteShapeResizeMode: 'none',
116
+ enableToolbarKeyboardShortcuts: true,
120
117
  } as const satisfies TldrawOptions
@@ -90,3 +90,15 @@ export const setStyleProperty = (
90
90
  if (!elm) return
91
91
  elm.style.setProperty(property, value as string)
92
92
  }
93
+
94
+ const INPUTS = ['input', 'select', 'button', 'textarea']
95
+
96
+ /** @internal */
97
+ export function activeElementShouldCaptureKeys() {
98
+ const { activeElement } = document
99
+ return !!(
100
+ activeElement &&
101
+ (activeElement.getAttribute('contenteditable') ||
102
+ INPUTS.indexOf(activeElement.tagName.toLowerCase()) > -1)
103
+ )
104
+ }
package/src/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.8.0-canary.c5d6281c3fdd'
4
+ export const version = '3.8.0-canary.c738f8c4d6db'
5
5
  export const publishDates = {
6
6
  major: '2024-09-13T14:36:29.063Z',
7
- minor: '2025-01-28T16:50:53.939Z',
8
- patch: '2025-01-28T16:50:53.939Z',
7
+ minor: '2025-02-12T15:13:37.538Z',
8
+ patch: '2025-02-12T15:13:37.538Z',
9
9
  }