@excalidraw/excalidraw 0.17.1-7441-c5548cc → 0.17.1-7441-0269e5a

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 (142) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/dist/browser/excalidraw-assets/{ar-SA-O4ZYAXHV.js → ar-SA-ZG4GMNKR.js} +1 -1
  3. package/dist/browser/excalidraw-assets/{az-AZ-RBGCVZSU.js → az-AZ-5QPIG4ZE.js} +1 -1
  4. package/dist/browser/excalidraw-assets/{bg-BG-27JU7ZTW.js → bg-BG-GWMMOXVZ.js} +1 -1
  5. package/dist/browser/excalidraw-assets/{bn-BD-YI5COLVX.js → bn-BD-FFLR3TNM.js} +1 -1
  6. package/dist/browser/excalidraw-assets/{c4Diagram-9cddb37f-M7FQCEGJ.js → c4Diagram-9cddb37f-DT3MBRIQ.js} +4 -4
  7. package/dist/browser/excalidraw-assets/{ca-ES-OT3NLCX2.js → ca-ES-7TTPSWTV.js} +1 -1
  8. package/dist/browser/excalidraw-assets/{chunk-Y73ZIZF2.js → chunk-2H6Q3UHB.js} +21 -21
  9. package/dist/browser/excalidraw-assets/{chunk-I7D3YGSV.js → chunk-5XVKPBR4.js} +1 -1
  10. package/dist/browser/excalidraw-assets/{chunk-EC7D42UC.js → chunk-67KWAPOR.js} +4 -4
  11. package/dist/browser/excalidraw-assets/{chunk-VFCK2VL6.js → chunk-AZELGDJ7.js} +3 -3
  12. package/dist/browser/excalidraw-assets/{chunk-KBSJWTUC.js → chunk-E67NG25X.js} +3 -3
  13. package/dist/browser/excalidraw-assets/{chunk-VJ4TJS2Y.js → chunk-ED7FCLMV.js} +3 -3
  14. package/dist/browser/excalidraw-assets/{chunk-YS3YHKSV.js → chunk-HG4GCABW.js} +7 -0
  15. package/dist/browser/excalidraw-assets/{chunk-PZKJ4HUG.js → chunk-K5VM6ZHC.js} +6 -6
  16. package/dist/browser/excalidraw-assets/{chunk-4RBOPRHV.js → chunk-L5BPE74O.js} +2 -2
  17. package/dist/browser/excalidraw-assets/{chunk-AB4DRNTX.js → chunk-OJAFOQ6I.js} +5 -5
  18. package/dist/browser/excalidraw-assets/{chunk-NUFRJSGA.js → chunk-RFZOXM2P.js} +3 -3
  19. package/dist/browser/excalidraw-assets/{chunk-Q5V3XSEB.js → chunk-T7PKCJTJ.js} +13 -1
  20. package/dist/browser/excalidraw-assets/{chunk-RRTDSCW5.js → chunk-UZYJGJH5.js} +2 -2
  21. package/dist/browser/excalidraw-assets/{chunk-C3WE7537.js → chunk-V52YQ6TH.js} +600 -172
  22. package/dist/browser/excalidraw-assets/{chunk-OBSLEQVG.js → chunk-YCSAT77X.js} +2 -2
  23. package/dist/browser/excalidraw-assets/{chunk-MDHEUGIE.js → chunk-YVMHRGYC.js} +2 -2
  24. package/dist/browser/excalidraw-assets/{classDiagram-bc733c3b-ILLIUUCV.js → classDiagram-bc733c3b-ADGQD5FE.js} +7 -7
  25. package/dist/browser/excalidraw-assets/{classDiagram-v2-8931bdaf-U7JETC6T.js → classDiagram-v2-8931bdaf-LQUNAO5F.js} +10 -10
  26. package/dist/browser/excalidraw-assets/{cs-CZ-VWNS2EBL.js → cs-CZ-ZBCV22AJ.js} +1 -1
  27. package/dist/browser/excalidraw-assets/{da-DK-ZSZISCYL.js → da-DK-Q4T27BFS.js} +1 -1
  28. package/dist/browser/excalidraw-assets/{de-DE-NGG5BQQU.js → de-DE-MBK4JIXX.js} +1 -1
  29. package/dist/browser/excalidraw-assets/{directory-open-01563666-OUEPAD2B.js → directory-open-01563666-XGWD52SG.js} +2 -2
  30. package/dist/browser/excalidraw-assets/{directory-open-4ed118d0-3YEXHCYQ.js → directory-open-4ed118d0-CW2C2TU4.js} +2 -2
  31. package/dist/browser/excalidraw-assets/{dist-YSQXM7F6.js → dist-GMU63VF7.js} +3 -3
  32. package/dist/browser/excalidraw-assets/{el-GR-WZRPRHPI.js → el-GR-4IO54FJG.js} +1 -1
  33. package/dist/browser/excalidraw-assets/{en-Y3Y5PHTH.js → en-6HNFHSKB.js} +4 -2
  34. package/dist/browser/excalidraw-assets/{erDiagram-f6946109-MARB7LUI.js → erDiagram-f6946109-LOZPUYNA.js} +5 -5
  35. package/dist/browser/excalidraw-assets/{es-ES-J4OESQ2T.js → es-ES-RTNHOKI6.js} +1 -1
  36. package/dist/browser/excalidraw-assets/{eu-ES-JIOSKIEU.js → eu-ES-IPUNFIRV.js} +1 -1
  37. package/dist/browser/excalidraw-assets/{fa-IR-KEVEW3J2.js → fa-IR-AFOLD64G.js} +1 -1
  38. package/dist/browser/excalidraw-assets/{fi-FI-VHWIPZNU.js → fi-FI-YDIGP7ED.js} +1 -1
  39. package/dist/browser/excalidraw-assets/{file-open-002ab408-YC7KQ7M7.js → file-open-002ab408-XIZJR36E.js} +2 -2
  40. package/dist/browser/excalidraw-assets/{file-open-7c801643-GRK3M4FM.js → file-open-7c801643-YIZPMU4W.js} +2 -2
  41. package/dist/browser/excalidraw-assets/{file-save-3189631c-XOSH6LGE.js → file-save-3189631c-BQMBD5TV.js} +2 -2
  42. package/dist/browser/excalidraw-assets/{file-save-745eba88-HT2N2RA6.js → file-save-745eba88-MWPDJIMB.js} +2 -2
  43. package/dist/browser/excalidraw-assets/{flowDiagram-93327f21-QAR7MBV2.js → flowDiagram-93327f21-IG42SU5S.js} +11 -11
  44. package/dist/browser/excalidraw-assets/{flowDiagram-v2-476db779-NRWK544J.js → flowDiagram-v2-476db779-Y67G2FM7.js} +11 -11
  45. package/dist/browser/excalidraw-assets/{flowchart-elk-definition-5082a990-YKT6KRH3.js → flowchart-elk-definition-5082a990-N6NGIBWD.js} +8 -8
  46. package/dist/browser/excalidraw-assets/{fr-FR-6IOJIJYL.js → fr-FR-DKTDAJMV.js} +1 -1
  47. package/dist/browser/excalidraw-assets/{ganttDiagram-7ce12d6b-TETXDXSS.js → ganttDiagram-7ce12d6b-QM7W7H3I.js} +3 -3
  48. package/dist/browser/excalidraw-assets/{gitGraphDiagram-1e960c50-KJ53NSM2.js → gitGraphDiagram-1e960c50-EKEGNJUG.js} +3 -3
  49. package/dist/browser/excalidraw-assets/{gl-ES-GLS3MPGJ.js → gl-ES-KAW5CTCB.js} +1 -1
  50. package/dist/browser/excalidraw-assets/{he-IL-PES5HNTH.js → he-IL-XFQ6PZWN.js} +1 -1
  51. package/dist/browser/excalidraw-assets/{hi-IN-KJ5CDJGW.js → hi-IN-CJGZ2R72.js} +1 -1
  52. package/dist/browser/excalidraw-assets/{hu-HU-Y4JXQDS4.js → hu-HU-LH67LOY3.js} +1 -1
  53. package/dist/browser/excalidraw-assets/{id-ID-DA5FA6OL.js → id-ID-L6Y7PWWN.js} +1 -1
  54. package/dist/browser/excalidraw-assets/{image-TP5JGDPK.css → image-2MHILQWB.css} +193 -2
  55. package/dist/browser/excalidraw-assets/{image-DBNYVO3T.js → image-MZHH7VY4.js} +4 -4
  56. package/dist/browser/excalidraw-assets/{image-blob-reduce.esm-EBROP3TW.js → image-blob-reduce.esm-5RGBO4BD.js} +2 -2
  57. package/dist/browser/excalidraw-assets/{infoDiagram-264bed3e-EX4AYPQQ.js → infoDiagram-264bed3e-DGYH27DL.js} +3 -3
  58. package/dist/browser/excalidraw-assets/{it-IT-BNXL4CYY.js → it-IT-NYW7ZXIC.js} +1 -1
  59. package/dist/browser/excalidraw-assets/{ja-JP-MNWVRFQD.js → ja-JP-PTAJBPX4.js} +1 -1
  60. package/dist/browser/excalidraw-assets/{journeyDiagram-31be0096-Y6RLBNJ4.js → journeyDiagram-31be0096-MOV4SXUQ.js} +4 -4
  61. package/dist/browser/excalidraw-assets/{kaa-MGHZRJX2.js → kaa-WXJRXWPF.js} +1 -1
  62. package/dist/browser/excalidraw-assets/{kab-KAB-JIMEPM6B.js → kab-KAB-ODUQXY6X.js} +1 -1
  63. package/dist/browser/excalidraw-assets/{kk-KZ-34LQGHKY.js → kk-KZ-UXGGFOE5.js} +1 -1
  64. package/dist/browser/excalidraw-assets/{km-KH-ASWPZXSX.js → km-KH-KH42MBCX.js} +1 -1
  65. package/dist/browser/excalidraw-assets/{ko-KR-TSJPRBBT.js → ko-KR-OK4WMN6E.js} +1 -1
  66. package/dist/browser/excalidraw-assets/{ku-TR-PNP7OOUH.js → ku-TR-I6JF7FTE.js} +1 -1
  67. package/dist/browser/excalidraw-assets/{lt-LT-OYI4CUPY.js → lt-LT-MRDJ3W6M.js} +1 -1
  68. package/dist/browser/excalidraw-assets/{lv-LV-UIBLRKLP.js → lv-LV-GUHKIRYT.js} +1 -1
  69. package/dist/browser/excalidraw-assets/{mindmap-definition-4fc2557c-BODO5LN7.js → mindmap-definition-4fc2557c-QD6CUNYL.js} +4 -4
  70. package/dist/browser/excalidraw-assets/{mr-IN-L2APYGBG.js → mr-IN-2VY5ATS4.js} +1 -1
  71. package/dist/browser/excalidraw-assets/{my-MM-75U3VCOE.js → my-MM-Q3UE7NDU.js} +1 -1
  72. package/dist/browser/excalidraw-assets/{nb-NO-NM6ZQSU6.js → nb-NO-YGVSWPTU.js} +1 -1
  73. package/dist/browser/excalidraw-assets/{nl-NL-D6PK3GH3.js → nl-NL-JYQZFVD6.js} +1 -1
  74. package/dist/browser/excalidraw-assets/{nn-NO-BNIHWH3L.js → nn-NO-SVCTK45S.js} +1 -1
  75. package/dist/browser/excalidraw-assets/{oc-FR-LCRUD5LT.js → oc-FR-7S4GZ53C.js} +1 -1
  76. package/dist/browser/excalidraw-assets/{pa-IN-STXLKWNM.js → pa-IN-OAXG5ILZ.js} +1 -1
  77. package/dist/browser/excalidraw-assets/{percentages-7OAWRSFY.js → percentages-G7XJNZNY.js} +1 -1
  78. package/dist/browser/excalidraw-assets/{pica-UY2E6YV3.js → pica-3M7LI2AU.js} +2 -2
  79. package/dist/browser/excalidraw-assets/{pieDiagram-157505fe-TR3EKKEP.js → pieDiagram-157505fe-THFWR2W3.js} +3 -3
  80. package/dist/browser/excalidraw-assets/{pl-PL-3XM5C6BE.js → pl-PL-4LOCCO6A.js} +1 -1
  81. package/dist/browser/excalidraw-assets/{pt-BR-PCB5M6Q5.js → pt-BR-UE7QKZT7.js} +1 -1
  82. package/dist/browser/excalidraw-assets/{pt-PT-JKKOIWOA.js → pt-PT-QRYXWDEQ.js} +1 -1
  83. package/dist/browser/excalidraw-assets/{quadrantDiagram-fd70f2d0-II72YD6R.js → quadrantDiagram-fd70f2d0-PM7WE6V7.js} +3 -3
  84. package/dist/browser/excalidraw-assets/{requirementDiagram-19c99588-KQYIFNAJ.js → requirementDiagram-19c99588-VQ7AQGMD.js} +5 -5
  85. package/dist/browser/excalidraw-assets/{ro-RO-CRH2KIPB.js → ro-RO-S6UM3GTE.js} +1 -1
  86. package/dist/browser/excalidraw-assets/{ru-RU-QBGPUX6G.js → ru-RU-X3LZJ2PM.js} +1 -1
  87. package/dist/browser/excalidraw-assets/{sequenceDiagram-5dfd0049-25L3RXZD.js → sequenceDiagram-5dfd0049-7VLXNLQB.js} +4 -4
  88. package/dist/browser/excalidraw-assets/{si-LK-3SZOS2BL.js → si-LK-47EZ7CDR.js} +1 -1
  89. package/dist/browser/excalidraw-assets/{sk-SK-J3IRFPPI.js → sk-SK-BZTESEQ3.js} +1 -1
  90. package/dist/browser/excalidraw-assets/{sl-SI-XMEM4DG7.js → sl-SI-UKPT7XYH.js} +1 -1
  91. package/dist/browser/excalidraw-assets/{stateDiagram-133e3642-BOXZPPAP.js → stateDiagram-133e3642-TFVBMKD2.js} +6 -6
  92. package/dist/browser/excalidraw-assets/{stateDiagram-v2-6371a76b-UE67H35B.js → stateDiagram-v2-6371a76b-HLD2VAQC.js} +10 -10
  93. package/dist/browser/excalidraw-assets/{sv-SE-ANRZHTXG.js → sv-SE-QCQFH645.js} +1 -1
  94. package/dist/browser/excalidraw-assets/{ta-IN-YQ3TKMCX.js → ta-IN-VVBM4WJT.js} +1 -1
  95. package/dist/browser/excalidraw-assets/{th-TH-SQW3PVEH.js → th-TH-7BH7SJAO.js} +1 -1
  96. package/dist/browser/excalidraw-assets/{timeline-definition-5ed366f4-VSVFFB5S.js → timeline-definition-5ed366f4-36TJ7JFQ.js} +3 -3
  97. package/dist/browser/excalidraw-assets/{tr-TR-KUEQIRHA.js → tr-TR-PSQK5I6C.js} +1 -1
  98. package/dist/browser/excalidraw-assets/{uk-UA-LHOOITZN.js → uk-UA-SPVEJS7T.js} +1 -1
  99. package/dist/browser/excalidraw-assets/{vi-VN-A6OAOG4Q.js → vi-VN-KIIQDQET.js} +1 -1
  100. package/dist/browser/excalidraw-assets/{zh-CN-TKODMXQV.js → zh-CN-6PVTYMG5.js} +1 -1
  101. package/dist/browser/excalidraw-assets/{zh-HK-3KKLKRDR.js → zh-HK-V2KK262G.js} +1 -1
  102. package/dist/browser/excalidraw-assets/{zh-TW-SN3SAI3Y.js → zh-TW-VYIR3NM2.js} +1 -1
  103. package/dist/browser/index.css +193 -2
  104. package/dist/browser/index.js +10 -6
  105. package/dist/index.css +193 -2
  106. package/dist/index.js +29488 -861
  107. package/package.json +8 -12
  108. package/types/excalidraw/actions/actionAddToLibrary.d.ts +57 -3
  109. package/types/excalidraw/actions/actionBoundText.d.ts +38 -2
  110. package/types/excalidraw/actions/actionCanvas.d.ts +367 -11
  111. package/types/excalidraw/actions/actionClipboard.d.ts +133 -7
  112. package/types/excalidraw/actions/actionDeleteSelected.d.ts +57 -3
  113. package/types/excalidraw/actions/actionElementLock.d.ts +38 -2
  114. package/types/excalidraw/actions/actionExport.d.ts +171 -9
  115. package/types/excalidraw/actions/actionFinalize.d.ts +38 -2
  116. package/types/excalidraw/actions/actionFrame.d.ts +57 -3
  117. package/types/excalidraw/actions/actionGroup.d.ts +38 -2
  118. package/types/excalidraw/actions/actionLinearEditor.d.ts +19 -1
  119. package/types/excalidraw/actions/actionMenu.d.ts +57 -3
  120. package/types/excalidraw/actions/actionNavigate.d.ts +302 -3
  121. package/types/excalidraw/actions/actionProperties.d.ts +247 -13
  122. package/types/excalidraw/actions/actionSelectAll.d.ts +19 -1
  123. package/types/excalidraw/actions/actionStyles.d.ts +19 -1
  124. package/types/excalidraw/actions/actionToggleGridMode.d.ts +19 -1
  125. package/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +19 -1
  126. package/types/excalidraw/actions/actionToggleStats.d.ts +19 -1
  127. package/types/excalidraw/actions/actionToggleViewMode.d.ts +19 -1
  128. package/types/excalidraw/actions/actionToggleZenMode.d.ts +19 -1
  129. package/types/excalidraw/actions/types.d.ts +1 -1
  130. package/types/excalidraw/components/App.d.ts +7 -2
  131. package/types/excalidraw/components/Avatar.d.ts +3 -1
  132. package/types/excalidraw/components/FollowMode/FollowMode.d.ts +11 -0
  133. package/types/excalidraw/components/Tooltip.d.ts +2 -1
  134. package/types/excalidraw/components/UserList.d.ts +18 -4
  135. package/types/excalidraw/components/icons.d.ts +1 -0
  136. package/types/excalidraw/element/Hyperlink.d.ts +19 -1
  137. package/types/excalidraw/element/bounds.d.ts +14 -1
  138. package/types/excalidraw/element/embeddable.d.ts +19 -1
  139. package/types/excalidraw/element/linearElementEditor.d.ts +20 -2
  140. package/types/excalidraw/index.d.ts +2 -1
  141. package/types/excalidraw/types.d.ts +25 -5
  142. package/types/excalidraw/utils.d.ts +10 -1
