@tldraw/editor 3.14.0 → 3.14.2

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.
@@ -1,8 +1,8 @@
1
- const version = "3.14.0";
1
+ const version = "3.14.2";
2
2
  const publishDates = {
3
3
  major: "2024-09-13T14:36:29.063Z",
4
4
  minor: "2025-07-03T08:34:52.269Z",
5
- patch: "2025-07-03T08:34:52.269Z"
5
+ patch: "2025-07-10T09:54:52.889Z"
6
6
  };
7
7
  export {
8
8
  publishDates,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.0'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-07-03T08:34:52.269Z',\n\tpatch: '2025-07-03T08:34:52.269Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.2'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-07-03T08:34:52.269Z',\n\tpatch: '2025-07-10T09:54:52.889Z',\n}\n"],
5
5
  "mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tldraw/editor",
3
3
  "description": "A tiny little drawing app (editor).",
4
- "version": "3.14.0",
4
+ "version": "3.14.2",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -48,12 +48,12 @@
48
48
  "@tiptap/core": "^2.9.1",
49
49
  "@tiptap/pm": "^2.9.1",
50
50
  "@tiptap/react": "^2.9.1",
51
- "@tldraw/state": "3.14.0",
52
- "@tldraw/state-react": "3.14.0",
53
- "@tldraw/store": "3.14.0",
54
- "@tldraw/tlschema": "3.14.0",
55
- "@tldraw/utils": "3.14.0",
56
- "@tldraw/validate": "3.14.0",
51
+ "@tldraw/state": "3.14.2",
52
+ "@tldraw/state-react": "3.14.2",
53
+ "@tldraw/store": "3.14.2",
54
+ "@tldraw/tlschema": "3.14.2",
55
+ "@tldraw/utils": "3.14.2",
56
+ "@tldraw/validate": "3.14.2",
57
57
  "@types/core-js": "^2.5.8",
58
58
  "@use-gesture/react": "^10.3.1",
59
59
  "classnames": "^2.5.1",
package/src/index.ts CHANGED
@@ -18,27 +18,6 @@ export * from '@tldraw/utils'
18
18
  // eslint-disable-next-line local/no-export-star
19
19
  export * from '@tldraw/validate'
20
20
 
21
- export {
22
- ErrorScreen,
23
- LoadingScreen,
24
- TldrawEditor,
25
- useOnMount,
26
- type LoadingScreenProps,
27
- type TLOnMountHandler,
28
- type TldrawEditorBaseProps,
29
- type TldrawEditorProps,
30
- type TldrawEditorStoreProps,
31
- type TldrawEditorWithStoreProps,
32
- type TldrawEditorWithoutStoreProps,
33
- } from './lib/TldrawEditor'
34
- export {
35
- ErrorBoundary,
36
- OptionalErrorBoundary,
37
- type TLErrorBoundaryProps,
38
- } from './lib/components/ErrorBoundary'
39
- export { HTMLContainer, type HTMLContainerProps } from './lib/components/HTMLContainer'
40
- export { MenuClickCapture } from './lib/components/MenuClickCapture'
41
- export { SVGContainer, type SVGContainerProps } from './lib/components/SVGContainer'
42
21
  export { DefaultBackground } from './lib/components/default-components/DefaultBackground'
43
22
  export { DefaultBrush, type TLBrushProps } from './lib/components/default-components/DefaultBrush'
44
23
  export {
@@ -94,6 +73,26 @@ export {
94
73
  } from './lib/components/default-components/DefaultSnapIndictor'
95
74
  export { DefaultSpinner } from './lib/components/default-components/DefaultSpinner'
96
75
  export { DefaultSvgDefs } from './lib/components/default-components/DefaultSvgDefs'
76
+ export {
77
+ ErrorBoundary,
78
+ OptionalErrorBoundary,
79
+ type TLErrorBoundaryProps,
80
+ } from './lib/components/ErrorBoundary'
81
+ export { HTMLContainer, type HTMLContainerProps } from './lib/components/HTMLContainer'
82
+ export { MenuClickCapture } from './lib/components/MenuClickCapture'
83
+ export { SVGContainer, type SVGContainerProps } from './lib/components/SVGContainer'
84
+ export {
85
+ createTLSchemaFromUtils,
86
+ createTLStore,
87
+ inlineBase64AssetStore,
88
+ type TLStoreBaseOptions,
89
+ type TLStoreEventInfo,
90
+ type TLStoreOptions,
91
+ type TLStoreSchemaOptions,
92
+ } from './lib/config/createTLStore'
93
+ export { createTLUser, useTldrawUser, type TLUser } from './lib/config/createTLUser'
94
+ export { type TLAnyBindingUtilConstructor } from './lib/config/defaultBindings'
95
+ export { coreShapes, type TLAnyShapeUtilConstructor } from './lib/config/defaultShapes'
97
96
  export {
98
97
  getSnapshot,
99
98
  loadSnapshot,
@@ -101,42 +100,23 @@ export {
101
100
  type TLLoadSnapshotOptions,
102
101
  } from './lib/config/TLEditorSnapshot'
103
102
  export {
104
- TAB_ID,
105
103
  createSessionStateSnapshotSignal,
106
104
  extractSessionStateFromLegacySnapshot,
107
105
  loadSessionStateSnapshotIntoStore,
106
+ TAB_ID,
108
107
  type TLLoadSessionStateSnapshotOptions,
109
108
  type TLSessionStateSnapshot,
110
109
  } from './lib/config/TLSessionStateSnapshot'
111
110
  export {
112
- USER_COLORS,
113
111
  defaultUserPreferences,
114
112
  getFreshUserPreferences,
115
113
  getUserPreferences,
116
114
  setUserPreferences,
115
+ USER_COLORS,
117
116
  userTypeValidator,
118
117
  type TLUserPreferences,
119
118
  } from './lib/config/TLUserPreferences'
120
- export {
121
- createTLSchemaFromUtils,
122
- createTLStore,
123
- inlineBase64AssetStore,
124
- type TLStoreBaseOptions,
125
- type TLStoreEventInfo,
126
- type TLStoreOptions,
127
- type TLStoreSchemaOptions,
128
- } from './lib/config/createTLStore'
129
- export { createTLUser, useTldrawUser, type TLUser } from './lib/config/createTLUser'
130
- export { type TLAnyBindingUtilConstructor } from './lib/config/defaultBindings'
131
- export { coreShapes, type TLAnyShapeUtilConstructor } from './lib/config/defaultShapes'
132
119
  export { DEFAULT_ANIMATION_OPTIONS, DEFAULT_CAMERA_OPTIONS, SIDES } from './lib/constants'
133
- export {
134
- Editor,
135
- type TLEditorOptions,
136
- type TLEditorRunOptions,
137
- type TLRenderingShape,
138
- type TLResizeShapeOptions,
139
- } from './lib/editor/Editor'
140
120
  export {
141
121
  BindingUtil,
142
122
  type BindingOnChangeOptions,
@@ -147,6 +127,13 @@ export {
147
127
  type BindingOnShapeIsolateOptions,
148
128
  type TLBindingUtilConstructor,
149
129
  } from './lib/editor/bindings/BindingUtil'
130
+ export {
131
+ Editor,
132
+ type TLEditorOptions,
133
+ type TLEditorRunOptions,
134
+ type TLRenderingShape,
135
+ type TLResizeShapeOptions,
136
+ } from './lib/editor/Editor'
150
137
  export { ClickManager, type TLClickState } from './lib/editor/managers/ClickManager/ClickManager'
151
138
  export { EdgeScrollManager } from './lib/editor/managers/EdgeScrollManager/EdgeScrollManager'
152
139
  export {
@@ -179,6 +166,7 @@ export {
179
166
  } from './lib/editor/managers/TextManager/TextManager'
180
167
  export { UserPreferencesManager } from './lib/editor/managers/UserPreferencesManager/UserPreferencesManager'
181
168
  export { BaseBoxShapeUtil, type TLBaseBoxShape } from './lib/editor/shapes/BaseBoxShapeUtil'
169
+ export { GroupShapeUtil } from './lib/editor/shapes/group/GroupShapeUtil'
182
170
  export {
183
171
  ShapeUtil,
184
172
  type TLCropInfo,
@@ -195,7 +183,6 @@ export {
195
183
  type TLShapeUtilCanvasSvgDef,
196
184
  type TLShapeUtilConstructor,
197
185
  } from './lib/editor/shapes/ShapeUtil'
198
- export { GroupShapeUtil } from './lib/editor/shapes/group/GroupShapeUtil'
199
186
  export {
200
187
  getPerfectDashProps,
201
188
  type PerfectDashTerminal,
@@ -205,22 +192,16 @@ export { resizeScaled } from './lib/editor/shapes/shared/resizeScaled'
205
192
  export { BaseBoxShapeTool } from './lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool'
206
193
  export { maybeSnapToGrid } from './lib/editor/tools/BaseBoxShapeTool/children/Pointing'
207
194
  export { StateNode, type TLStateNodeConstructor } from './lib/editor/tools/StateNode'
208
- export {
209
- useDelaySvgExport,
210
- useSvgExportContext,
211
- type SvgExportContext,
212
- type SvgExportDef,
213
- } from './lib/editor/types/SvgExportContext'
214
195
  export { type TLContent } from './lib/editor/types/clipboard-types'
215
196
  export { type TLEventMap, type TLEventMapHandler } from './lib/editor/types/emit-types'
216
197
  export {
217
198
  EVENT_NAME_MAP,
218
199
  type TLBaseEventInfo,
219
- type TLCLickEventName,
220
200
  type TLCancelEvent,
221
201
  type TLCancelEventInfo,
222
202
  type TLClickEvent,
223
203
  type TLClickEventInfo,
204
+ type TLCLickEventName,
224
205
  type TLCompleteEvent,
225
206
  type TLCompleteEventInfo,
226
207
  type TLEnterEventHandler,
@@ -289,6 +270,12 @@ export {
289
270
  type TLResizeHandle,
290
271
  type TLSelectionHandle,
291
272
  } from './lib/editor/types/selection-types'
273
+ export {
274
+ useDelaySvgExport,
275
+ useSvgExportContext,
276
+ type SvgExportContext,
277
+ type SvgExportDef,
278
+ } from './lib/editor/types/SvgExportContext'
292
279
  export { getSvgAsImage } from './lib/exports/getSvgAsImage'
293
280
  export { tlenv } from './lib/globals/environment'
294
281
  export { tlmenus } from './lib/globals/menus'
@@ -346,8 +333,6 @@ export {
346
333
  type SelectionEdge,
347
334
  type SelectionHandle,
348
335
  } from './lib/primitives/Box'
349
- export { Mat, type MatLike, type MatModel } from './lib/primitives/Mat'
350
- export { Vec, type VecLike } from './lib/primitives/Vec'
351
336
  export { EASINGS } from './lib/primitives/easings'
352
337
  export { Arc2d } from './lib/primitives/geometry/Arc2d'
353
338
  export { Circle2d } from './lib/primitives/geometry/Circle2d'
@@ -382,11 +367,8 @@ export {
382
367
  polygonIntersectsPolyline,
383
368
  polygonsIntersect,
384
369
  } from './lib/primitives/intersect'
370
+ export { Mat, type MatLike, type MatModel } from './lib/primitives/Mat'
385
371
  export {
386
- HALF_PI,
387
- PI,
388
- PI2,
389
- SIN,
390
372
  angleDistance,
391
373
  approximately,
392
374
  areAnglesCompatible,
@@ -403,23 +385,36 @@ export {
403
385
  getPointOnCircle,
404
386
  getPointsOnArc,
405
387
  getPolygonVertices,
388
+ HALF_PI,
406
389
  isSafeFloat,
407
390
  perimeterOfEllipse,
391
+ PI,
392
+ PI2,
408
393
  pointInPolygon,
409
394
  precise,
410
395
  radiansToDegrees,
411
396
  rangeIntersection,
412
397
  shortAngleDist,
398
+ SIN,
413
399
  snapAngle,
414
400
  toDomPrecision,
415
401
  toFixed,
416
402
  toPrecision,
417
403
  } from './lib/primitives/utils'
404
+ export { Vec, type VecLike } from './lib/primitives/Vec'
418
405
  export {
419
- ReadonlySharedStyleMap,
420
- SharedStyleMap,
421
- type SharedStyle,
422
- } from './lib/utils/SharedStylesMap'
406
+ ErrorScreen,
407
+ LoadingScreen,
408
+ TldrawEditor,
409
+ useOnMount,
410
+ type LoadingScreenProps,
411
+ type TldrawEditorBaseProps,
412
+ type TldrawEditorProps,
413
+ type TldrawEditorStoreProps,
414
+ type TldrawEditorWithoutStoreProps,
415
+ type TldrawEditorWithStoreProps,
416
+ type TLOnMountHandler,
417
+ } from './lib/TldrawEditor'
423
418
  export { dataUrlToFile, getDefaultCdnBaseUrl } from './lib/utils/assets'
424
419
  export { clampToBrowserMaxCanvasSize, type CanvasMaxSize } from './lib/utils/browserCanvasMaxSize'
425
420
  export {
@@ -455,9 +450,9 @@ export {
455
450
  getFontsFromRichText,
456
451
  type RichTextFontVisitor,
457
452
  type RichTextFontVisitorState,
458
- type TLTextOptions,
459
453
  type TiptapEditor,
460
454
  type TiptapNode,
455
+ type TLTextOptions,
461
456
  } from './lib/utils/richText'
462
457
  export {
463
458
  applyRotationToSnapshotShapes,
@@ -465,9 +460,14 @@ export {
465
460
  type TLRotationSnapshot,
466
461
  } from './lib/utils/rotation'
467
462
  export { runtime, setRuntimeOverrides } from './lib/utils/runtime'
463
+ export {
464
+ ReadonlySharedStyleMap,
465
+ SharedStyleMap,
466
+ type SharedStyle,
467
+ } from './lib/utils/SharedStylesMap'
468
+ export { hardReset } from './lib/utils/sync/hardReset'
468
469
  export { LocalIndexedDb, Table, type StoreName } from './lib/utils/sync/LocalIndexedDb'
469
470
  export { type TLStoreWithStatus } from './lib/utils/sync/StoreWithStatus'
470
- export { hardReset } from './lib/utils/sync/hardReset'
471
471
  export { uniq } from './lib/utils/uniq'
472
472
  export { openWindow } from './lib/utils/window-open'
473
473
 
@@ -1,4 +1,5 @@
1
1
  import { BoxModel, TLDefaultHorizontalAlignStyle } from '@tldraw/tlschema'
2
+ import { objectMapKeys } from '@tldraw/utils'
2
3
  import { Editor } from '../../Editor'
3
4
 
4
5
  const fixNewLines = /\r?\n|\r/g
@@ -60,10 +61,18 @@ export interface TLMeasureTextSpanOpts {
60
61
 
61
62
  const spaceCharacterRegex = /\s/
62
63
 
64
+ const initialDefaultStyles = Object.freeze({
65
+ 'overflow-wrap': 'break-word',
66
+ 'word-break': 'auto',
67
+ width: null,
68
+ height: null,
69
+ 'max-width': null,
70
+ 'min-width': null,
71
+ })
72
+
63
73
  /** @public */
64
74
  export class TextManager {
65
75
  private elm: HTMLDivElement
66
- private defaultStyles: Record<string, string | null>
67
76
 
68
77
  constructor(public editor: Editor) {
69
78
  const elm = document.createElement('div')
@@ -73,31 +82,34 @@ export class TextManager {
73
82
  elm.tabIndex = -1
74
83
  this.editor.getContainer().appendChild(elm)
75
84
 
76
- // we need to save the default styles so that we can restore them when we're done
77
- // these must be the css names, not the js names for the styles
78
- this.defaultStyles = {
79
- 'overflow-wrap': 'break-word',
80
- 'word-break': 'auto',
81
- width: null,
82
- height: null,
83
- 'max-width': null,
84
- 'min-width': null,
85
+ this.elm = elm
86
+
87
+ for (const key of objectMapKeys(initialDefaultStyles)) {
88
+ elm.style.setProperty(key, initialDefaultStyles[key])
85
89
  }
90
+ }
86
91
 
87
- this.elm = elm
92
+ private setElementStyles(styles: Record<string, string | undefined>) {
93
+ const stylesToReinstate = {} as any
94
+ for (const key of objectMapKeys(styles)) {
95
+ if (typeof styles[key] === 'string') {
96
+ const oldValue = this.elm.style.getPropertyValue(key)
97
+ if (oldValue === styles[key]) continue
98
+ stylesToReinstate[key] = oldValue
99
+ this.elm.style.setProperty(key, styles[key])
100
+ }
101
+ }
102
+ return () => {
103
+ for (const key of objectMapKeys(stylesToReinstate)) {
104
+ this.elm.style.setProperty(key, stylesToReinstate[key])
105
+ }
106
+ }
88
107
  }
89
108
 
90
109
  dispose() {
91
110
  return this.elm.remove()
92
111
  }
93
112
 
94
- private resetElmStyles() {
95
- const { elm, defaultStyles } = this
96
- for (const key in defaultStyles) {
97
- elm.style.setProperty(key, defaultStyles[key])
98
- }
99
- }
100
-
101
113
  measureText(textToMeasure: string, opts: TLMeasureTextOpts): BoxModel & { scrollWidth: number } {
102
114
  const div = document.createElement('div')
103
115
  div.textContent = normalizeTextForDom(textToMeasure)
@@ -107,54 +119,36 @@ export class TextManager {
107
119
  measureHtml(html: string, opts: TLMeasureTextOpts): BoxModel & { scrollWidth: number } {
108
120
  const { elm } = this
109
121
 
110
- if (opts.otherStyles) {
111
- for (const key in opts.otherStyles) {
112
- if (!this.defaultStyles[key]) {
113
- // we need to save the original style so that we can restore it when we're done
114
- this.defaultStyles[key] = elm.style.getPropertyValue(key)
115
- }
116
- }
122
+ const newStyles = {
123
+ 'font-family': opts.fontFamily,
124
+ 'font-style': opts.fontStyle,
125
+ 'font-weight': opts.fontWeight,
126
+ 'font-size': opts.fontSize + 'px',
127
+ 'line-height': opts.lineHeight.toString(),
128
+ padding: opts.padding,
129
+ 'max-width': opts.maxWidth ? opts.maxWidth + 'px' : undefined,
130
+ 'min-width': opts.minWidth ? opts.minWidth + 'px' : undefined,
131
+ 'overflow-wrap': opts.disableOverflowWrapBreaking ? 'normal' : undefined,
132
+ ...opts.otherStyles,
117
133
  }
118
134
 
119
- elm.innerHTML = html
135
+ const restoreStyles = this.setElementStyles(newStyles)
120
136
 
121
- // Apply the default styles to the element (for all styles here or that were ever seen in opts.otherStyles)
122
- this.resetElmStyles()
137
+ try {
138
+ elm.innerHTML = html
123
139
 
124
- elm.style.setProperty('font-family', opts.fontFamily)
125
- elm.style.setProperty('font-style', opts.fontStyle)
126
- elm.style.setProperty('font-weight', opts.fontWeight)
127
- elm.style.setProperty('font-size', opts.fontSize + 'px')
128
- elm.style.setProperty('line-height', opts.lineHeight.toString())
129
- elm.style.setProperty('padding', opts.padding)
140
+ const scrollWidth = opts.measureScrollWidth ? elm.scrollWidth : 0
141
+ const rect = elm.getBoundingClientRect()
130
142
 
131
- if (opts.maxWidth) {
132
- elm.style.setProperty('max-width', opts.maxWidth + 'px')
133
- }
134
-
135
- if (opts.minWidth) {
136
- elm.style.setProperty('min-width', opts.minWidth + 'px')
137
- }
138
-
139
- if (opts.disableOverflowWrapBreaking) {
140
- elm.style.setProperty('overflow-wrap', 'normal')
141
- }
142
-
143
- if (opts.otherStyles) {
144
- for (const [key, value] of Object.entries(opts.otherStyles)) {
145
- elm.style.setProperty(key, value)
143
+ return {
144
+ x: 0,
145
+ y: 0,
146
+ w: rect.width,
147
+ h: rect.height,
148
+ scrollWidth,
146
149
  }
147
- }
148
-
149
- const scrollWidth = opts.measureScrollWidth ? elm.scrollWidth : 0
150
- const rect = elm.getBoundingClientRect()
151
-
152
- return {
153
- x: 0,
154
- y: 0,
155
- w: rect.width,
156
- h: rect.height,
157
- scrollWidth,
150
+ } finally {
151
+ restoreStyles()
158
152
  }
159
153
  }
160
154
 
@@ -274,82 +268,68 @@ export class TextManager {
274
268
 
275
269
  const { elm } = this
276
270
 
277
- if (opts.otherStyles) {
278
- for (const key in opts.otherStyles) {
279
- if (!this.defaultStyles[key]) {
280
- // we need to save the original style so that we can restore it when we're done
281
- this.defaultStyles[key] = elm.style.getPropertyValue(key)
282
- }
283
- }
284
- }
285
-
286
- this.resetElmStyles()
287
-
288
- elm.style.setProperty('font-family', opts.fontFamily)
289
- elm.style.setProperty('font-style', opts.fontStyle)
290
- elm.style.setProperty('font-weight', opts.fontWeight)
291
- elm.style.setProperty('font-size', opts.fontSize + 'px')
292
- elm.style.setProperty('line-height', opts.lineHeight.toString())
293
-
294
- const elementWidth = Math.ceil(opts.width - opts.padding * 2)
295
- elm.style.setProperty('width', `${elementWidth}px`)
296
- elm.style.setProperty('height', 'min-content')
297
- elm.style.setProperty('text-align', textAlignmentsForLtr[opts.textAlign])
298
-
299
271
  const shouldTruncateToFirstLine =
300
272
  opts.overflow === 'truncate-ellipsis' || opts.overflow === 'truncate-clip'
301
-
302
- if (shouldTruncateToFirstLine) {
303
- elm.style.setProperty('overflow-wrap', 'anywhere')
304
- elm.style.setProperty('word-break', 'break-all')
305
- }
306
-
307
- if (opts.otherStyles) {
308
- for (const [key, value] of Object.entries(opts.otherStyles)) {
309
- elm.style.setProperty(key, value)
310
- }
273
+ const elementWidth = Math.ceil(opts.width - opts.padding * 2)
274
+ const newStyles = {
275
+ 'font-family': opts.fontFamily,
276
+ 'font-style': opts.fontStyle,
277
+ 'font-weight': opts.fontWeight,
278
+ 'font-size': opts.fontSize + 'px',
279
+ 'line-height': opts.lineHeight.toString(),
280
+ width: `${elementWidth}px`,
281
+ height: 'min-content',
282
+ 'text-align': textAlignmentsForLtr[opts.textAlign],
283
+ 'overflow-wrap': shouldTruncateToFirstLine ? 'anywhere' : undefined,
284
+ 'word-break': shouldTruncateToFirstLine ? 'break-all' : undefined,
285
+ ...opts.otherStyles,
311
286
  }
287
+ const restoreStyles = this.setElementStyles(newStyles)
312
288
 
313
- const normalizedText = normalizeTextForDom(textToMeasure)
314
-
315
- // Render the text into the measurement element:
316
- elm.textContent = normalizedText
317
-
318
- // actually measure the text:
319
- const { spans, didTruncate } = this.measureElementTextNodeSpans(elm, {
320
- shouldTruncateToFirstLine,
321
- })
289
+ try {
290
+ const normalizedText = normalizeTextForDom(textToMeasure)
322
291
 
323
- if (opts.overflow === 'truncate-ellipsis' && didTruncate) {
324
- // we need to measure the ellipsis to know how much space it takes up
325
- elm.textContent = '…'
326
- const ellipsisWidth = Math.ceil(this.measureElementTextNodeSpans(elm).spans[0].box.w)
327
-
328
- // then, we need to subtract that space from the width we have and measure again:
329
- elm.style.setProperty('width', `${elementWidth - ellipsisWidth}px`)
292
+ // Render the text into the measurement element:
330
293
  elm.textContent = normalizedText
331
- const truncatedSpans = this.measureElementTextNodeSpans(elm, {
332
- shouldTruncateToFirstLine: true,
333
- }).spans
334
-
335
- // Finally, we add in our ellipsis at the end of the last span. We
336
- // have to do this after measuring, not before, because adding the
337
- // ellipsis changes how whitespace might be getting collapsed by the
338
- // browser.
339
- const lastSpan = truncatedSpans[truncatedSpans.length - 1]!
340
- truncatedSpans.push({
341
- text: '…',
342
- box: {
343
- x: Math.min(lastSpan.box.x + lastSpan.box.w, opts.width - opts.padding - ellipsisWidth),
344
- y: lastSpan.box.y,
345
- w: ellipsisWidth,
346
- h: lastSpan.box.h,
347
- },
294
+
295
+ // actually measure the text:
296
+ const { spans, didTruncate } = this.measureElementTextNodeSpans(elm, {
297
+ shouldTruncateToFirstLine,
348
298
  })
349
299
 
350
- return truncatedSpans
351
- }
300
+ if (opts.overflow === 'truncate-ellipsis' && didTruncate) {
301
+ // we need to measure the ellipsis to know how much space it takes up
302
+ elm.textContent = '…'
303
+ const ellipsisWidth = Math.ceil(this.measureElementTextNodeSpans(elm).spans[0].box.w)
304
+
305
+ // then, we need to subtract that space from the width we have and measure again:
306
+ elm.style.setProperty('width', `${elementWidth - ellipsisWidth}px`)
307
+ elm.textContent = normalizedText
308
+ const truncatedSpans = this.measureElementTextNodeSpans(elm, {
309
+ shouldTruncateToFirstLine: true,
310
+ }).spans
311
+
312
+ // Finally, we add in our ellipsis at the end of the last span. We
313
+ // have to do this after measuring, not before, because adding the
314
+ // ellipsis changes how whitespace might be getting collapsed by the
315
+ // browser.
316
+ const lastSpan = truncatedSpans[truncatedSpans.length - 1]!
317
+ truncatedSpans.push({
318
+ text: '…',
319
+ box: {
320
+ x: Math.min(lastSpan.box.x + lastSpan.box.w, opts.width - opts.padding - ellipsisWidth),
321
+ y: lastSpan.box.y,
322
+ w: ellipsisWidth,
323
+ h: lastSpan.box.h,
324
+ },
325
+ })
326
+
327
+ return truncatedSpans
328
+ }
352
329
 
353
- return spans
330
+ return spans
331
+ } finally {
332
+ restoreStyles()
333
+ }
354
334
  }
355
335
  }
@@ -417,7 +417,7 @@ function importPrivateKey(pemContents: string) {
417
417
  // base64 decode the string to get the binary data
418
418
  const binaryDerString = atob(pemContents)
419
419
  // convert from a binary string to an ArrayBuffer
420
- const binaryDer = str2ab(binaryDerString) as Uint8Array
420
+ const binaryDer = str2ab(binaryDerString)
421
421
 
422
422
  return crypto.subtle.importKey(
423
423
  'pkcs8',
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.14.0'
4
+ export const version = '3.14.2'
5
5
  export const publishDates = {
6
6
  major: '2024-09-13T14:36:29.063Z',
7
7
  minor: '2025-07-03T08:34:52.269Z',
8
- patch: '2025-07-03T08:34:52.269Z',
8
+ patch: '2025-07-10T09:54:52.889Z',
9
9
  }