@tldraw/editor 3.16.0-canary.6074088f67bd → 3.16.0-canary.62bc202550a3

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 (64) hide show
  1. package/dist-cjs/index.d.ts +5 -101
  2. package/dist-cjs/index.js +1 -5
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +0 -4
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/editor/Editor.js +3 -99
  7. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  8. package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
  9. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +4 -1
  10. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
  11. package/dist-cjs/lib/license/LicenseManager.js +17 -22
  12. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  13. package/dist-cjs/lib/license/LicenseProvider.js +5 -0
  14. package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
  15. package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
  16. package/dist-cjs/lib/primitives/Vec.js +0 -4
  17. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  18. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +26 -18
  19. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  20. package/dist-cjs/lib/primitives/geometry/Group2d.js +3 -0
  21. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  22. package/dist-cjs/lib/utils/reparenting.js +2 -35
  23. package/dist-cjs/lib/utils/reparenting.js.map +3 -3
  24. package/dist-cjs/version.js +3 -3
  25. package/dist-cjs/version.js.map +1 -1
  26. package/dist-esm/index.d.mts +5 -101
  27. package/dist-esm/index.mjs +1 -5
  28. package/dist-esm/index.mjs.map +2 -2
  29. package/dist-esm/lib/TldrawEditor.mjs +0 -4
  30. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  31. package/dist-esm/lib/editor/Editor.mjs +3 -99
  32. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  33. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +4 -1
  34. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
  35. package/dist-esm/lib/license/LicenseManager.mjs +17 -22
  36. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  37. package/dist-esm/lib/license/LicenseProvider.mjs +5 -0
  38. package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
  39. package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
  40. package/dist-esm/lib/primitives/Vec.mjs +0 -4
  41. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  42. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +29 -19
  43. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  44. package/dist-esm/lib/primitives/geometry/Group2d.mjs +3 -0
  45. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  46. package/dist-esm/lib/utils/reparenting.mjs +3 -40
  47. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  48. package/dist-esm/version.mjs +3 -3
  49. package/dist-esm/version.mjs.map +1 -1
  50. package/package.json +7 -7
  51. package/src/index.ts +1 -9
  52. package/src/lib/TldrawEditor.tsx +0 -11
  53. package/src/lib/editor/Editor.ts +1 -125
  54. package/src/lib/editor/types/misc-types.ts +0 -6
  55. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +4 -1
  56. package/src/lib/license/LicenseManager.test.ts +58 -51
  57. package/src/lib/license/LicenseManager.ts +32 -24
  58. package/src/lib/license/LicenseProvider.tsx +8 -0
  59. package/src/lib/license/useLicenseManagerState.ts +2 -2
  60. package/src/lib/primitives/Vec.ts +0 -5
  61. package/src/lib/primitives/geometry/Geometry2d.ts +49 -19
  62. package/src/lib/primitives/geometry/Group2d.ts +4 -0
  63. package/src/lib/utils/reparenting.ts +3 -69
  64. package/src/version.ts +3 -3
@@ -4,7 +4,7 @@ import { publishDates } from '../../version'
4
4
  import { str2ab } from '../utils/licensing'
5
5
  import {
6
6
  FLAGS,
7
- isEditorUnlicensed,
7
+ getLicenseState,
8
8
  LicenseManager,
9
9
  PROPERTIES,
10
10
  ValidLicenseKeyResult,
@@ -487,115 +487,122 @@ function getDefaultLicenseResult(overrides: Partial<ValidLicenseKeyResult>): Val
487
487
  }
488
488
  }
489
489
 