@@ -1,18 +1,19 @@
1
1
  import {
2
2
  define_import_meta_env_default,
3
3
  init_define_import_meta_env
4
- } from "./chunk-I7D3YGSV.js";
4
+ } from "./chunk-5XVKPBR4.js";
5
5
  import {
6
6
  en_default
7
- } from "./chunk-Q5V3XSEB.js";
7
+ } from "./chunk-T7PKCJTJ.js";
8
8
  import {
9
9
  percentages_default
10
10
  } from "./chunk-I6H72Z5H.js";
11
11
  import {
12
12
  __commonJS,
13
13
  __export,
14
+ __glob,
14
15
  __toESM
15
- } from "./chunk-YS3YHKSV.js";
16
+ } from "./chunk-HG4GCABW.js";
16
17
 
17
18
  // ../../node_modules/crc-32/crc32.js
18
19
  var require_crc32 = __commonJS({
@@ -5479,11 +5480,11 @@ var require_react_jsx_runtime_development = __commonJS({
5479
5480
  return jsxWithValidation(type, props, key, false);
5480
5481
  }
5481
5482
  }
5482
- var jsx130 = jsxWithValidationDynamic;
5483
- var jsxs73 = jsxWithValidationStatic;
5483
+ var jsx131 = jsxWithValidationDynamic;
5484
+ var jsxs76 = jsxWithValidationStatic;
5484
5485
  exports.Fragment = REACT_FRAGMENT_TYPE;
5485
- exports.jsx = jsx130;
5486
- exports.jsxs = jsxs73;
5486
+ exports.jsx = jsx131;
5487
+ exports.jsxs = jsxs76;
5487
5488
  })();
5488
5489
  }
5489
5490
  }
@@ -7362,6 +7363,65 @@ var import_react2 = __toESM(require_react(), 1);
7362
7363
  var jotaiScope = Symbol();
7363
7364
  var jotaiStore = createStoreForExport();
7364
7365
 
7366
+ // import("./locales/**/*.json") in i18n.ts
7367
+ var globImport_locales_json = __glob({
7368
+ "./locales/ar-SA.json": () => import("./ar-SA-ZG4GMNKR.js"),
7369
+ "./locales/az-AZ.json": () => import("./az-AZ-5QPIG4ZE.js"),
7370
+ "./locales/bg-BG.json": () => import("./bg-BG-GWMMOXVZ.js"),
7371
+ "./locales/bn-BD.json": () => import("./bn-BD-FFLR3TNM.js"),
7372
+ "./locales/ca-ES.json": () => import("./ca-ES-7TTPSWTV.js"),
7373
+ "./locales/cs-CZ.json": () => import("./cs-CZ-ZBCV22AJ.js"),
7374
+ "./locales/da-DK.json": () => import("./da-DK-Q4T27BFS.js"),
7375
+ "./locales/de-DE.json": () => import("./de-DE-MBK4JIXX.js"),
7376
+ "./locales/el-GR.json": () => import("./el-GR-4IO54FJG.js"),
7377
+ "./locales/en.json": () => import("./en-6HNFHSKB.js"),
7378
+ "./locales/es-ES.json": () => import("./es-ES-RTNHOKI6.js"),
7379
+ "./locales/eu-ES.json": () => import("./eu-ES-IPUNFIRV.js"),
7380
+ "./locales/fa-IR.json": () => import("./fa-IR-AFOLD64G.js"),
7381
+ "./locales/fi-FI.json": () => import("./fi-FI-YDIGP7ED.js"),
7382
+ "./locales/fr-FR.json": () => import("./fr-FR-DKTDAJMV.js"),
7383
+ "./locales/gl-ES.json": () => import("./gl-ES-KAW5CTCB.js"),
7384
+ "./locales/he-IL.json": () => import("./he-IL-XFQ6PZWN.js"),
7385
+ "./locales/hi-IN.json": () => import("./hi-IN-CJGZ2R72.js"),
7386
+ "./locales/hu-HU.json": () => import("./hu-HU-LH67LOY3.js"),
7387
+ "./locales/id-ID.json": () => import("./id-ID-L6Y7PWWN.js"),
7388
+ "./locales/it-IT.json": () => import("./it-IT-NYW7ZXIC.js"),
7389
+ "./locales/ja-JP.json": () => import("./ja-JP-PTAJBPX4.js"),
7390
+ "./locales/kaa.json": () => import("./kaa-WXJRXWPF.js"),
7391
+ "./locales/kab-KAB.json": () => import("./kab-KAB-ODUQXY6X.js"),
7392
+ "./locales/kk-KZ.json": () => import("./kk-KZ-UXGGFOE5.js"),
7393
+ "./locales/km-KH.json": () => import("./km-KH-KH42MBCX.js"),
7394
+ "./locales/ko-KR.json": () => import("./ko-KR-OK4WMN6E.js"),
7395
+ "./locales/ku-TR.json": () => import("./ku-TR-I6JF7FTE.js"),
7396
+ "./locales/lt-LT.json": () => import("./lt-LT-MRDJ3W6M.js"),
7397
+ "./locales/lv-LV.json": () => import("./lv-LV-GUHKIRYT.js"),
7398
+ "./locales/mr-IN.json": () => import("./mr-IN-2VY5ATS4.js"),
7399
+ "./locales/my-MM.json": () => import("./my-MM-Q3UE7NDU.js"),
7400
+ "./locales/nb-NO.json": () => import("./nb-NO-YGVSWPTU.js"),
7401
+ "./locales/nl-NL.json": () => import("./nl-NL-JYQZFVD6.js"),
7402
+ "./locales/nn-NO.json": () => import("./nn-NO-SVCTK45S.js"),
7403
+ "./locales/oc-FR.json": () => import("./oc-FR-7S4GZ53C.js"),
7404
+ "./locales/pa-IN.json": () => import("./pa-IN-OAXG5ILZ.js"),
7405
+ "./locales/percentages.json": () => import("./percentages-G7XJNZNY.js"),
7406
+ "./locales/pl-PL.json": () => import("./pl-PL-4LOCCO6A.js"),
7407
+ "./locales/pt-BR.json": () => import("./pt-BR-UE7QKZT7.js"),
7408
+ "./locales/pt-PT.json": () => import("./pt-PT-QRYXWDEQ.js"),
7409
+ "./locales/ro-RO.json": () => import("./ro-RO-S6UM3GTE.js"),
7410
+ "./locales/ru-RU.json": () => import("./ru-RU-X3LZJ2PM.js"),
7411
+ "./locales/si-LK.json": () => import("./si-LK-47EZ7CDR.js"),
7412
+ "./locales/sk-SK.json": () => import("./sk-SK-BZTESEQ3.js"),
7413
+ "./locales/sl-SI.json": () => import("./sl-SI-UKPT7XYH.js"),
7414
+ "./locales/sv-SE.json": () => import("./sv-SE-QCQFH645.js"),
7415
+ "./locales/ta-IN.json": () => import("./ta-IN-VVBM4WJT.js"),
7416
+ "./locales/th-TH.json": () => import("./th-TH-7BH7SJAO.js"),
7417
+ "./locales/tr-TR.json": () => import("./tr-TR-PSQK5I6C.js"),
7418
+ "./locales/uk-UA.json": () => import("./uk-UA-SPVEJS7T.js"),
7419
+ "./locales/vi-VN.json": () => import("./vi-VN-KIIQDQET.js"),
7420
+ "./locales/zh-CN.json": () => import("./zh-CN-6PVTYMG5.js"),
7421
+ "./locales/zh-HK.json": () => import("./zh-HK-V2KK262G.js"),
7422
+ "./locales/zh-TW.json": () => import("./zh-TW-VYIR3NM2.js")
7423
+ });
7424
+
7365
7425
  // i18n.ts
7366
7426
  var COMPLETION_THRESHOLD = 85;
7367
7427
  var defaultLang = { code: "en", label: "English" };
@@ -7437,8 +7497,7 @@ var setLanguage = async (lang) => {
7437
7497
  currentLangData = {};
7438
7498
  } else {
7439
7499
  try {
7440
- currentLangData = await /* webpackChunkName: "locales/[request]" */
7441
- globImport_locales_json(`./locales/${currentLang.code}.json`);
7500
+ currentLangData = await globImport_locales_json(`./locales/${currentLang.code}.json`);
7442
7501
  } catch (error) {
7443
7502
  console.error(`Failed to load language ${lang.code}:`, error.message);
7444
7503
  currentLangData = en_default;
@@ -7866,17 +7925,40 @@ var queryFocusableElements = (container) => {
7866
7925
  (element) => element.tabIndex > -1 && !element.disabled
7867
7926
  ) : [];
7868
7927
  };
7928
+ var _defaultIsShallowComparatorFallback = (a4, b4) => {
7929
+ if (Array.isArray(a4) && Array.isArray(b4) && a4.length === 0 && b4.length === 0) {
7930
+ return true;
7931
+ }
7932
+ return a4 === b4;
7933
+ };
7869
7934
  var isShallowEqual = (objA, objB, comparators, debug = false) => {
7870
7935
  const aKeys = Object.keys(objA);
7871
7936
  const bKeys = Object.keys(objB);
7872
7937
  if (aKeys.length !== bKeys.length) {
7873
7938
  return false;
7874
7939
  }
7940
+ if (comparators && Array.isArray(comparators)) {
7941
+ for (const key of comparators) {
7942
+ const ret = objA[key] === objB[key] || _defaultIsShallowComparatorFallback(objA[key], objB[key]);
7943
+ if (!ret) {
7944
+ if (debug) {
7945
+ console.warn(
7946
+ `%cisShallowEqual: ${key} not equal ->`,
7947
+ "color: #8B4000",
7948
+ objA[key],
7949
+ objB[key]
7950
+ );
7951
+ }
7952
+ return false;
7953
+ }
7954
+ }
7955
+ return true;
7956
+ }
7875
7957
  return aKeys.every((key) => {
7876
7958
  const comparator = comparators?.[key];
7877
- const ret = comparator ? comparator(objA[key], objB[key]) : objA[key] === objB[key];
7959
+ const ret = comparator ? comparator(objA[key], objB[key]) : objA[key] === objB[key] || _defaultIsShallowComparatorFallback(objA[key], objB[key]);
7878
7960
  if (!ret && debug) {
7879
- console.info(
7961
+ console.warn(
7880
7962
  `%cisShallowEqual: ${key} not equal ->`,
7881
7963
  "color: #8B4000",
7882
7964
  objA[key],
@@ -7964,6 +8046,12 @@ var cloneJSON = (obj) => JSON.parse(JSON.stringify(obj));
7964
8046
  var isFiniteNumber = (value) => {
7965
8047
  return typeof value === "number" && Number.isFinite(value);
7966
8048
  };
8049
+ var updateStable = (prevValue, nextValue) => {
8050
+ if (isShallowEqual(prevValue, nextValue)) {
8051
+ return prevValue;
8052
+ }
8053
+ return nextValue;
8054
+ };
7967
8055
 
7968
8056
  // appState.ts
7969
8057
  var defaultExportScale = EXPORT_SCALES.includes(devicePixelRatio) ? devicePixelRatio : 1;
@@ -8053,7 +8141,9 @@ var getDefaultAppState = () => {
8053
8141
  x: 0,
8054
8142
  y: 0
8055
8143
  },
8056
- objectsSnapModeEnabled: false
8144
+ objectsSnapModeEnabled: false,
8145
+ userToFollow: null,
8146
+ followedBy: /* @__PURE__ */ new Set()
8057
8147
  };
8058
8148
  };
8059
8149
  var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
@@ -8147,7 +8237,9 @@ var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
8147
8237
  selectedLinearElement: { browser: true, export: false, server: false },
8148
8238
  snapLines: { browser: false, export: false, server: false },
8149
8239
  originSnapOffset: { browser: false, export: false, server: false },
8150
- objectsSnapModeEnabled: { browser: true, export: false, server: false }
8240
+ objectsSnapModeEnabled: { browser: true, export: false, server: false },
8241
+ userToFollow: { browser: false, export: false, server: false },
8242
+ followedBy: { browser: false, export: false, server: false }
8151
8243
  });
8152
8244
  var _clearAppStateForStorage = (appState, exportType) => {
8153
8245
  const stateForExport = {};
@@ -14018,6 +14110,14 @@ var brainIcon = createIcon(
14018
14110
  ] }),
14019
14111
  tablerIconProps
14020
14112
  );
14113
+ var searchIcon = createIcon(
14114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { strokeWidth: 1.5, children: [
14115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }),
14116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" }),
14117
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 21l-6 -6" })
14118
+ ] }),
14119
+ tablerIconProps
14120
+ );
14021
14121
 
14022
14122
  // actions/actionDeleteSelected.tsx
14023
14123
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
@@ -20556,11 +20656,15 @@ var Tooltip = ({
20556
20656
  children,
20557
20657
  label,
20558
20658
  long = false,
20559
- style
20659
+ style,
20660
+ disabled
20560
20661
  }) => {
20561
20662
  (0, import_react37.useEffect)(() => {
20562
20663
  return () => getTooltipDiv().classList.remove("excalidraw-tooltip--visible");
20563
20664
  }, []);
20665
+ if (disabled) {
20666
+ return null;
20667
+ }
20564
20668
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
20565
20669
  "div",
20566
20670
  {
@@ -20654,7 +20758,8 @@ var actionZoomIn = register({
20654
20758
  nextZoom: getNormalizedZoom(appState.zoom.value + ZOOM_STEP)
20655
20759
  },
20656
20760
  appState
20657
- )
20761
+ ),
20762
+ userToFollow: null
20658
20763
  },
20659
20764
  commitToHistory: false
20660
20765
  };
@@ -20689,7 +20794,8 @@ var actionZoomOut = register({
20689
20794
  nextZoom: getNormalizedZoom(appState.zoom.value - ZOOM_STEP)
20690
20795
  },
20691
20796
  appState
20692
- )
20797
+ ),
20798
+ userToFollow: null
20693
20799
  },
20694
20800
  commitToHistory: false
20695
20801
  };
@@ -20724,7 +20830,8 @@ var actionResetZoom = register({
20724
20830
  nextZoom: getNormalizedZoom(1)
20725
20831
  },
20726
20832
  appState
20727
- )
20833
+ ),
20834
+ userToFollow: null
20728
20835
  },
20729
20836
  commitToHistory: false
20730
20837
  };
@@ -20761,14 +20868,13 @@ var zoomValueToFitBoundsOnViewport = (bounds, viewportDimensions) => {
20761
20868
  );
20762
20869
  return clampedZoomValueToFitElements;
20763
20870
  };