490
- describe(isEditorUnlicensed, () => {
491
- it('shows watermark when license is not parseable', () => {
490
+ describe('getLicenseState', () => {
491
+ it('returns "unlicensed" for unparseable license', () => {
492
492
  const licenseResult = getDefaultLicenseResult({
493
493
  // @ts-ignore
494
494
  isLicenseParseable: false,
495
495
  })
496
- expect(isEditorUnlicensed(licenseResult)).toBe(true)
496
+ expect(getLicenseState(licenseResult)).toBe('unlicensed')
497
497
  })
498
498
 
499
- it('shows watermark when domain is not valid', () => {
499
+ it('returns "unlicensed" for invalid domain in production', () => {
500
500
  const licenseResult = getDefaultLicenseResult({
501
501
  isDomainValid: false,
502
+ isDevelopment: false,
502
503
  })
503
- expect(isEditorUnlicensed(licenseResult)).toBe(true)
504
+ expect(getLicenseState(licenseResult)).toBe('unlicensed')
504
505
  })
505
506
 
506
- it('shows watermark when annual license has expired', () => {
507
+ it('returns "licensed" for invalid domain in development mode', () => {
508
+ const licenseResult = getDefaultLicenseResult({
509
+ isDomainValid: false,
510
+ isDevelopment: true,
511
+ })
512
+ expect(getLicenseState(licenseResult)).toBe('licensed')
513
+ })
514
+
515
+ it('returns "unlicensed" for expired annual license', () => {
507
516
  const licenseResult = getDefaultLicenseResult({
508
517
  isAnnualLicense: true,
509
518
  isAnnualLicenseExpired: true,
519
+ isInternalLicense: false,
510
520
  })
511
- expect(isEditorUnlicensed(licenseResult)).toBe(true)
521
+ expect(getLicenseState(licenseResult)).toBe('unlicensed')
512
522
  })
513
523
 
514
- it('shows watermark when annual license has expired, even if dev mode', () => {
524
+ it('returns "unlicensed" for expired annual license even in dev mode', () => {
515
525
  const licenseResult = getDefaultLicenseResult({
516
526
  isAnnualLicense: true,
517
527
  isAnnualLicenseExpired: true,
518
528
  isDevelopment: true,
529
+ isInternalLicense: false,
519
530
  })
520
- expect(isEditorUnlicensed(licenseResult)).toBe(true)
531
+ expect(getLicenseState(licenseResult)).toBe('unlicensed')
521
532
  })
522
533
 
523
- it('shows watermark when perpetual license has expired', () => {
534
+ it('returns "unlicensed" for expired perpetual license', () => {
524
535
  const licenseResult = getDefaultLicenseResult({
525
536
  isPerpetualLicense: true,
526
537
  isPerpetualLicenseExpired: true,
538
+ isInternalLicense: false,
527
539
  })
528
- expect(isEditorUnlicensed(licenseResult)).toBe(true)
540
+ expect(getLicenseState(licenseResult)).toBe('unlicensed')
529
541
  })
530
542
 
531
- it('does not show watermark when license is valid and not expired', () => {
543
+ it('returns "internal-expired" for expired internal annual license with valid domain', () => {
544
+ const expiryDate = new Date(2023, 1, 1)
532
545
  const licenseResult = getDefaultLicenseResult({
533
546
  isAnnualLicense: true,
534
- isAnnualLicenseExpired: false,
535
- isInternalLicense: false,
547
+ isAnnualLicenseExpired: true,
548
+ isInternalLicense: true,
549
+ isDomainValid: true,
550
+ expiryDate,
536
551
  })
537
- expect(isEditorUnlicensed(licenseResult)).toBe(false)
552
+ expect(getLicenseState(licenseResult)).toBe('internal-expired')
538
553
  })
539
554
 
540
- it('does not show watermark when perpetual license is valid and not expired', () => {
555
+ it('returns "internal-expired" for expired internal perpetual license with valid domain', () => {
556
+ const expiryDate = new Date(2023, 1, 1)
541
557
  const licenseResult = getDefaultLicenseResult({
542
558
  isPerpetualLicense: true,
543
- isPerpetualLicenseExpired: false,
544
- isInternalLicense: false,
545
- })
546
- expect(isEditorUnlicensed(licenseResult)).toBe(false)
547
- })
548
-
549
- it('does not show watermark when in development mode', () => {
550
- const licenseResult = getDefaultLicenseResult({
551
- isDevelopment: true,
559
+ isPerpetualLicenseExpired: true,
560
+ isInternalLicense: true,
561
+ isDomainValid: true,
562
+ expiryDate,
552
563
  })
553
- expect(isEditorUnlicensed(licenseResult)).toBe(false)
564
+ expect(getLicenseState(licenseResult)).toBe('internal-expired')
554
565
  })
555
566
 
556
- it('does not show watermark when license is parseable and domain is valid', () => {
567
+ it('returns "unlicensed" for expired internal license with invalid domain', () => {
568
+ const expiryDate = new Date(2023, 1, 1)
557
569
  const licenseResult = getDefaultLicenseResult({
558
- isLicenseParseable: true,
559
- isDomainValid: true,
570
+ isAnnualLicense: true,
571
+ isAnnualLicenseExpired: true,
572
+ isInternalLicense: true,
573
+ isDomainValid: false,
574
+ expiryDate,
560
575
  })
561
- expect(isEditorUnlicensed(licenseResult)).toBe(false)
576
+ expect(getLicenseState(licenseResult)).toBe('unlicensed')
562
577
  })
563
578
 
564
- it('does not show watermark when license is parseable and domain is not valid and dev mode', () => {
579
+ it('returns "licensed-with-watermark" for watermarked license', () => {
565
580
  const licenseResult = getDefaultLicenseResult({
566
- isLicenseParseable: true,
567
- isDomainValid: false,
568
- isDevelopment: true,
581
+ isLicensedWithWatermark: true,
569
582
  })
570
- expect(isEditorUnlicensed(licenseResult)).toBe(false)
583
+ expect(getLicenseState(licenseResult)).toBe('licensed-with-watermark')
571
584
  })
572
585
 
573
- it('throws when an internal annual license has expired', () => {
574
- const expiryDate = new Date(2023, 1, 1)
586
+ it('returns "licensed" for valid annual license', () => {
575
587
  const licenseResult = getDefaultLicenseResult({
576
588
  isAnnualLicense: true,
577
- isAnnualLicenseExpired: true,
578
- isInternalLicense: true,
579
- expiryDate,
589
+ isAnnualLicenseExpired: false,
580
590
  })
581
- expect(() => isEditorUnlicensed(licenseResult)).toThrow(/License: Internal license expired/)
591
+ expect(getLicenseState(licenseResult)).toBe('licensed')
582
592
  })
583
593
 
584
- it('throws when an internal perpetual license has expired', () => {
585
- const expiryDate = new Date(2023, 1, 1)
594
+ it('returns "licensed" for valid perpetual license', () => {
586
595
  const licenseResult = getDefaultLicenseResult({
587
596
  isPerpetualLicense: true,
588
- isPerpetualLicenseExpired: true,
589
- isInternalLicense: true,
590
- expiryDate,
597
+ isPerpetualLicenseExpired: false,
591
598
  })
592
- expect(() => isEditorUnlicensed(licenseResult)).toThrow(/License: Internal license expired/)
599
+ expect(getLicenseState(licenseResult)).toBe('licensed')
593
600
  })
594
601
 
595
- it('shows watermark when license has that flag specified', () => {
602
+ it('returns "licensed" for valid license in development mode', () => {
596
603
  const licenseResult = getDefaultLicenseResult({
597
- isLicensedWithWatermark: true,
604
+ isDevelopment: true,
598
605
  })
599
- expect(isEditorUnlicensed(licenseResult)).toBe(false)
606
+ expect(getLicenseState(licenseResult)).toBe('licensed')
600
607
  })
601
608
  })
@@ -33,6 +33,14 @@ export interface LicenseInfo {
33
33
  flags: number
34
34
  expiryDate: string
35
35
  }
36
+
37
+ /** @internal */
38
+ export type LicenseState =
39
+ | 'pending'
40
+ | 'licensed'
41
+ | 'licensed-with-watermark'
42
+ | 'unlicensed'
43
+ | 'internal-expired'
36
44
  /** @internal */
37
45
  export type InvalidLicenseReason =
38
46
  | 'invalid-license-key'
@@ -73,10 +81,7 @@ export class LicenseManager {
73
81
  public isDevelopment: boolean
74
82
  public isTest: boolean
75
83
  public isCryptoAvailable: boolean
76
- state = atom<'pending' | 'licensed' | 'licensed-with-watermark' | 'unlicensed'>(
77
- 'license state',
78
- 'pending'
79
- )
84
+ state = atom<LicenseState>('license state', 'pending')
80
85
  public verbose = true
81
86
 
82
87
  constructor(
@@ -89,21 +94,20 @@ export class LicenseManager {
89
94
  this.publicKey = testPublicKey || this.publicKey
90
95
  this.isCryptoAvailable = !!crypto.subtle
91
96
 
92
- this.getLicenseFromKey(licenseKey).then((result) => {
93
- const isUnlicensed = isEditorUnlicensed(result)
97
+ this.getLicenseFromKey(licenseKey)
98
+ .then((result) => {
99
+ const licenseState = getLicenseState(result)
94
100
 
95
- if (!this.isDevelopment && isUnlicensed) {
96
- fetch(WATERMARK_TRACK_SRC)
97
- }
101
+ if (!this.isDevelopment && licenseState === 'unlicensed') {
102
+ fetch(WATERMARK_TRACK_SRC)
103
+ }
98
104
 
99
- if (isUnlicensed) {
105
+ this.state.set(licenseState)
106
+ })
107
+ .catch((error) => {
108
+ console.error('License validation failed:', error)
100
109
  this.state.set('unlicensed')
101
- } else if ((result as ValidLicenseKeyResult).isLicensedWithWatermark) {
102
- this.state.set('licensed-with-watermark')
103
- } else {
104
- this.state.set('licensed')
105
- }
106
- })
110
+ })
107
111
  }
108
112
 
109
113
  private getIsDevelopment(testEnvironment?: TestEnvironment) {
@@ -367,15 +371,19 @@ export class LicenseManager {
367
371
  static className = 'tl-watermark_SEE-LICENSE'
368
372
  }
369
373
 
370
- export function isEditorUnlicensed(result: LicenseFromKeyResult) {
371
- if (!result.isLicenseParseable) return true
372
- if (!result.isDomainValid && !result.isDevelopment) return true
374
+ export function getLicenseState(result: LicenseFromKeyResult): LicenseState {
375
+ if (!result.isLicenseParseable) return 'unlicensed'
376
+ if (!result.isDomainValid && !result.isDevelopment) return 'unlicensed'
373
377
  if (result.isPerpetualLicenseExpired || result.isAnnualLicenseExpired) {
374
- if (result.isInternalLicense) {
375
- throw new Error('License: Internal license expired.')
376
- }
377
- return true
378
+ // Check if it's an expired internal license with valid domain
379
+ const internalExpired = result.isInternalLicense && result.isDomainValid
380
+ return internalExpired ? 'internal-expired' : 'unlicensed'
381
+ }
382
+
383
+ // License is valid, determine if it has watermark
384
+ if (result.isLicensedWithWatermark) {
385
+ return 'licensed-with-watermark'
378
386
  }
379
387
 
380
- return false
388
+ return 'licensed'
381
389
  }
@@ -1,3 +1,4 @@
1
+ import { useValue } from '@tldraw/state-react'
1
2
  import { createContext, ReactNode, useContext, useState } from 'react'
2
3
  import { LicenseManager } from './LicenseManager'
3
4
 
@@ -16,5 +17,12 @@ export function LicenseProvider({
16
17
  children: ReactNode
17
18
  }) {
18
19
  const [licenseManager] = useState(() => new LicenseManager(licenseKey))
20
+ const licenseState = useValue(licenseManager.state)
21
+
22
+ // If internal license has expired, don't render the editor at all
23
+ if (licenseState === 'internal-expired') {
24
+ return <div data-testid="tl-license-expired" style={{ display: 'none' }} />
25
+ }
26
+
19
27
  return <LicenseContext.Provider value={licenseManager}>{children}</LicenseContext.Provider>
20
28
  }
@@ -1,7 +1,7 @@
1
1
  import { useValue } from '@tldraw/state-react'
2
- import { LicenseManager } from './LicenseManager'
2
+ import { LicenseManager, LicenseState } from './LicenseManager'
3
3
 
4
4
  /** @internal */
5
- export function useLicenseManagerState(licenseManager: LicenseManager) {
5
+ export function useLicenseManagerState(licenseManager: LicenseManager): LicenseState {
6
6
  return useValue('watermarkState', () => licenseManager.state.get(), [licenseManager])
7
7
  }
@@ -240,11 +240,6 @@ export class Vec {
240
240
  return Vec.EqualsXY(this, x, y)
241
241
  }
242
242
 
243
- /** @deprecated use `uni` instead */
244
- norm() {
245
- return this.uni()
246
- }
247
-
248
243
  toFixed() {
249
244
  this.x = toFixed(this.x)
250
245
  this.y = toFixed(this.y)
@@ -9,6 +9,8 @@ import {
9
9
  intersectLineSegmentPolyline,
10
10
  intersectPolys,
11
11
  linesIntersect,
12
+ polygonIntersectsPolyline,
13
+ polygonsIntersect,
12
14
  } from '../intersect'
13
15
  import { approximately, pointInPolygon } from '../utils'
14
16
 
@@ -227,25 +229,6 @@ export abstract class Geometry2d {
227
229
  return distanceAlongRoute / length
228
230
  }
229
231
 
230
- /** @deprecated Iterate the vertices instead. */
231
- nearestPointOnLineSegment(A: VecLike, B: VecLike): Vec {
232
- const { vertices } = this
233
- let nearest: Vec | undefined
234
- let dist = Infinity
235
- let d: number, p: Vec, q: Vec
236
- for (let i = 0; i < vertices.length; i++) {
237
- p = vertices[i]
238
- q = Vec.NearestPointOnLineSegment(A, B, p, true)
239
- d = Vec.Dist2(p, q)
240
- if (d < dist) {
241
- dist = d
242
- nearest = q
243
- }
244
- }
245
- if (!nearest) throw Error('nearest point not found')
246
- return nearest
247
- }
248
-
249
232
  isPointInBounds(point: VecLike, margin = 0) {
250
233
  const { bounds } = this
251
234
  return !(
@@ -256,6 +239,53 @@ export abstract class Geometry2d {
256
239
  )
257
240
  }
258
241
 
242
+ overlapsPolygon(_polygon: VecLike[]): boolean {
243
+ const polygon = _polygon.map((v) => Vec.From(v))
244
+
245
+ // Otherwise, check if the geometry itself overlaps the polygon
246
+ const { vertices, center, isFilled, isEmptyLabel, isClosed } = this
247
+
248
+ // We'll do things in order of cheapest to most expensive checks
249
+
250
+ // Skip empty labels
251
+ if (isEmptyLabel) return false
252
+
253
+ // If any of the geometry's vertices are inside the polygon, it's inside
254
+ if (vertices.some((v) => pointInPolygon(v, polygon))) {
255
+ return true
256
+ }
257
+
258
+ // If the geometry is filled and closed and its center is inside the polygon, it's inside
259
+ if (isClosed) {
260
+ if (isFilled) {
261
+ // If closed and filled, check if the center is inside the polygon
262
+ if (pointInPolygon(center, polygon)) {
263
+ return true
264
+ }
265
+
266
+ // ..then, slightly more expensive check, see the geometry covers the entire polygon but not its center
267
+ if (polygon.every((v) => pointInPolygon(v, vertices))) {
268
+ return true
269
+ }
270
+ }
271
+
272
+ // If any the geometry's vertices intersect the edge of the polygon, it's inside.
273
+ // for example when a rotated rectangle is moved over the corner of a parent rectangle
274
+ // If the geometry is closed, intersect as a polygon
275
+ if (polygonsIntersect(polygon, vertices)) {
276
+ return true
277
+ }
278
+ } else {
279
+ // If the geometry is not closed, intersect as a polyline
280
+ if (polygonIntersectsPolyline(polygon, vertices)) {
281
+ return true
282
+ }
283
+ }
284
+
285
+ // If none of the above checks passed, the geometry is outside the polygon
286
+ return false
287
+ }
288
+
259
289
  transform(transform: MatModel, opts?: TransformedGeometry2dOptions): Geometry2d {
260
290
  return new TransformedGeometry2d(this, transform, opts)
261
291
  }
@@ -236,4 +236,8 @@ export class Group2d extends Geometry2d {
236
236
  getSvgPathData(): string {
237
237
  return this.children.map((c, i) => (c.isLabel ? '' : c.getSvgPathData(i === 0))).join(' ')
238
238
  }
239
+
240
+ overlapsPolygon(polygon: VecLike[]): boolean {
241
+ return this.children.some((child) => child.overlapsPolygon(polygon))
242
+ }
239
243
  }
@@ -2,15 +2,7 @@ import { EMPTY_ARRAY } from '@tldraw/state'
2
2
  import { TLGroupShape, TLParentId, TLShape, TLShapeId } from '@tldraw/tlschema'
3
3
  import { IndexKey, compact, getIndexAbove, getIndexBetween } from '@tldraw/utils'
4
4
  import { Editor } from '../editor/Editor'
5
- import { Vec } from '../primitives/Vec'
6
- import { Geometry2d } from '../primitives/geometry/Geometry2d'
7
- import { Group2d } from '../primitives/geometry/Group2d'
8
- import {
9
- intersectPolygonPolygon,
10
- polygonIntersectsPolyline,
11
- polygonsIntersect,
12
- } from '../primitives/intersect'
13
- import { pointInPolygon } from '../primitives/utils'
5
+ import { intersectPolygonPolygon } from '../primitives/intersect'
14
6
 
15
7
  /**
16
8
  * Reparents shapes that are no longer contained within their parent shapes.
@@ -189,68 +181,10 @@ function getOverlappingShapes<T extends TLShape[] | TLShapeId[]>(
189
181
 
190
182
  const geometry = editor.getShapeGeometry(childId)
191
183
 
192
- return doesGeometryOverlapPolygon(geometry, parentPolygonInShapeShape)
184
+ return geometry.overlapsPolygon(parentPolygonInShapeShape)
193
185
  })
194
186
  }
195
187
 
196
- /**
197
- * @public
198
- */
199
- export function doesGeometryOverlapPolygon(
200
- geometry: Geometry2d,
201
- parentCornersInShapeSpace: Vec[]
202
- ): boolean {
203
- // If the child is a group, check if any of its children overlap the box
204
- if (geometry instanceof Group2d) {
205
- return geometry.children.some((childGeometry) =>
206
- doesGeometryOverlapPolygon(childGeometry, parentCornersInShapeSpace)
207
- )
208
- }
209
-
210
- // Otherwise, check if the geometry overlaps the box
211
- const { vertices, center, isFilled, isEmptyLabel, isClosed } = geometry
212
-
213
- // We'll do things in order of cheapest to most expensive checks
214
-
215
- // Skip empty labels
216
- if (isEmptyLabel) return false
217
-
218
- // If any of the shape's vertices are inside the occluder, it's inside
219
- if (vertices.some((v) => pointInPolygon(v, parentCornersInShapeSpace))) {
220
- return true
221
- }
222
-
223
- // If the shape is filled and closed and its center is inside the parent, it's inside
224
- if (isClosed) {
225
- if (isFilled) {
226
- // If closed and filled, check if the center is inside the parent
227
- if (pointInPolygon(center, parentCornersInShapeSpace)) {
228
- return true
229
- }
230
-
231
- // ..then, slightly more expensive check, see the shape covers the entire parent but not its center
232
- if (parentCornersInShapeSpace.every((v) => pointInPolygon(v, vertices))) {
233
- return true
234
- }
235
- }
236
-
237
- // If any the shape's vertices intersect the edge of the occluder, it's inside.
238
- // for example when a rotated rectangle is moved over the corner of a parent rectangle
239
- // If the child shape is closed, intersect as a polygon
240
- if (polygonsIntersect(parentCornersInShapeSpace, vertices)) {
241
- return true
242
- }
243
- } else {
244
- // if the child shape is not closed, intersect as a polyline
245
- if (polygonIntersectsPolyline(parentCornersInShapeSpace, vertices)) {
246
- return true
247
- }
248
- }
249
-
250
- // If none of the above checks passed, the shape is outside the parent
251
- return false
252
- }
253
-
254
188
  /**
255
189
  * Get the shapes that will be reparented to new parents when the shapes are dropped.
256
190
  *
@@ -354,7 +288,7 @@ export function getDroppedShapesToNewParents(
354
288
  .applyToPoints(parentPagePolygon)
355
289
 
356
290
  // If the shape overlaps the parent polygon, reparent it to that parent
357
- if (doesGeometryOverlapPolygon(editor.getShapeGeometry(shape), parentPolygonInShapeSpace)) {
291
+ if (editor.getShapeGeometry(shape).overlapsPolygon(parentPolygonInShapeSpace)) {
358
292
  // Use the util to check if the shape can be reparented to the parent
359
293
  if (
360
294
  !editor.getShapeUtil(parentShape).canReceiveNewChildrenOfType?.(parentShape, shape.type)
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.16.0-canary.6074088f67bd'
4
+ export const version = '3.16.0-canary.62bc202550a3'
5
5
  export const publishDates = {
6
6
  major: '2024-09-13T14:36:29.063Z',
7
- minor: '2025-08-28T08:54:13.475Z',
8
- patch: '2025-08-28T08:54:13.475Z',
7
+ minor: '2025-09-03T09:39:32.548Z',
8
+ patch: '2025-09-03T09:39:32.548Z',
9
9
  }