20764
- var zoomToFit = ({
20765
- targetElements,
20871
+ var zoomToFitBounds = ({
20872
+ bounds,
20766
20873
  appState,
20767
20874
  fitToViewport = false,
20768
20875
  viewportZoomFactor = 0.7
20769
20876
  }) => {
20770
- const commonBounds = getCommonBounds(getNonDeletedElements(targetElements));
20771
- const [x1, y1, x22, y22] = commonBounds;
20877
+ const [x1, y1, x22, y22] = bounds;
20772
20878
  const centerX = (x1 + x22) / 2;
20773
20879
  const centerY = (y1 + y22) / 2;
20774
20880
  let newZoomValue;
@@ -20797,7 +20903,7 @@ var zoomToFit = ({
20797
20903
  scrollX = appStateWidth / 2 * (1 / newZoomValue) - centerX;
20798
20904
  scrollY = appState.height / 2 * (1 / newZoomValue) - centerY;
20799
20905
  } else {
20800
- newZoomValue = zoomValueToFitBoundsOnViewport(commonBounds, {
20906
+ newZoomValue = zoomValueToFitBoundsOnViewport(bounds, {
20801
20907
  width: appState.width,
20802
20908
  height: appState.height
20803
20909
  });
@@ -20822,6 +20928,20 @@ var zoomToFit = ({
20822
20928
  commitToHistory: false
20823
20929
  };
20824
20930
  };
20931
+ var zoomToFit = ({
20932
+ targetElements,
20933
+ appState,
20934
+ fitToViewport,
20935
+ viewportZoomFactor
20936
+ }) => {
20937
+ const commonBounds = getCommonBounds(getNonDeletedElements(targetElements));
20938
+ return zoomToFitBounds({
20939
+ bounds: commonBounds,
20940
+ appState,
20941
+ fitToViewport,
20942
+ viewportZoomFactor
20943
+ });
20944
+ };
20825
20945
  var actionZoomToFitSelectionInViewport = register({
20826
20946
  name: "zoomToFitSelectionInViewport",
20827
20947
  trackEvent: { category: "canvas" },
@@ -20829,7 +20949,10 @@ var actionZoomToFitSelectionInViewport = register({
20829
20949
  const selectedElements = app.scene.getSelectedElements(appState);
20830
20950
  return zoomToFit({
20831
20951
  targetElements: selectedElements.length ? selectedElements : elements,
20832
- appState,
20952
+ appState: {
20953
+ ...appState,
20954
+ userToFollow: null
20955
+ },
20833
20956
  fitToViewport: false
20834
20957
  });
20835
20958
  },
@@ -20844,7 +20967,10 @@ var actionZoomToFitSelection = register({
20844
20967
  const selectedElements = app.scene.getSelectedElements(appState);
20845
20968
  return zoomToFit({
20846
20969
  targetElements: selectedElements.length ? selectedElements : elements,
20847
- appState,
20970
+ appState: {
20971
+ ...appState,
20972
+ userToFollow: null
20973
+ },
20848
20974
  fitToViewport: true
20849
20975
  });
20850
20976
  },
@@ -20855,7 +20981,14 @@ var actionZoomToFit = register({
20855
20981
  name: "zoomToFit",
20856
20982
  viewMode: true,
20857
20983
  trackEvent: { category: "canvas" },
20858
- perform: (elements, appState) => zoomToFit({ targetElements: elements, appState, fitToViewport: false }),
20984
+ perform: (elements, appState) => zoomToFit({
20985
+ targetElements: elements,
20986
+ appState: {
20987
+ ...appState,
20988
+ userToFollow: null
20989
+ },
20990
+ fitToViewport: false
20991
+ }),
20859
20992
  keyTest: (event) => event.code === CODES.ONE && event.shiftKey && !event.altKey && !event[KEYS.CTRL_OR_CMD]
20860
20993
  });
20861
20994
  var actionToggleTheme = register({
@@ -21845,12 +21978,12 @@ var e2 = (() => {
21845
21978
  return "showOpenFilePicker";
21846
21979
  return false;
21847
21980
  })();
21848
- var t3 = e2 ? import("./file-open-002ab408-YC7KQ7M7.js") : import("./file-open-7c801643-GRK3M4FM.js");
21981
+ var t3 = e2 ? import("./file-open-002ab408-XIZJR36E.js") : import("./file-open-7c801643-YIZPMU4W.js");
21849
21982
  async function n3(...e3) {
21850
21983
  return (await t3).default(...e3);
21851
21984
  }
21852
- var i3 = e2 ? import("./directory-open-4ed118d0-3YEXHCYQ.js") : import("./directory-open-01563666-OUEPAD2B.js");
21853
- var o3 = e2 ? import("./file-save-745eba88-HT2N2RA6.js") : import("./file-save-3189631c-XOSH6LGE.js");
21985
+ var i3 = e2 ? import("./directory-open-4ed118d0-CW2C2TU4.js") : import("./directory-open-01563666-XGWD52SG.js");
21986
+ var o3 = e2 ? import("./file-save-745eba88-MWPDJIMB.js") : import("./file-save-3189631c-BQMBD5TV.js");
21854
21987
  async function s3(...e3) {
21855
21988
  return (await o3).default(...e3);
21856
21989
  }
@@ -22296,10 +22429,7 @@ var exportToSvg = async (elements, appState, files, opts) => {
22296
22429
  let metadata = "";
22297
22430
  if (exportEmbedScene) {
22298
22431
  try {
22299
- metadata = await (await import(
22300
- /* webpackChunkName: "image" */
22301
- "./image-DBNYVO3T.js"
22302
- )).encodeSvgMetadata({
22432
+ metadata = await (await import("./image-MZHH7VY4.js")).encodeSvgMetadata({
22303
22433
  // when embedding scene, we want to embed the origionally supplied
22304
22434
  // elements which don't contain the temp frame labels.
22305
22435
  // But it also requires that the exportToSvg is being supplied with
@@ -23550,10 +23680,7 @@ var exportCanvas = async (type, elements, appState, files, {
23550
23680
  if (type === "png") {
23551
23681
  let blob = await canvasToBlob(tempCanvas);
23552
23682
  if (appState.exportEmbedScene) {
23553
- blob = await (await import(
23554
- /* webpackChunkName: "image" */
23555
- "./image-DBNYVO3T.js"
23556
- )).encodePngMetadata({
23683
+ blob = await (await import("./image-MZHH7VY4.js")).encodePngMetadata({
23557
23684
  blob,
23558
23685
  metadata: serializeAsJSON(elements, appState, files, "local")
23559
23686
  });
@@ -24276,21 +24403,39 @@ init_define_import_meta_env();
24276
24403
  init_define_import_meta_env();
24277
24404
  var import_react41 = __toESM(require_react(), 1);
24278
24405
  var import_jsx_runtime28 = __toESM(require_jsx_runtime(), 1);
24279
- var Avatar = ({ color, onClick, name, src }) => {
24406
+ var Avatar = ({
24407
+ color,
24408
+ onClick,
24409
+ name,
24410
+ src,
24411
+ isBeingFollowed,
24412
+ isCurrentUser
24413
+ }) => {
24280
24414
  const shortName = getNameInitial(name);
24281
24415
  const [error, setError] = (0, import_react41.useState)(false);
24282
24416
  const loadImg = !error && src;
24283
24417
  const style = loadImg ? void 0 : { background: color };
24284
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "Avatar", style, onClick, children: loadImg ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
24285
- "img",
24418
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
24419
+ "div",
24286
24420
  {
24287
- className: "Avatar-img",
24288
- src,
24289
- alt: shortName,
24290
- referrerPolicy: "no-referrer",
24291
- onError: () => setError(true)
24421
+ className: clsx_m_default("Avatar", {
24422
+ "Avatar--is-followed": isBeingFollowed,
24423
+ "Avatar--is-current-user": isCurrentUser
24424
+ }),
24425
+ style,
24426
+ onClick,
24427
+ children: loadImg ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
24428
+ "img",
24429
+ {
24430
+ className: "Avatar-img",
24431
+ src,
24432
+ alt: shortName,
24433
+ referrerPolicy: "no-referrer",
24434
+ onError: () => setError(true)
24435
+ }
24436
+ ) : shortName
24292
24437
  }
24293
- ) : shortName });
24438
+ );
24294
24439
  };
24295
24440
 
24296
24441
  // actions/actionNavigate.tsx
@@ -24299,38 +24444,74 @@ var actionGoToCollaborator = register({
24299
24444
  name: "goToCollaborator",
24300
24445
  viewMode: true,
24301
24446
  trackEvent: { category: "collab" },
24302
- perform: (_elements, appState, value) => {
24303
- const point2 = value;
24304
- if (!point2) {
24305
- return { appState, commitToHistory: false };
24447
+ perform: (_elements, appState, collaborator) => {
24448
+ if (!collaborator.socketId || appState.userToFollow?.socketId === collaborator.socketId || collaborator.isCurrentUser) {
24449
+ return {
24450
+ appState: {
24451
+ ...appState,
24452
+ userToFollow: null
24453
+ },
24454
+ commitToHistory: false
24455
+ };
24306
24456
  }
24307
24457
  return {
24308
24458
  appState: {
24309
24459
  ...appState,
24310
- ...centerScrollOn({
24311
- scenePoint: point2,
24312
- viewportDimensions: {
24313
- width: appState.width,
24314
- height: appState.height
24315
- },
24316
- zoom: appState.zoom
24317
- }),
24460
+ userToFollow: {
24461
+ socketId: collaborator.socketId,
24462
+ username: collaborator.username || ""
24463
+ },
24318
24464
  // Close mobile menu
24319
24465
  openMenu: appState.openMenu === "canvas" ? null : appState.openMenu
24320
24466
  },
24321
24467
  commitToHistory: false
24322
24468
  };
24323
24469
  },
24324
- PanelComponent: ({ updateData, data }) => {
24325
- const [clientId, collaborator] = data;
24470
+ PanelComponent: ({ updateData, data, appState }) => {
24471
+ const { clientId, collaborator, withName, isBeingFollowed } = data;
24326
24472
  const background = getClientColor(clientId);
24327
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
24473
+ return withName ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
24474
+ "div",
24475
+ {
24476
+ className: "dropdown-menu-item dropdown-menu-item-base UserList__collaborator",
24477
+ onClick: () => updateData(collaborator),
24478
+ children: [
24479
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
24480
+ Avatar,
24481
+ {
24482
+ color: background,
24483
+ onClick: () => {
24484
+ },
24485
+ name: collaborator.username || "",
24486
+ src: collaborator.avatarUrl,
24487
+ isBeingFollowed,
24488
+ isCurrentUser: collaborator.isCurrentUser === true
24489
+ }
24490
+ ),
24491
+ collaborator.username,
24492
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
24493
+ "div",
24494
+ {
24495
+ className: "UserList__collaborator-follow-status-icon",
24496
+ style: { visibility: isBeingFollowed ? "visible" : "hidden" },
24497
+ title: isBeingFollowed ? t("userList.hint.followStatus") : void 0,
24498
+ "aria-hidden": true,
24499
+ children: eyeIcon
24500
+ }
24501
+ )
24502
+ ]
24503
+ }
24504
+ ) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
24328
24505
  Avatar,
24329
24506
  {
24330
24507
  color: background,
24331
- onClick: () => updateData(collaborator.pointer),
24508
+ onClick: () => {
24509
+ updateData(collaborator);
24510
+ },
24332
24511
  name: collaborator.username || "",
24333
- src: collaborator.avatarUrl
24512
+ src: collaborator.avatarUrl,
24513
+ isBeingFollowed,
24514
+ isCurrentUser: collaborator.isCurrentUser === true
24334
24515
  }
24335
24516
  );
24336
24517
  }
@@ -31471,32 +31652,169 @@ var HelpDialog = ({ onClose }) => {
31471
31652
  init_define_import_meta_env();
31472
31653
  var import_react70 = __toESM(require_react(), 1);
31473
31654
  var import_jsx_runtime76 = __toESM(require_jsx_runtime(), 1);
31474
- var UserList = ({ className, mobile, collaborators }) => {
31475
- const actionManager = useExcalidrawActionManager();
31476
- const uniqueCollaborators = /* @__PURE__ */ new Map();
31477
- collaborators.forEach((collaborator, socketId) => {
31478
- uniqueCollaborators.set(
31479
- // filter on user id, else fall back on unique socketId
31480
- collaborator.id || socketId,
31481
- collaborator
31482
- );
31483
- });
31484
- const avatars = uniqueCollaborators.size > 0 && Array.from(uniqueCollaborators).filter(([_, client]) => Object.keys(client).length !== 0).map(([clientId, collaborator]) => {
31485
- const avatarJSX = actionManager.renderAction("goToCollaborator", [
31655
+ var FIRST_N_AVATARS = 3;
31656
+ var SHOW_COLLABORATORS_FILTER_AT = 8;
31657
+ var ConditionalTooltipWrapper = ({
31658
+ shouldWrap,
31659
+ children,
31660
+ clientId,
31661
+ username
31662
+ }) => shouldWrap ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Tooltip, { label: username || "Unknown user", children }, clientId) : /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(import_react70.default.Fragment, { children }, clientId);
31663
+ var renderCollaborator = ({
31664
+ actionManager,
31665
+ collaborator,
31666
+ clientId,
31667
+ withName = false,
31668
+ shouldWrapWithTooltip = false,
31669
+ isBeingFollowed
31670
+ }) => {
31671
+ const data = {
31672
+ clientId,
31673
+ collaborator,
31674
+ withName,
31675
+ isBeingFollowed
31676
+ };
31677
+ const avatarJSX = actionManager.renderAction("goToCollaborator", data);
31678
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
31679
+ ConditionalTooltipWrapper,
31680
+ {
31486
31681
  clientId,
31487
- collaborator
31488
- ]);
31489
- return mobile ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
31490
- Tooltip,
31491
- {
31492
- label: collaborator.username || "Unknown user",
31493
- children: avatarJSX
31494
- },
31495
- clientId
31496
- ) : /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(import_react70.default.Fragment, { children: avatarJSX }, clientId);
31497
- });
31498
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: clsx_m_default("UserList", className, { UserList_mobile: mobile }), children: avatars });
31682
+ username: collaborator.username,
31683
+ shouldWrap: shouldWrapWithTooltip,
31684
+ children: avatarJSX
31685
+ },
31686
+ clientId
31687
+ );
31499
31688
  };
31689
+ var collaboratorComparatorKeys = [
31690
+ "avatarUrl",
31691
+ "id",
31692
+ "socketId",
31693
+ "username"
31694
+ ];
31695
+ var UserList = import_react70.default.memo(
31696
+ ({ className, mobile, collaborators, userToFollow }) => {
31697
+ const actionManager = useExcalidrawActionManager();
31698
+ const uniqueCollaboratorsMap = /* @__PURE__ */ new Map();
31699
+ collaborators.forEach((collaborator, socketId) => {
31700
+ const userId = collaborator.id || socketId;
31701
+ uniqueCollaboratorsMap.set(
31702
+ // filter on user id, else fall back on unique socketId
31703
+ userId,
31704
+ { ...collaborator, socketId }
31705
+ );
31706
+ });
31707
+ const uniqueCollaboratorsArray = Array.from(uniqueCollaboratorsMap).filter(
31708
+ ([_, collaborator]) => collaborator.username?.trim()
31709
+ );
31710
+ const [searchTerm, setSearchTerm] = import_react70.default.useState("");
31711
+ if (uniqueCollaboratorsArray.length === 0) {
31712
+ return null;
31713
+ }
31714
+ const searchTermNormalized = searchTerm.trim().toLowerCase();
31715
+ const filteredCollaborators = searchTermNormalized ? uniqueCollaboratorsArray.filter(
31716
+ ([, collaborator]) => collaborator.username?.toLowerCase().includes(searchTerm)
31717
+ ) : uniqueCollaboratorsArray;
31718
+ const firstNCollaborators = uniqueCollaboratorsArray.slice(
31719
+ 0,
31720
+ FIRST_N_AVATARS
31721
+ );
31722
+ const firstNAvatarsJSX = firstNCollaborators.map(
31723
+ ([clientId, collaborator]) => renderCollaborator({
31724
+ actionManager,
31725
+ collaborator,
31726
+ clientId,
31727
+ shouldWrapWithTooltip: true,
31728
+ isBeingFollowed: collaborator.socketId === userToFollow
31729
+ })
31730
+ );
31731
+ return mobile ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: clsx_m_default("UserList UserList_mobile", className), children: uniqueCollaboratorsArray.map(
31732
+ ([clientId, collaborator]) => renderCollaborator({
31733
+ actionManager,
31734
+ collaborator,
31735
+ clientId,
31736
+ shouldWrapWithTooltip: true,
31737
+ isBeingFollowed: collaborator.socketId === userToFollow
31738
+ })
31739
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: clsx_m_default("UserList", className), children: [
31740
+ firstNAvatarsJSX,
31741
+ uniqueCollaboratorsArray.length > FIRST_N_AVATARS && /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
31742
+ $cb5cc270b50c6fcd$export$be92b6f5f03c0fe9,
31743
+ {
31744
+ onOpenChange: (isOpen) => {
31745
+ if (!isOpen) {
31746
+ setSearchTerm("");
31747
+ }
31748
+ },
31749
+ children: [
31750
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)($cb5cc270b50c6fcd$export$41fb9f06171c75f4, { className: "UserList__more", children: [
31751
+ "+",
31752
+ uniqueCollaboratorsArray.length - FIRST_N_AVATARS
31753
+ ] }),
31754
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
31755
+ $cb5cc270b50c6fcd$export$7c6e2c02157bb7d2,
31756
+ {
31757
+ style: {
31758
+ zIndex: 2,
31759
+ width: "13rem",
31760
+ textAlign: "left"
31761
+ },
31762
+ align: "end",
31763
+ sideOffset: 10,
31764
+ children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(Island, { style: { overflow: "hidden" }, children: [
31765
+ uniqueCollaboratorsArray.length >= SHOW_COLLABORATORS_FILTER_AT && /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "UserList__search-wrapper", children: [
31766
+ searchIcon,
31767
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
31768
+ "input",
31769
+ {
31770
+ className: "UserList__search",
31771
+ type: "text",
31772
+ placeholder: t("userList.search.placeholder"),
31773
+ value: searchTerm,
31774
+ onChange: (e3) => {
31775
+ setSearchTerm(e3.target.value);
31776
+ }
31777
+ }
31778
+ )
31779
+ ] }),
31780
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "dropdown-menu UserList__collaborators", children: [
31781
+ filteredCollaborators.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: "UserList__collaborators__empty", children: t("userList.search.empty") }),
31782
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: "UserList__hint", children: t("userList.hint.text") }),
31783
+ filteredCollaborators.map(
31784
+ ([clientId, collaborator]) => renderCollaborator({
31785
+ actionManager,
31786
+ collaborator,
31787
+ clientId,
31788
+ withName: true,
31789
+ isBeingFollowed: collaborator.socketId === userToFollow
31790
+ })
31791
+ )
31792
+ ] })
31793
+ ] })
31794
+ }
31795
+ )
31796
+ ]
31797
+ }
31798
+ )
31799
+ ] });
31800
+ },
31801
+ (prev, next) => {
31802
+ if (prev.collaborators.size !== next.collaborators.size || prev.mobile !== next.mobile || prev.className !== next.className || prev.userToFollow !== next.userToFollow) {
31803
+ return false;
31804
+ }
31805
+ for (const [socketId, collaborator] of prev.collaborators) {
31806
+ const nextCollaborator = next.collaborators.get(socketId);
31807
+ if (!nextCollaborator || !isShallowEqual(
31808
+ collaborator,
31809
+ nextCollaborator,
31810
+ collaboratorComparatorKeys
31811
+ )) {
31812
+ return false;
31813
+ }
31814
+ }
31815
+ return true;
31816
+ }
31817
+ );
31500
31818
 
31501
31819
  // components/JSONExportDialog.tsx
31502
31820
  init_define_import_meta_env();
@@ -31809,7 +32127,7 @@ var SidebarTrigger = ({
31809
32127
  }) => {
31810
32128
  const setAppState = useExcalidrawSetAppState();
31811
32129
  const appState = useUIAppState();
31812
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("label", { title, children: [
32130
+ return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("label", { title, className: "sidebar-trigger__label-element", children: [
31813
32131
  /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
31814
32132
  "input",
31815
32133
  {
@@ -32911,7 +33229,8 @@ var MainMenu = Object.assign(
32911
33229
  UserList,
32912
33230
  {
32913
33231
  mobile: true,
32914
- collaborators: appState.collaborators
33232
+ collaborators: appState.collaborators,
33233
+ userToFollow: appState.userToFollow?.socketId || null
32915
33234
  }
32916
33235
  )
32917
33236
  ] })
@@ -34953,10 +35272,7 @@ TTD mermaid definition render errror: ${error3.message}`,
34953
35272
  refOnGenerate.current = onGenerate;
34954
35273
  const [mermaidToExcalidrawLib, setMermaidToExcalidrawLib] = (0, import_react89.useState)({
34955
35274
  loaded: false,
34956
- api: import(
34957
- /* webpackChunkName:"mermaid-to-excalidraw" */
34958
- "./dist-YSQXM7F6.js"
34959
- )
35275
+ api: import("./dist-GMU63VF7.js")
34960
35276
  });
34961
35277
  (0, import_react89.useEffect)(() => {
34962
35278
  const fn = async () => {
@@ -35364,7 +35680,13 @@ var LayerUI = ({
35364
35680
  }
35365
35681
  ),
35366
35682
  children: [
35367
- /* @__PURE__ */ (0, import_jsx_runtime121.jsx)(UserList, { collaborators: appState.collaborators }),
35683
+ appState.collaborators.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime121.jsx)(
35684
+ UserList,
35685
+ {
35686
+ collaborators: appState.collaborators,
35687
+ userToFollow: appState.userToFollow?.socketId || null
35688
+ }
35689
+ ),
35368
35690
  renderTopRightUI?.(device.editor.isMobile, appState),
35369
35691
  !appState.viewModeEnabled && // hide button when sidebar docked
35370
35692
  (!isSidebarDocked || appState.openSidebar?.name !== DEFAULT_SIDEBAR.name) && /* @__PURE__ */ (0, import_jsx_runtime121.jsx)(tunnels.DefaultSidebarTriggerTunnel.Out, {})
@@ -37914,8 +38236,42 @@ var ElementCanvasButton = (props) => {
37914
38236
  );
37915
38237
  };
37916
38238
 
37917
- // components/App.tsx
38239
+ // components/FollowMode/FollowMode.tsx
38240
+ init_define_import_meta_env();
37918
38241
  var import_jsx_runtime129 = __toESM(require_jsx_runtime(), 1);
38242
+ var FollowMode = ({
38243
+ height,
38244
+ width,
38245
+ userToFollow,
38246
+ onDisconnect
38247
+ }) => {
38248
+ return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)("div", { style: { position: "relative" }, children: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)("div", { className: "follow-mode", style: { width, height }, children: /* @__PURE__ */ (0, import_jsx_runtime129.jsxs)("div", { className: "follow-mode__badge", children: [
38249
+ /* @__PURE__ */ (0, import_jsx_runtime129.jsxs)("div", { className: "follow-mode__badge__label", children: [
38250
+ "Following",
38251
+ " ",
38252
+ /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
38253
+ "span",
38254
+ {
38255
+ className: "follow-mode__badge__username",
38256
+ title: userToFollow.username,
38257
+ children: userToFollow.username
38258
+ }
38259
+ )
38260
+ ] }),
38261
+ /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
38262
+ "button",
38263
+ {
38264
+ onClick: onDisconnect,
38265
+ className: "follow-mode__disconnect-btn",
38266
+ children: CloseIcon
38267
+ }
38268
+ )
38269
+ ] }) }) });
38270
+ };
38271
+ var FollowMode_default = FollowMode;
38272
+
38273
+ // components/App.tsx
38274
+ var import_jsx_runtime130 = __toESM(require_jsx_runtime(), 1);
37919
38275
  var AppContext = import_react95.default.createContext(null);
37920
38276
  var AppPropsContext = import_react95.default.createContext(null);
37921
38277
  var deviceContextInitialValue = {
@@ -37944,7 +38300,7 @@ var ExcalidrawAppStateContext = import_react95.default.createContext({
37944
38300
  });
37945
38301
  ExcalidrawAppStateContext.displayName = "ExcalidrawAppStateContext";
37946
38302
  var ExcalidrawSetAppStateContext = import_react95.default.createContext(() => {
37947
- console.warn("unitialized ExcalidrawSetAppStateContext context!");
38303
+ console.warn("Uninitialized ExcalidrawSetAppStateContext context!");
37948
38304
  });
37949
38305
  ExcalidrawSetAppStateContext.displayName = "ExcalidrawSetAppStateContext";
37950
38306
  var ExcalidrawActionManagerContext = import_react95.default.createContext(
@@ -38008,6 +38364,8 @@ var App = class _App extends import_react95.default.Component {
38008
38364
  onChangeEmitter = new Emitter();
38009
38365
  onPointerDownEmitter = new Emitter();
38010
38366
  onPointerUpEmitter = new Emitter();
38367
+ onUserFollowEmitter = new Emitter();
38368
+ onScrollChangeEmitter = new Emitter();
38011
38369
  constructor(props) {
38012
38370
  super(props);
38013
38371
  const defaultAppState2 = getDefaultAppState();
@@ -38072,7 +38430,9 @@ var App = class _App extends import_react95.default.Component {
38072
38430
  toggleSidebar: this.toggleSidebar,
38073
38431
  onChange: (cb) => this.onChangeEmitter.on(cb),
38074
38432
  onPointerDown: (cb) => this.onPointerDownEmitter.on(cb),
38075
- onPointerUp: (cb) => this.onPointerUpEmitter.on(cb)
38433
+ onPointerUp: (cb) => this.onPointerUpEmitter.on(cb),
38434
+ onScrollChange: (cb) => this.onScrollChangeEmitter.on(cb),
38435
+ onUserFollow: (cb) => this.onUserFollowEmitter.on(cb)
38076
38436
  };
38077
38437
  if (typeof excalidrawAPI === "function") {
38078
38438
  excalidrawAPI(api);
@@ -38254,7 +38614,7 @@ var App = class _App extends import_react95.default.Component {
38254
38614
  const embeddableElements = this.scene.getNonDeletedElements().filter(
38255
38615
  (el) => isEmbeddableElement(el) && !!el.validated || isIframeElement(el)
38256
38616
  );
38257
- return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(import_jsx_runtime129.Fragment, { children: embeddableElements.map((el) => {
38617
+ return /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(import_jsx_runtime130.Fragment, { children: embeddableElements.map((el) => {
38258
38618
  const { x: x3, y: y3 } = sceneCoordsToViewportCoords(
38259
38619
  { sceneX: el.x, sceneY: el.y },
38260
38620
  this.state
@@ -38401,7 +38761,7 @@ var App = class _App extends import_react95.default.Component {
38401
38761
  );
38402
38762
  const isActive = this.state.activeEmbeddable?.element === el && this.state.activeEmbeddable?.state === "active";
38403
38763
  const isHovered = this.state.activeEmbeddable?.element === el && this.state.activeEmbeddable?.state === "hover";
38404
- return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
38764
+ return /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38405
38765
  "div",
38406
38766
  {
38407
38767
  className: clsx_m_default("excalidraw__embeddable-container", {
@@ -38416,7 +38776,7 @@ var App = class _App extends import_react95.default.Component {
38416
38776
  el
38417
38777
  )}px`
38418
38778
  },
38419
- children: /* @__PURE__ */ (0, import_jsx_runtime129.jsxs)(
38779
+ children: /* @__PURE__ */ (0, import_jsx_runtime130.jsxs)(
38420
38780
  "div",
38421
38781
  {
38422
38782
  className: "excalidraw__embeddable-container__inner",
@@ -38427,15 +38787,15 @@ var App = class _App extends import_react95.default.Component {
38427
38787
  pointerEvents: isActive ? POINTER_EVENTS.enabled : POINTER_EVENTS.disabled
38428
38788
  },
38429
38789
  children: [
38430
- isHovered && /* @__PURE__ */ (0, import_jsx_runtime129.jsx)("div", { className: "excalidraw__embeddable-hint", children: t("buttons.embeddableInteractionButton") }),
38431
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
38790
+ isHovered && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)("div", { className: "excalidraw__embeddable-hint", children: t("buttons.embeddableInteractionButton") }),
38791
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38432
38792
  "div",
38433
38793
  {
38434
38794
  className: "excalidraw__embeddable__outer",
38435
38795
  style: {
38436
38796
  padding: `${el.strokeWidth}px`
38437
38797
  },
38438
- children: (isEmbeddableElement(el) ? this.props.renderEmbeddable?.(el, this.state) : null) ?? /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
38798
+ children: (isEmbeddableElement(el) ? this.props.renderEmbeddable?.(el, this.state) : null) ?? /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38439
38799
  "iframe",
38440
38800
  {
38441
38801
  ref: (ref) => this.cacheEmbeddableRef(el, ref),
@@ -38546,7 +38906,7 @@ var App = class _App extends import_react95.default.Component {
38546
38906
  );
38547
38907
  if (f3.id === this.state.editingFrame) {
38548
38908
  const frameNameInEdit = frameName;
38549
- frameNameJSX = /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
38909
+ frameNameJSX = /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38550
38910
  "input",
38551
38911
  {
38552
38912
  autoFocus: true,
@@ -38588,7 +38948,7 @@ var App = class _App extends import_react95.default.Component {
38588
38948
  } else {
38589
38949
  frameNameJSX = frameName;
38590
38950
  }
38591
- return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
38951
+ return /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38592
38952
  "div",
38593
38953
  {
38594
38954
  id: this.getFrameNameDOMId(f3),
@@ -38646,7 +39006,7 @@ var App = class _App extends import_react95.default.Component {
38646
39006
  const shouldBlockPointerEvents = !(this.state.editingElement && isLinearElement(this.state.editingElement)) && (this.state.selectionElement || this.state.draggingElement || this.state.resizingElement || this.state.activeTool.type === "laser" && // technically we can just test on this once we make it more safe
38647
39007
  this.state.cursorButton === "down" || this.state.editingElement && !isTextElement(this.state.editingElement));
38648
39008
  const firstSelectedElement = selectedElements[0];
38649
- return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39009
+ return /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38650
39010
  "div",
38651
39011
  {
38652
39012
  className: clsx_m_default("excalidraw excalidraw-container", {
@@ -38660,21 +39020,21 @@ var App = class _App extends import_react95.default.Component {
38660
39020
  onDrop: this.handleAppOnDrop,
38661
39021
  tabIndex: 0,
38662
39022
  onKeyDown: this.props.handleKeyboardGlobally ? void 0 : this.onKeyDown,
38663
- children: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(AppContext.Provider, { value: this, children: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(AppPropsContext.Provider, { value: this.props, children: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39023
+ children: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(AppContext.Provider, { value: this, children: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(AppPropsContext.Provider, { value: this.props, children: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38664
39024
  ExcalidrawContainerContext.Provider,
38665
39025
  {
38666
39026
  value: this.excalidrawContainerValue,
38667
- children: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(DeviceContext.Provider, { value: this.device, children: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(ExcalidrawSetAppStateContext.Provider, { value: this.setAppState, children: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(ExcalidrawAppStateContext.Provider, { value: this.state, children: /* @__PURE__ */ (0, import_jsx_runtime129.jsxs)(
39027
+ children: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(DeviceContext.Provider, { value: this.device, children: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(ExcalidrawSetAppStateContext.Provider, { value: this.setAppState, children: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(ExcalidrawAppStateContext.Provider, { value: this.state, children: /* @__PURE__ */ (0, import_jsx_runtime130.jsxs)(
38668
39028
  ExcalidrawElementsContext.Provider,
38669
39029
  {
38670
39030
  value: this.scene.getNonDeletedElements(),
38671
39031
  children: [
38672
- /* @__PURE__ */ (0, import_jsx_runtime129.jsxs)(
39032
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsxs)(
38673
39033
  ExcalidrawActionManagerContext.Provider,
38674
39034
  {
38675
39035
  value: this.actionManager,
38676
39036
  children: [
38677
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39037
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38678
39038
  LayerUI_default,
38679
39039
  {
38680
39040
  canvas: this.canvas,
@@ -38702,11 +39062,11 @@ var App = class _App extends import_react95.default.Component {
38702
39062
  children: this.props.children
38703
39063
  }
38704
39064
  ),
38705
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)("div", { className: "excalidraw-textEditorContainer" }),
38706
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)("div", { className: "excalidraw-contextMenuContainer" }),
38707
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)("div", { className: "excalidraw-eye-dropper-container" }),
38708
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(LaserToolOverlay, { manager: this.laserPathManager }),
38709
- selectedElements.length === 1 && this.state.showHyperlinkPopup && /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39065
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)("div", { className: "excalidraw-textEditorContainer" }),
39066
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)("div", { className: "excalidraw-contextMenuContainer" }),
39067
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)("div", { className: "excalidraw-eye-dropper-container" }),
39068
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(LaserToolOverlay, { manager: this.laserPathManager }),
39069
+ selectedElements.length === 1 && this.state.showHyperlinkPopup && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38710
39070
  Hyperlink,
38711
39071
  {
38712
39072
  element: firstSelectedElement,
@@ -38716,11 +39076,11 @@ var App = class _App extends import_react95.default.Component {
38716
39076
  },
38717
39077
  firstSelectedElement.id
38718
39078
  ),
38719
- this.props.aiEnabled !== false && selectedElements.length === 1 && isMagicFrameElement(firstSelectedElement) && /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39079
+ this.props.aiEnabled !== false && selectedElements.length === 1 && isMagicFrameElement(firstSelectedElement) && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38720
39080
  ElementCanvasButtons,
38721
39081
  {
38722
39082
  element: firstSelectedElement,
38723
- children: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39083
+ children: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38724
39084
  ElementCanvasButton,
38725
39085
  {
38726
39086
  title: t("labels.convertToCode"),
@@ -38734,12 +39094,12 @@ var App = class _App extends import_react95.default.Component {
38734
39094
  )
38735
39095
  }
38736
39096
  ),
38737
- selectedElements.length === 1 && isIframeElement(firstSelectedElement) && firstSelectedElement.customData?.generationData?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime129.jsxs)(
39097
+ selectedElements.length === 1 && isIframeElement(firstSelectedElement) && firstSelectedElement.customData?.generationData?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime130.jsxs)(
38738
39098
  ElementCanvasButtons,
38739
39099
  {
38740
39100
  element: firstSelectedElement,
38741
39101
  children: [
38742
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39102
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38743
39103
  ElementCanvasButton,
38744
39104
  {
38745
39105
  title: t("labels.copySource"),
@@ -38748,7 +39108,7 @@ var App = class _App extends import_react95.default.Component {
38748
39108
  onChange: () => this.onIframeSrcCopy(firstSelectedElement)
38749
39109
  }
38750
39110
  ),
38751
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39111
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38752
39112
  ElementCanvasButton,
38753
39113
  {
38754
39114
  title: "Enter fullscreen",
@@ -38785,7 +39145,7 @@ var App = class _App extends import_react95.default.Component {
38785
39145
  ]
38786
39146
  }
38787
39147
  ),
38788
- this.state.toast !== null && /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39148
+ this.state.toast !== null && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38789
39149
  Toast,
38790
39150
  {
38791
39151
  message: this.state.toast.message,
@@ -38794,7 +39154,7 @@ var App = class _App extends import_react95.default.Component {
38794
39154
  closable: this.state.toast.closable
38795
39155
  }
38796
39156
  ),
38797
- this.state.contextMenu && /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39157
+ this.state.contextMenu && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38798
39158
  ContextMenu,
38799
39159
  {
38800
39160
  items: this.state.contextMenu.items,
@@ -38809,7 +39169,7 @@ var App = class _App extends import_react95.default.Component {
38809
39169
  }
38810
39170
  }
38811
39171
  ),
38812
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39172
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38813
39173
  StaticCanvas_default,
38814
39174
  {
38815
39175
  canvas: this.canvas,
@@ -38828,7 +39188,7 @@ var App = class _App extends import_react95.default.Component {
38828
39188
  }
38829
39189
  }
38830
39190
  ),
38831
- /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
39191
+ /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
38832
39192
  InteractiveCanvas_default,
38833
39193
  {
38834
39194
  containerRef: this.excalidrawContainerRef,
@@ -38851,6 +39211,15 @@ var App = class _App extends import_react95.default.Component {
38851
39211
  onDoubleClick: this.handleCanvasDoubleClick
38852
39212
  }
38853
39213
  ),
39214
+ this.state.userToFollow && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
39215
+ FollowMode_default,
39216
+ {
39217
+ width: this.state.width,
39218
+ height: this.state.height,
39219
+ userToFollow: this.state.userToFollow,
39220
+ onDisconnect: this.maybeUnfollowRemoteUser
39221
+ }
39222
+ ),
38854
39223
  this.renderFrameNames()
38855
39224
  ]
38856
39225
  }
@@ -39430,7 +39799,7 @@ var App = class _App extends import_react95.default.Component {
39430
39799
  }
39431
39800
  if (isBrave() && !isMeasureTextSupported()) {
39432
39801
  this.setState({
39433
- errorMessage: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(BraveMeasureTextError_default, {})
39802
+ errorMessage: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(BraveMeasureTextError_default, {})
39434
39803
  });
39435
39804
  }
39436
39805
  }
@@ -39602,8 +39971,35 @@ var App = class _App extends import_react95.default.Component {
39602
39971
  if (prevProps.UIOptions.dockedSidebarBreakpoint !== this.props.UIOptions.dockedSidebarBreakpoint) {
39603
39972
  this.refreshEditorBreakpoints();
39604
39973
  }
39605
- if (prevState.scrollX !== this.state.scrollX || prevState.scrollY !== this.state.scrollY) {
39606
- this.props?.onScrollChange?.(this.state.scrollX, this.state.scrollY);
39974
+ const hasFollowedPersonLeft = prevState.userToFollow && !this.state.collaborators.has(prevState.userToFollow.socketId);
39975
+ if (hasFollowedPersonLeft) {
39976
+ this.maybeUnfollowRemoteUser();
39977
+ }
39978
+ if (prevState.zoom.value !== this.state.zoom.value || prevState.scrollX !== this.state.scrollX || prevState.scrollY !== this.state.scrollY) {
39979
+ this.props?.onScrollChange?.(
39980
+ this.state.scrollX,
39981
+ this.state.scrollY,
39982
+ this.state.zoom
39983
+ );
39984
+ this.onScrollChangeEmitter.trigger(
39985
+ this.state.scrollX,
39986
+ this.state.scrollY,
39987
+ this.state.zoom
39988
+ );
39989
+ }
39990
+ if (prevState.userToFollow !== this.state.userToFollow) {
39991
+ if (prevState.userToFollow) {
39992
+ this.onUserFollowEmitter.trigger({
39993
+ userToFollow: prevState.userToFollow,
39994
+ action: "UNFOLLOW"
39995
+ });
39996
+ }
39997
+ if (this.state.userToFollow) {
39998
+ this.onUserFollowEmitter.trigger({
39999
+ userToFollow: this.state.userToFollow,
40000
+ action: "FOLLOW"
40001
+ });
40002
+ }
39607
40003
  }
39608
40004
  if (Object.keys(this.state.selectedElementIds).length && isEraserActive(this.state)) {
39609
40005
  this.setState({
@@ -40188,9 +40584,9 @@ var App = class _App extends import_react95.default.Component {
40188
40584
  )
40189
40585
  });
40190
40586
  };
40191
- cancelInProgresAnimation = null;
40587
+ cancelInProgressAnimation = null;
40192
40588
  scrollToContent = (target = this.scene.getNonDeletedElements(), opts) => {
40193
- this.cancelInProgresAnimation?.();
40589
+ this.cancelInProgressAnimation?.();
40194
40590
  const targetElements = Array.isArray(target) ? target : [target];
40195
40591
  let zoom = this.state.zoom;
40196
40592
  let scrollX = this.state.scrollX;
@@ -40245,17 +40641,23 @@ var App = class _App extends import_react95.default.Component {
40245
40641
  },
40246
40642
  duration: opts?.duration ?? 500
40247
40643
  });
40248
- this.cancelInProgresAnimation = () => {
40644
+ this.cancelInProgressAnimation = () => {
40249
40645
  cancel();
40250
- this.cancelInProgresAnimation = null;
40646
+ this.cancelInProgressAnimation = null;
40251
40647
  };
40252
40648
  } else {
40253
40649
  this.setState({ scrollX, scrollY, zoom });
40254
40650
  }
40255
40651
  };
40652
+ maybeUnfollowRemoteUser = () => {
40653
+ if (this.state.userToFollow) {
40654
+ this.setState({ userToFollow: null });
40655
+ }
40656
+ };
40256
40657
  /** use when changing scrollX/scrollY/zoom based on user interaction */
40257
40658
  translateCanvas = (state) => {
40258
- this.cancelInProgresAnimation?.();
40659
+ this.cancelInProgressAnimation?.();
40660
+ this.maybeUnfollowRemoteUser();
40259
40661
  this.setState(state);
40260
40662
  };
40261
40663
  setToast = (toast) => {
@@ -41148,13 +41550,25 @@ var App = class _App extends import_react95.default.Component {
41148
41550
  },
41149
41551
  event
41150
41552
  );
41151
- this.setState({
41152
- snapLines,
41153
- originSnapOffset: originOffset
41553
+ this.setState((prevState) => {
41554
+ const nextSnapLines = updateStable(prevState.snapLines, snapLines);
41555
+ const nextOriginOffset = prevState.originSnapOffset ? updateStable(prevState.originSnapOffset, originOffset) : originOffset;
41556
+ if (prevState.snapLines === nextSnapLines && prevState.originSnapOffset === nextOriginOffset) {
41557
+ return null;
41558
+ }
41559
+ return {
41560
+ snapLines: nextSnapLines,
41561
+ originSnapOffset: nextOriginOffset
41562
+ };
41154
41563
  });
41155
41564
  } else if (!this.state.draggingElement) {
41156
- this.setState({
41157
- snapLines: []
41565
+ this.setState((prevState) => {
41566
+ if (prevState.snapLines.length) {
41567
+ return {
41568
+ snapLines: []
41569
+ };
41570
+ }
41571
+ return null;
41158
41572
  });
41159
41573
  }
41160
41574
  if (this.state.editingLinearElement && !this.state.editingLinearElement.isDragging) {
@@ -41498,6 +41912,7 @@ var App = class _App extends import_react95.default.Component {
41498
41912
  }
41499
41913
  }
41500
41914
  handleCanvasPointerDown = (event) => {
41915
+ this.maybeUnfollowRemoteUser();
41501
41916
  if (this.state.contextMenu) {
41502
41917
  this.setState({ contextMenu: null });
41503
41918
  }
@@ -42937,7 +43352,7 @@ var App = class _App extends import_react95.default.Component {
42937
43352
  isResizing,
42938
43353
  isRotating
42939
43354
  } = this.state;
42940
- this.setState({
43355
+ this.setState((prevState) => ({
42941
43356
  isResizing: false,
42942
43357
  isRotating: false,
42943
43358
  resizingElement: null,
@@ -42948,9 +43363,9 @@ var App = class _App extends import_react95.default.Component {
42948
43363
  // text elements are reset on finalize, and resetting on pointerup
42949
43364
  // may cause issues with double taps
42950
43365
  editingElement: multiElement || isTextElement(this.state.editingElement) ? this.state.editingElement : null,
42951
- snapLines: [],
43366
+ snapLines: updateStable(prevState.snapLines, []),
42952
43367
  originSnapOffset: null
42953
- });
43368
+ }));
42954
43369
  SnapCache.setReferenceSnapPoints(null);
42955
43370
  SnapCache.setVisibleGaps(null);
42956
43371
  this.savePointer(childEvent.clientX, childEvent.clientY, "up");
@@ -43571,7 +43986,10 @@ var App = class _App extends import_react95.default.Component {
43571
43986
  maxWidthOrHeight: DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT
43572
43987
  });
43573
43988
  } catch (error) {
43574
- console.error("error trying to resing image file on insertion", error);
43989
+ console.error(
43990
+ "Error trying to resizing image file on insertion",
43991
+ error
43992
+ );
43575
43993
  }
43576
43994
  if (imageFile.size > MAX_ALLOWED_FILE_BYTES) {
43577
43995
  throw new Error(
@@ -44047,11 +44465,11 @@ var App = class _App extends import_react95.default.Component {
44047
44465
  includeLockedElements: true
44048
44466
  });
44049
44467
  const selectedElements = this.scene.getSelectedElements(this.state);
44050
- const isHittignCommonBoundBox = this.isHittingCommonBoundingBoxOfSelectedElements(
44468
+ const isHittingCommonBoundBox = this.isHittingCommonBoundingBoxOfSelectedElements(
44051
44469
  { x: x3, y: y3 },
44052
44470
  selectedElements
44053
44471
  );
44054
- const type = element || isHittignCommonBoundBox ? "element" : "canvas";
44472
+ const type = element || isHittingCommonBoundBox ? "element" : "canvas";
44055
44473
  const container = this.excalidrawContainerRef.current;
44056
44474
  const { top: offsetTop, left: offsetLeft } = container.getBoundingClientRect();
44057
44475
  const left = event.clientX - offsetLeft;
@@ -44483,7 +44901,7 @@ if (define_import_meta_env_default.MODE === ENV.TEST || define_import_meta_env_d
44483
44901
  var App_default = App;
44484
44902
 
44485
44903
  // components/ToolButton.tsx
44486
- var import_jsx_runtime130 = __toESM(require_jsx_runtime(), 1);
44904
+ var import_jsx_runtime131 = __toESM(require_jsx_runtime(), 1);
44487
44905
  var ToolButton = import_react96.default.forwardRef((props, ref) => {
44488
44906
  const { id: excalId } = useExcalidrawContainer();
44489
44907
  const innerRef = import_react96.default.useRef(null);
@@ -44519,7 +44937,7 @@ var ToolButton = import_react96.default.forwardRef((props, ref) => {
44519
44937
  const lastPointerTypeRef = (0, import_react96.useRef)(null);
44520
44938
  if (props.type === "button" || props.type === "icon" || props.type === "submit") {
44521
44939
  const type = props.type === "icon" ? "button" : props.type;
44522
- return /* @__PURE__ */ (0, import_jsx_runtime130.jsxs)(
44940
+ return /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
44523
44941
  "button",
44524
44942
  {
44525
44943
  className: clsx_m_default(
@@ -44543,22 +44961,22 @@ var ToolButton = import_react96.default.forwardRef((props, ref) => {
44543
44961
  ref: innerRef,
44544
44962
  disabled: isLoading || props.isLoading,
44545
44963
  children: [
44546
- (props.icon || props.label) && /* @__PURE__ */ (0, import_jsx_runtime130.jsxs)("div", { className: "ToolIcon__icon", "aria-hidden": "true", children: [
44964
+ (props.icon || props.label) && /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)("div", { className: "ToolIcon__icon", "aria-hidden": "true", children: [
44547
44965
  props.icon || props.label,
44548
- props.keyBindingLabel && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)("span", { className: "ToolIcon__keybinding", children: props.keyBindingLabel }),
44549
- props.isLoading && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(Spinner_default, {})
44966
+ props.keyBindingLabel && /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "ToolIcon__keybinding", children: props.keyBindingLabel }),
44967
+ props.isLoading && /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(Spinner_default, {})
44550
44968
  ] }),
44551
- props.showAriaLabel && /* @__PURE__ */ (0, import_jsx_runtime130.jsxs)("div", { className: "ToolIcon__label", children: [
44969
+ props.showAriaLabel && /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)("div", { className: "ToolIcon__label", children: [
44552
44970
  props["aria-label"],
44553
44971
  " ",
44554
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(Spinner_default, {})
44972
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(Spinner_default, {})
44555
44973
  ] }),
44556
44974
  props.children
44557
44975
  ]
44558
44976
  }
44559
44977
  );
44560
44978
  }
44561
- return /* @__PURE__ */ (0, import_jsx_runtime130.jsxs)(
44979
+ return /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
44562
44980
  "label",
44563
44981
  {
44564
44982
  className: clsx_m_default("ToolIcon", props.className),
@@ -44573,7 +44991,7 @@ var ToolButton = import_react96.default.forwardRef((props, ref) => {
44573
44991
  });
44574
44992
  },
44575
44993
  children: [
44576
- /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
44994
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(
44577
44995
  "input",
44578
44996
  {
44579
44997
  className: `ToolIcon_type_radio ${sizeCn}`,
@@ -44590,9 +45008,9 @@ var ToolButton = import_react96.default.forwardRef((props, ref) => {
44590
45008
  ref: innerRef
44591
45009
  }
44592
45010
  ),
44593
- /* @__PURE__ */ (0, import_jsx_runtime130.jsxs)("div", { className: "ToolIcon__icon", children: [
45011
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)("div", { className: "ToolIcon__icon", children: [
44594
45012
  props.icon,
44595
- props.keyBindingLabel && /* @__PURE__ */ (0, import_jsx_runtime130.jsx)("span", { className: "ToolIcon__keybinding", children: props.keyBindingLabel })
45013
+ props.keyBindingLabel && /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "ToolIcon__keybinding", children: props.keyBindingLabel })
44596
45014
  ] })
44597
45015
  ]
44598
45016
  }
@@ -44607,7 +45025,7 @@ ToolButton.displayName = "ToolButton";
44607
45025
 
44608
45026
  // element/Hyperlink.tsx
44609
45027
  var import_react97 = __toESM(require_react(), 1);
44610
- var import_jsx_runtime131 = __toESM(require_jsx_runtime(), 1);
45028
+ var import_jsx_runtime132 = __toESM(require_jsx_runtime(), 1);
44611
45029
  var CONTAINER_WIDTH = 320;
44612
45030
  var SPACE_BOTTOM = 85;
44613
45031
  var CONTAINER_PADDING2 = 5;
@@ -44739,7 +45157,7 @@ var Hyperlink = ({
44739
45157
  if (appState.contextMenu || appState.draggingElement || appState.resizingElement || appState.isRotating || appState.openMenu || appState.viewModeEnabled) {
44740
45158
  return null;
44741
45159
  }
44742
- return /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
45160
+ return /* @__PURE__ */ (0, import_jsx_runtime132.jsxs)(
44743
45161
  "div",
44744
45162
  {
44745
45163
  className: "excalidraw-hyperlinkContainer",
@@ -44755,7 +45173,7 @@ var Hyperlink = ({
44755
45173
  }
44756
45174
  },
44757
45175
  children: [
44758
- isEditing ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(
45176
+ isEditing ? /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(
44759
45177
  "input",
44760
45178
  {
44761
45179
  className: clsx_m_default("excalidraw-hyperlinkContainer-input"),
@@ -44775,7 +45193,7 @@ var Hyperlink = ({
44775
45193
  }
44776
45194
  }
44777
45195
  }
44778
- ) : element.link ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(
45196
+ ) : element.link ? /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(
44779
45197
  "a",
44780
45198
  {
44781
45199
  href: normalizeLink(element.link || ""),
@@ -44802,9 +45220,9 @@ var Hyperlink = ({
44802
45220
  rel: "noopener noreferrer",
44803
45221
  children: element.link
44804
45222
  }
44805
- ) : /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("div", { className: "excalidraw-hyperlinkContainer-link", children: t("labels.link.empty") }),
44806
- /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)("div", { className: "excalidraw-hyperlinkContainer__buttons", children: [
44807
- !isEditing && /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(
45223
+ ) : /* @__PURE__ */ (0, import_jsx_runtime132.jsx)("div", { className: "excalidraw-hyperlinkContainer-link", children: t("labels.link.empty") }),
45224
+ /* @__PURE__ */ (0, import_jsx_runtime132.jsxs)("div", { className: "excalidraw-hyperlinkContainer__buttons", children: [
45225
+ !isEditing && /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(
44808
45226
  ToolButton,
44809
45227
  {
44810
45228
  type: "button",
@@ -44816,7 +45234,7 @@ var Hyperlink = ({
44816
45234
  icon: FreedrawIcon
44817
45235
  }
44818
45236
  ),
44819
- linkVal && !isEmbeddableElement(element) && /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(
45237
+ linkVal && !isEmbeddableElement(element) && /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(
44820
45238
  ToolButton,
44821
45239
  {
44822
45240
  type: "button",
@@ -44868,7 +45286,7 @@ var actionLink = register({
44868
45286
  },
44869
45287
  PanelComponent: ({ elements, appState, updateData }) => {
44870
45288
  const selectedElements = getSelectedElements(elements, appState);
44871
- return /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(
45289
+ return /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(
44872
45290
  ToolButton,
44873
45291
  {
44874
45292
  type: "button",
@@ -51077,6 +51495,20 @@ var getCommonBoundingBox = (elements) => {
51077
51495
  midY: (minY + maxY) / 2
51078
51496
  };
51079
51497
  };
51498
+ var getVisibleSceneBounds = ({
51499
+ scrollX,
51500
+ scrollY,
51501
+ width,
51502
+ height,
51503
+ zoom
51504
+ }) => {
51505
+ return [
51506
+ -scrollX,
51507
+ -scrollY,
51508
+ -scrollX + width / zoom.value,
51509
+ -scrollY + height / zoom.value
51510
+ ];
51511
+ };
51080
51512
 
51081
51513
  // math.ts
51082
51514
  var rotate2 = (x3, y3, cx, cy, angle) => (
@@ -52434,10 +52866,7 @@ var parseFileContents = async (blob) => {
52434
52866
  let contents;
52435
52867
  if (blob.type === MIME_TYPES.png) {
52436
52868
  try {
52437
- return await (await import(
52438
- /* webpackChunkName: "image" */
52439
- "./image-DBNYVO3T.js"
52440
- )).decodePngMetadata(blob);
52869
+ return await (await import("./image-MZHH7VY4.js")).decodePngMetadata(blob);
52441
52870
  } catch (error) {
52442
52871
  if (error.message === "INVALID") {
52443
52872
  throw new ImageSceneDataError(
@@ -52464,10 +52893,7 @@ var parseFileContents = async (blob) => {
52464
52893
  }
52465
52894
  if (blob.type === MIME_TYPES.svg) {
52466
52895
  try {
52467
- return await (await import(
52468
- /* webpackChunkName: "image" */
52469
- "./image-DBNYVO3T.js"
52470
- )).decodeSvgMetadata({
52896
+ return await (await import("./image-MZHH7VY4.js")).decodeSvgMetadata({
52471
52897
  svg: contents
52472
52898
  });
52473
52899
  } catch (error) {
@@ -52633,9 +53059,9 @@ var resizeImageFile = async (file2, opts) => {
52633
53059
  return file2;
52634
53060
  }
52635
53061
  const [pica, imageBlobReduce] = await Promise.all([
52636
- import("./pica-UY2E6YV3.js").then((res) => res.default),
53062
+ import("./pica-3M7LI2AU.js").then((res) => res.default),
52637
53063
  // a wrapper for pica for better API
52638
- import("./image-blob-reduce.esm-EBROP3TW.js").then((res) => res.default)
53064
+ import("./image-blob-reduce.esm-5RGBO4BD.js").then((res) => res.default)
52639
53065
  ]);
52640
53066
  const reduce = imageBlobReduce({
52641
53067
  pica: pica({ features: ["js", "wasm"] })
@@ -52938,8 +53364,10 @@ export {
52938
53364
  sceneCoordsToViewportCoords,
52939
53365
  isLinearElement,
52940
53366
  normalizeLink,
53367
+ zoomToFitBounds,
52941
53368
  getFreeDrawSvgPath,
52942
53369
  getCommonBounds,
53370
+ getVisibleSceneBounds,
52943
53371
  restoreElements,
52944
53372
  restoreAppState,
52945
53373
  restore,