Compare commits

...

2234 Commits

Author SHA1 Message Date
c507d1726a New translations en.json (Portuguese) 2025-02-04 11:04:24 +01:00
d6ef71c15c New translations en.json (German) 2025-01-22 20:35:23 +01:00
4b9978cd57 New translations en.json (Slovak) 2025-01-21 03:20:22 +01:00
79cac89d45 New translations en.json (Hindi) 2025-01-16 07:15:41 +01:00
2651ce2e9b New translations en.json (Marathi) 2025-01-16 07:15:40 +01:00
6c3c6f26d9 New translations en.json (Chinese Simplified) 2025-01-16 01:06:46 +01:00
38da08662c New translations en.json (Spanish) 2025-01-14 14:59:30 +01:00
571053aec9 New translations en.json (Romanian) 2025-01-14 11:01:30 +01:00
88b3d9b6a5 New translations en.json (Russian) 2025-01-13 19:17:34 +01:00
f2b9da3255 New translations en.json (German) 2025-01-13 18:13:41 +01:00
ba4a9f1e82 New translations en.json (Karakalpak) 2025-01-13 17:08:29 +01:00
90ee80a3fa New translations en.json (Kabyle) 2025-01-13 17:08:28 +01:00
01c6cbefbc New translations en.json (Bengali, India) 2025-01-13 17:08:27 +01:00
8aee0f5f24 New translations en.json (German, Switzerland) 2025-01-13 17:08:26 +01:00
d865bfb985 New translations en.json (Occitan) 2025-01-13 17:08:25 +01:00
4ac707927a New translations en.json (Norwegian Bokmal) 2025-01-13 17:08:24 +01:00
e102ee38cd New translations en.json (Uzbek) 2025-01-13 17:08:23 +01:00
4df31a063a New translations en.json (Sinhala) 2025-01-13 17:08:21 +01:00
f8e0e7cda9 New translations en.json (Chinese Traditional, Hong Kong) 2025-01-13 17:08:20 +01:00
bfd79929b7 New translations en.json (Burmese) 2025-01-13 17:08:19 +01:00
182df6516a New translations en.json (Hindi) 2025-01-13 17:08:17 +01:00
08840c89ca New translations en.json (Azerbaijani) 2025-01-13 17:08:16 +01:00
30cf52e15c New translations en.json (Latvian) 2025-01-13 17:08:15 +01:00
09f2f38ce7 New translations en.json (Kazakh) 2025-01-13 17:08:14 +01:00
df54053d44 New translations en.json (Norwegian Nynorsk) 2025-01-13 17:08:13 +01:00
1850a09ffd New translations en.json (Thai) 2025-01-13 17:08:11 +01:00
16e2694301 New translations en.json (Marathi) 2025-01-13 17:08:10 +01:00
48fdd416e4 New translations en.json (Bengali) 2025-01-13 17:08:09 +01:00
0e71b552a0 New translations en.json (Tamil) 2025-01-13 17:08:08 +01:00
201df105a0 New translations en.json (Khmer) 2025-01-13 17:08:06 +01:00
8b0297e024 New translations en.json (Persian) 2025-01-13 17:08:05 +01:00
88f2d3d848 New translations en.json (Indonesian) 2025-01-13 17:08:04 +01:00
2262458d08 New translations en.json (Portuguese, Brazilian) 2025-01-13 17:08:02 +01:00
367dbb6a20 New translations en.json (Galician) 2025-01-13 17:08:01 +01:00
15bb6af068 New translations en.json (Vietnamese) 2025-01-13 17:08:00 +01:00
0da5f82b4b New translations en.json (Chinese Simplified) 2025-01-13 17:07:58 +01:00
b6fadd90c6 New translations en.json (Ukrainian) 2025-01-13 17:07:57 +01:00
f4dd5ced14 New translations en.json (Turkish) 2025-01-13 17:07:56 +01:00
67b4a6083e New translations en.json (Swedish) 2025-01-13 17:07:54 +01:00
d011d8ffbe New translations en.json (Slovenian) 2025-01-13 17:07:53 +01:00
9341ae94fe New translations en.json (Russian) 2025-01-13 17:07:52 +01:00
5d9d93e400 New translations en.json (Portuguese) 2025-01-13 17:07:51 +01:00
8660a48958 New translations en.json (Polish) 2025-01-13 17:07:49 +01:00
361cb1b94c New translations en.json (Punjabi) 2025-01-13 17:07:48 +01:00
4282f3c2dc New translations en.json (Dutch) 2025-01-13 17:07:47 +01:00
37ee37caaa New translations en.json (Lithuanian) 2025-01-13 17:07:46 +01:00
9ef56c2b20 New translations en.json (Kurdish) 2025-01-13 17:07:44 +01:00
7f235f5830 New translations en.json (Japanese) 2025-01-13 17:07:43 +01:00
cbe30a553f New translations en.json (Italian) 2025-01-13 17:07:42 +01:00
28eef4fc08 New translations en.json (Finnish) 2025-01-13 17:07:41 +01:00
10bf4dae6b New translations en.json (Basque) 2025-01-13 17:07:39 +01:00
ccb2b9e5e2 New translations en.json (Greek) 2025-01-13 17:07:38 +01:00
25c9334ebe New translations en.json (German) 2025-01-13 17:07:36 +01:00
057a5b555a New translations en.json (Danish) 2025-01-13 17:07:34 +01:00
7adb935619 New translations en.json (Czech) 2025-01-13 17:07:33 +01:00
6d6bb7a6d0 New translations en.json (Catalan) 2025-01-13 17:07:31 +01:00
7fa8edcdfe New translations en.json (Bulgarian) 2025-01-13 17:07:29 +01:00
63facdd1b3 New translations en.json (Arabic) 2025-01-13 17:07:28 +01:00
0ead775db7 New translations en.json (Spanish) 2025-01-13 17:07:27 +01:00
5af0f1c11e New translations en.json (French) 2025-01-13 17:07:25 +01:00
fd5c2b81d8 New translations en.json (Romanian) 2025-01-13 17:07:24 +01:00
052e456826 New translations en.json (Chinese Traditional) 2025-01-13 17:07:23 +01:00
0e71e2e49b New translations en.json (Korean) 2025-01-13 17:07:22 +01:00
0d50481428 New translations en.json (Hungarian) 2025-01-13 17:07:21 +01:00
c82882e7e4 New translations en.json (Hebrew) 2025-01-13 17:07:19 +01:00
62bd7cca34 New translations en.json (Slovak) 2025-01-13 17:07:18 +01:00
0e37679c89 New translations en.json (Slovak) 2025-01-13 02:34:56 +01:00
cfcac1d74d New translations en.json (Turkish) 2025-01-09 20:19:36 +01:00
f8935be5fd New translations en.json (Chinese Traditional) 2025-01-07 08:35:18 +01:00
2ad3c1e3a0 New translations en.json (Russian) 2025-01-06 20:51:27 +01:00
8c69e77458 New translations en.json (Spanish) 2025-01-06 17:36:56 +01:00
7c60960708 New translations en.json (Chinese Simplified) 2025-01-06 06:18:41 +01:00
c050f50920 New translations en.json (Slovenian) 2025-01-05 23:23:46 +01:00
fc0364e49b New translations en.json (German) 2025-01-05 23:23:44 +01:00
1c2bc960e3 New translations en.json (Romanian) 2025-01-05 23:23:43 +01:00
fa3e95e62d New translations en.json (Karakalpak) 2025-01-05 22:14:04 +01:00
91ff8ece0d New translations en.json (Kabyle) 2025-01-05 22:14:03 +01:00
08241465c4 New translations en.json (Bengali, India) 2025-01-05 22:14:02 +01:00
4a70e3c8c6 New translations en.json (German, Switzerland) 2025-01-05 22:14:01 +01:00
58ae2ef67f New translations en.json (Occitan) 2025-01-05 22:14:00 +01:00
d4474ce348 New translations en.json (Norwegian Bokmal) 2025-01-05 22:13:59 +01:00
a02df75456 New translations en.json (Uzbek) 2025-01-05 22:13:58 +01:00
e0d1d4ae53 New translations en.json (Sinhala) 2025-01-05 22:13:57 +01:00
91f906d122 New translations en.json (Chinese Traditional, Hong Kong) 2025-01-05 22:13:56 +01:00
8e76a3576a New translations en.json (Burmese) 2025-01-05 22:13:55 +01:00
575ba7c167 New translations en.json (Hindi) 2025-01-05 22:13:54 +01:00
f4ea623e65 New translations en.json (Azerbaijani) 2025-01-05 22:13:52 +01:00
a74946d8ba New translations en.json (Latvian) 2025-01-05 22:13:51 +01:00
5cf9ce5a19 New translations en.json (Kazakh) 2025-01-05 22:13:50 +01:00
06b26a347e New translations en.json (Norwegian Nynorsk) 2025-01-05 22:13:50 +01:00
4a071e90e8 New translations en.json (Thai) 2025-01-05 22:13:48 +01:00
11e7ea11df New translations en.json (Marathi) 2025-01-05 22:13:48 +01:00
01b0ac438c New translations en.json (Bengali) 2025-01-05 22:13:46 +01:00
3b6c1fdbaa New translations en.json (Tamil) 2025-01-05 22:13:45 +01:00
a6119a0910 New translations en.json (Khmer) 2025-01-05 22:13:44 +01:00
c42898a939 New translations en.json (Persian) 2025-01-05 22:13:43 +01:00
aaa239113f New translations en.json (Indonesian) 2025-01-05 22:13:42 +01:00
110d3d7c69 New translations en.json (Portuguese, Brazilian) 2025-01-05 22:13:41 +01:00
1e9fe91adf New translations en.json (Galician) 2025-01-05 22:13:40 +01:00
b8baa27839 New translations en.json (Vietnamese) 2025-01-05 22:13:39 +01:00
c1c2091a88 New translations en.json (Chinese Simplified) 2025-01-05 22:13:38 +01:00
8f7aa71a4c New translations en.json (Ukrainian) 2025-01-05 22:13:37 +01:00
d38ea58a27 New translations en.json (Turkish) 2025-01-05 22:13:36 +01:00
cb62a51426 New translations en.json (Swedish) 2025-01-05 22:13:35 +01:00
c300216307 New translations en.json (Slovenian) 2025-01-05 22:13:34 +01:00
a01bbedada New translations en.json (Russian) 2025-01-05 22:13:33 +01:00
0d9e1e8f92 New translations en.json (Portuguese) 2025-01-05 22:13:32 +01:00
93a95db1b2 New translations en.json (Polish) 2025-01-05 22:13:31 +01:00
b22d830b3b New translations en.json (Punjabi) 2025-01-05 22:13:30 +01:00
de09e6867c New translations en.json (Dutch) 2025-01-05 22:13:29 +01:00
6f37102175 New translations en.json (Lithuanian) 2025-01-05 22:13:28 +01:00
351aac987b New translations en.json (Kurdish) 2025-01-05 22:13:27 +01:00
9c534fe870 New translations en.json (Japanese) 2025-01-05 22:13:26 +01:00
fbe2745b2d New translations en.json (Italian) 2025-01-05 22:13:25 +01:00
cfa03593a6 New translations en.json (Finnish) 2025-01-05 22:13:24 +01:00
b13771496f New translations en.json (Basque) 2025-01-05 22:13:23 +01:00
a7cc1247d1 New translations en.json (Greek) 2025-01-05 22:13:22 +01:00
323008553e New translations en.json (German) 2025-01-05 22:13:21 +01:00
253017fe8e New translations en.json (Danish) 2025-01-05 22:13:20 +01:00
97ee0973dd New translations en.json (Czech) 2025-01-05 22:13:19 +01:00
a0f3c50ceb New translations en.json (Catalan) 2025-01-05 22:13:18 +01:00
0a9ae2505d New translations en.json (Bulgarian) 2025-01-05 22:13:17 +01:00
5bb7a37121 New translations en.json (Arabic) 2025-01-05 22:13:16 +01:00
532c4bb639 New translations en.json (Spanish) 2025-01-05 22:13:15 +01:00
218c9ef1c3 New translations en.json (French) 2025-01-05 22:13:14 +01:00
21016e21a5 New translations en.json (Romanian) 2025-01-05 22:13:13 +01:00
20ca0ccf12 New translations en.json (Chinese Traditional) 2025-01-05 22:13:12 +01:00
a96c2013b7 New translations en.json (Korean) 2025-01-05 22:13:10 +01:00
bf9733f7ef New translations en.json (Hungarian) 2025-01-05 22:13:09 +01:00
7566d96b35 New translations en.json (Hebrew) 2025-01-05 22:13:08 +01:00
4b8642d1d0 New translations en.json (Slovak) 2025-01-05 22:13:07 +01:00
3ca773f54d New translations en.json (Hungarian) 2024-12-31 16:17:49 +01:00
3dbdfdcffc New translations en.json (Hungarian) 2024-12-31 15:16:38 +01:00
4acea43b12 New translations en.json (Slovak) 2024-12-30 10:40:20 +01:00
aabc4b701e New translations en.json (Slovak) 2024-12-30 08:55:51 +01:00
1325c85a48 New translations en.json (Hebrew) 2024-12-28 00:16:03 +01:00
3f3134435e New translations en.json (Hebrew) 2024-12-27 22:51:12 +01:00
2d370b9360 New translations en.json (Chinese Traditional) 2024-12-23 10:29:20 +01:00
dab6df1a77 New translations en.json (Korean) 2024-12-23 07:42:22 +01:00
4390f6d75e New translations en.json (Romanian) 2024-12-18 11:57:51 +01:00
4d1730882b New translations en.json (Polish) 2024-12-18 10:37:52 +01:00
6bff123aea New translations en.json (Chinese Simplified) 2024-12-18 04:04:53 +01:00
e255caefc5 New translations en.json (German) 2024-12-17 21:04:56 +01:00
a62ebd7f71 New translations en.json (Hindi) 2024-12-17 18:15:21 +01:00
376d25ad8b New translations en.json (Marathi) 2024-12-17 18:15:19 +01:00
dfc89f9d6e New translations en.json (Russian) 2024-12-17 15:27:00 +01:00
62114e309f New translations en.json (Portuguese) 2024-12-17 15:26:58 +01:00
c6901cae98 New translations en.json (Karakalpak) 2024-12-17 14:11:42 +01:00
d4b760f7b3 New translations en.json (Kabyle) 2024-12-17 14:11:41 +01:00
5e21607153 New translations en.json (Bengali, India) 2024-12-17 14:11:40 +01:00
3e79c6caab New translations en.json (German, Switzerland) 2024-12-17 14:11:38 +01:00
fee26ea12c New translations en.json (Occitan) 2024-12-17 14:11:37 +01:00
b551e5336c New translations en.json (Norwegian Bokmal) 2024-12-17 14:11:36 +01:00
172ecace2f New translations en.json (Uzbek) 2024-12-17 14:11:35 +01:00
e146d42598 New translations en.json (Sinhala) 2024-12-17 14:11:33 +01:00
0546406d4b New translations en.json (Chinese Traditional, Hong Kong) 2024-12-17 14:11:32 +01:00
4a5ca8d3ea New translations en.json (Burmese) 2024-12-17 14:11:31 +01:00
267341b9b7 New translations en.json (Hindi) 2024-12-17 14:11:29 +01:00
c3a15bc297 New translations en.json (Azerbaijani) 2024-12-17 14:11:28 +01:00
4b1d99fbf4 New translations en.json (Latvian) 2024-12-17 14:11:27 +01:00
c4c1193094 New translations en.json (Kazakh) 2024-12-17 14:11:25 +01:00
03adc9b7bc New translations en.json (Norwegian Nynorsk) 2024-12-17 14:11:24 +01:00
fd491e45e9 New translations en.json (Thai) 2024-12-17 14:11:23 +01:00
a19c1d64e4 New translations en.json (Marathi) 2024-12-17 14:11:21 +01:00
836c8f2dba New translations en.json (Bengali) 2024-12-17 14:11:20 +01:00
01f2001a0d New translations en.json (Tamil) 2024-12-17 14:11:19 +01:00
8136b719bd New translations en.json (Khmer) 2024-12-17 14:11:18 +01:00
20870a78c2 New translations en.json (Persian) 2024-12-17 14:11:16 +01:00
e741a6f370 New translations en.json (Portuguese, Brazilian) 2024-12-17 14:11:15 +01:00
e76ef06074 New translations en.json (Galician) 2024-12-17 14:11:14 +01:00
0fd05e34c4 New translations en.json (Vietnamese) 2024-12-17 14:11:12 +01:00
b11c80361a New translations en.json (Chinese Traditional) 2024-12-17 14:11:11 +01:00
f19c0d14ed New translations en.json (Ukrainian) 2024-12-17 14:11:09 +01:00
b242a9df79 New translations en.json (Turkish) 2024-12-17 14:11:07 +01:00
9fed9613fa New translations en.json (Russian) 2024-12-17 14:11:06 +01:00
01fa484a5e New translations en.json (Polish) 2024-12-17 14:11:04 +01:00
9a7e1710a4 New translations en.json (Punjabi) 2024-12-17 14:11:03 +01:00
d1957e4056 New translations en.json (Dutch) 2024-12-17 14:11:02 +01:00
68c96c5c9f New translations en.json (Lithuanian) 2024-12-17 14:11:00 +01:00
617897be5b New translations en.json (Kurdish) 2024-12-17 14:10:59 +01:00
b116388c7e New translations en.json (Korean) 2024-12-17 14:10:57 +01:00
473d4da923 New translations en.json (Japanese) 2024-12-17 14:10:56 +01:00
4c15aa2cf2 New translations en.json (Indonesian) 2024-12-17 14:10:55 +01:00
73f1d98d06 New translations en.json (Portuguese) 2024-12-17 14:10:53 +01:00
4e75a68ad3 New translations en.json (Chinese Simplified) 2024-12-17 14:10:52 +01:00
c0cf71a6f5 New translations en.json (Swedish) 2024-12-17 14:10:50 +01:00
4b5b7e8f5a New translations en.json (Slovenian) 2024-12-17 14:10:49 +01:00
e0dff46a28 New translations en.json (Slovak) 2024-12-17 14:10:48 +01:00
505b6ace2b New translations en.json (Italian) 2024-12-17 14:10:47 +01:00
4845574506 New translations en.json (Hungarian) 2024-12-17 14:10:45 +01:00
a9f69d750b New translations en.json (Hebrew) 2024-12-17 14:10:44 +01:00
f883167acc New translations en.json (Finnish) 2024-12-17 14:10:43 +01:00
3d89b04ac4 New translations en.json (Basque) 2024-12-17 14:10:42 +01:00
3ffa6c93e4 New translations en.json (Greek) 2024-12-17 14:10:40 +01:00
6be95e9fbf New translations en.json (German) 2024-12-17 14:10:39 +01:00
be0d4241e4 New translations en.json (Danish) 2024-12-17 14:10:37 +01:00
dc0b951dfa New translations en.json (Catalan) 2024-12-17 14:10:36 +01:00
b92b0ec82b New translations en.json (Bulgarian) 2024-12-17 14:10:35 +01:00
774fd07ca8 New translations en.json (Arabic) 2024-12-17 14:10:34 +01:00
a18a1ace4d New translations en.json (Spanish) 2024-12-17 14:10:32 +01:00
728ac246d5 New translations en.json (French) 2024-12-17 14:10:31 +01:00
a1b5ff5372 New translations en.json (Romanian) 2024-12-17 14:10:30 +01:00
80b98ca5e4 New translations en.json (Czech) 2024-12-17 14:10:28 +01:00
4d22570b55 New translations en.json (Czech) 2024-12-17 12:44:37 +01:00
f1a2bb6677 New translations en.json (Indonesian) 2024-12-16 00:25:54 +01:00
b213e344fb New translations en.json (Indonesian) 2024-12-15 23:23:04 +01:00
ed61daeb16 New translations en.json (Portuguese) 2024-12-15 21:05:23 +01:00
4e752e95a3 New translations en.json (Chinese Simplified) 2024-12-12 03:59:20 +01:00
e459e07af5 New translations en.json (Swedish) 2024-12-09 08:39:44 +01:00
1aa82f1c80 New translations en.json (Slovak) 2024-12-07 17:51:15 +01:00
ae9dca08b5 New translations en.json (Slovak) 2024-12-07 16:55:39 +01:00
7af0ba734d New translations en.json (Slovenian) 2024-12-03 07:13:08 +01:00
d200ee2d0d New translations en.json (Italian) 2024-12-01 16:32:30 +01:00
597bde73d4 New translations en.json (Persian) 2024-11-30 14:11:06 +01:00
44642e29e4 New translations en.json (Persian) 2024-11-30 13:08:35 +01:00
d01091c094 New translations en.json (Persian) 2024-11-30 12:05:49 +01:00
9cbe0a89a7 New translations en.json (Chinese Traditional) 2024-11-28 15:43:42 +01:00
09c53b975e New translations en.json (Hindi) 2024-11-27 06:51:41 +01:00
356d13cae7 New translations en.json (Marathi) 2024-11-27 06:51:40 +01:00
37a3caf5a9 New translations en.json (Hindi) 2024-11-27 05:10:53 +01:00
baaad3a443 New translations en.json (Marathi) 2024-11-27 05:10:52 +01:00
d679f40082 New translations en.json (Chinese Simplified) 2024-11-26 23:12:40 +01:00
9a7cd4f7ef New translations en.json (Russian) 2024-11-26 21:32:27 +01:00
f94ca28f79 New translations en.json (German) 2024-11-26 20:27:07 +01:00
f264ae11f4 New translations en.json (Romanian) 2024-11-26 20:27:06 +01:00
d864979a03 New translations en.json (Karakalpak) 2024-11-26 19:16:20 +01:00
0a6d3d1adb New translations en.json (Kabyle) 2024-11-26 19:16:19 +01:00
1d9a5047ad New translations en.json (Bengali, India) 2024-11-26 19:16:18 +01:00
e3ec60d5f0 New translations en.json (German, Switzerland) 2024-11-26 19:16:16 +01:00
7d13b85641 New translations en.json (Occitan) 2024-11-26 19:16:15 +01:00
5d507846bc New translations en.json (Norwegian Bokmal) 2024-11-26 19:16:14 +01:00
b75e141298 New translations en.json (Uzbek) 2024-11-26 19:16:13 +01:00
884c74fbb2 New translations en.json (Sinhala) 2024-11-26 19:16:12 +01:00
bcf4d508f1 New translations en.json (Chinese Traditional, Hong Kong) 2024-11-26 19:16:11 +01:00
dc539e6820 New translations en.json (Burmese) 2024-11-26 19:16:10 +01:00
6f2eb61779 New translations en.json (Hindi) 2024-11-26 19:16:08 +01:00
9f616b80ad New translations en.json (Azerbaijani) 2024-11-26 19:16:07 +01:00
054616a1cc New translations en.json (Latvian) 2024-11-26 19:16:06 +01:00
cec851802c New translations en.json (Kazakh) 2024-11-26 19:16:04 +01:00
3a0185547b New translations en.json (Norwegian Nynorsk) 2024-11-26 19:16:03 +01:00
3ff94c62d8 New translations en.json (Thai) 2024-11-26 19:16:02 +01:00
5c389ba4f8 New translations en.json (Marathi) 2024-11-26 19:16:01 +01:00
17e68174e0 New translations en.json (Bengali) 2024-11-26 19:15:59 +01:00
e709161793 New translations en.json (Tamil) 2024-11-26 19:15:58 +01:00
20f73f04d0 New translations en.json (Khmer) 2024-11-26 19:15:57 +01:00
fbac5eca10 New translations en.json (Persian) 2024-11-26 19:15:55 +01:00
cad57ed57f New translations en.json (Portuguese, Brazilian) 2024-11-26 19:15:54 +01:00
4df28ca379 New translations en.json (Galician) 2024-11-26 19:15:53 +01:00
1a89311bf1 New translations en.json (Vietnamese) 2024-11-26 19:15:52 +01:00
e419fbf34f New translations en.json (Chinese Traditional) 2024-11-26 19:15:50 +01:00
84f2ab1730 New translations en.json (Chinese Simplified) 2024-11-26 19:15:49 +01:00
4d0d230a2a New translations en.json (Ukrainian) 2024-11-26 19:15:48 +01:00
b1c73bfa1d New translations en.json (Turkish) 2024-11-26 19:15:47 +01:00
f6b5f846a0 New translations en.json (Swedish) 2024-11-26 19:15:45 +01:00
db0f79925b New translations en.json (Slovenian) 2024-11-26 19:15:43 +01:00
f23ba3ef04 New translations en.json (Slovak) 2024-11-26 19:15:42 +01:00
8c0adc2057 New translations en.json (Russian) 2024-11-26 19:15:41 +01:00
a9276c6be4 New translations en.json (Portuguese) 2024-11-26 19:15:39 +01:00
e9239f7cd6 New translations en.json (Polish) 2024-11-26 19:15:38 +01:00
3607ed03a4 New translations en.json (Punjabi) 2024-11-26 19:15:37 +01:00
0fbc118070 New translations en.json (Dutch) 2024-11-26 19:15:34 +01:00
6a620a5384 New translations en.json (Lithuanian) 2024-11-26 19:15:33 +01:00
c87d215ca7 New translations en.json (Kurdish) 2024-11-26 19:15:32 +01:00
2a31a1ff29 New translations en.json (Korean) 2024-11-26 19:15:30 +01:00
cdc50c727e New translations en.json (Japanese) 2024-11-26 19:15:29 +01:00
73c788b92a New translations en.json (Italian) 2024-11-26 19:15:28 +01:00
b14ddf04bd New translations en.json (Hungarian) 2024-11-26 19:15:26 +01:00
2099a5a9ce New translations en.json (Hebrew) 2024-11-26 19:15:25 +01:00
e645dde8cb New translations en.json (Finnish) 2024-11-26 19:15:23 +01:00
481c01a2f1 New translations en.json (Basque) 2024-11-26 19:15:22 +01:00
3cbff07c4d New translations en.json (Greek) 2024-11-26 19:15:21 +01:00
afff916b38 New translations en.json (German) 2024-11-26 19:15:19 +01:00
89b4bf9ba9 New translations en.json (Danish) 2024-11-26 19:15:18 +01:00
0d2c2589ff New translations en.json (Czech) 2024-11-26 19:15:17 +01:00
8bad0ff2f4 New translations en.json (Bulgarian) 2024-11-26 19:15:15 +01:00
5f395cb853 New translations en.json (Arabic) 2024-11-26 19:15:14 +01:00
7fff5d5b81 New translations en.json (Spanish) 2024-11-26 19:15:12 +01:00
b025fee131 New translations en.json (French) 2024-11-26 19:15:11 +01:00
be6bed7ef6 New translations en.json (Romanian) 2024-11-26 19:15:10 +01:00
14d3a5d24c New translations en.json (Indonesian) 2024-11-26 19:15:09 +01:00
185e8c2872 New translations en.json (Catalan) 2024-11-26 19:15:07 +01:00
911acf5563 New translations en.json (Indonesian) 2024-11-26 18:06:22 +01:00
06f4d4bdf6 New translations en.json (Catalan) 2024-11-19 12:11:10 +01:00
51df6af4d5 New translations en.json (Catalan) 2024-11-19 09:45:38 +01:00
2b82cfeb17 New translations en.json (Persian) 2024-11-06 16:00:23 +01:00
45412a5b9f New translations en.json (Persian) 2024-11-06 14:10:19 +01:00
0d02fe5357 New translations en.json (Portuguese, Brazilian) 2024-11-05 21:43:37 +01:00
7173691477 New translations en.json (Chinese Simplified) 2024-10-26 12:43:37 +02:00
48b9a4d5dc New translations en.json (Hindi) 2024-10-24 09:47:16 +02:00
76dd970ded New translations en.json (Marathi) 2024-10-24 09:47:14 +02:00
9c963374c1 New translations en.json (Marathi) 2024-10-24 07:40:11 +02:00
9be077c0af New translations en.json (Polish) 2024-10-23 14:28:30 +02:00
6980e289ba New translations en.json (Thai) 2024-10-23 13:16:18 +02:00
4ac09f6b2b New translations en.json (Polish) 2024-10-23 13:16:16 +02:00
62e9b39ac5 New translations en.json (Chinese Traditional) 2024-10-23 06:40:53 +02:00
f9b0d26c7f New translations en.json (German) 2024-10-22 19:44:31 +02:00
43e8ae3bdd New translations en.json (Romanian) 2024-10-22 12:29:39 +02:00
695c2580cd New translations en.json (Slovenian) 2024-10-22 06:25:46 +02:00
41a7111e19 New translations en.json (Karakalpak) 2024-10-21 23:42:54 +02:00
0338f74b45 New translations en.json (Kabyle) 2024-10-21 23:42:53 +02:00
baa1858a95 New translations en.json (Bengali, India) 2024-10-21 23:42:52 +02:00
e011b47e58 New translations en.json (German, Switzerland) 2024-10-21 23:42:51 +02:00
a97c8a0360 New translations en.json (Occitan) 2024-10-21 23:42:50 +02:00
976ffab80f New translations en.json (Norwegian Bokmal) 2024-10-21 23:42:49 +02:00
84a363fe4d New translations en.json (Uzbek) 2024-10-21 23:42:48 +02:00
62d05d7f25 New translations en.json (Sinhala) 2024-10-21 23:42:47 +02:00
66e5170691 New translations en.json (Chinese Traditional, Hong Kong) 2024-10-21 23:42:46 +02:00
da16dd3eff New translations en.json (Burmese) 2024-10-21 23:42:44 +02:00
00f0f85cd8 New translations en.json (Hindi) 2024-10-21 23:42:43 +02:00
8c864ea97b New translations en.json (Azerbaijani) 2024-10-21 23:42:42 +02:00
b20083c572 New translations en.json (Latvian) 2024-10-21 23:42:41 +02:00
c91a774849 New translations en.json (Kazakh) 2024-10-21 23:42:40 +02:00
835be2ae12 New translations en.json (Norwegian Nynorsk) 2024-10-21 23:42:39 +02:00
3831c17d45 New translations en.json (Thai) 2024-10-21 23:42:38 +02:00
3b2779dacc New translations en.json (Marathi) 2024-10-21 23:42:36 +02:00
31a0a79438 New translations en.json (Bengali) 2024-10-21 23:42:35 +02:00
310e04cd63 New translations en.json (Tamil) 2024-10-21 23:42:34 +02:00
ebd84c318d New translations en.json (Khmer) 2024-10-21 23:42:33 +02:00
3b5a918176 New translations en.json (Persian) 2024-10-21 23:42:32 +02:00
c878278c4c New translations en.json (Indonesian) 2024-10-21 23:42:31 +02:00
2fb60ffdd2 New translations en.json (Portuguese, Brazilian) 2024-10-21 23:42:30 +02:00
3ed09450bf New translations en.json (Galician) 2024-10-21 23:42:29 +02:00
6ba9228ee1 New translations en.json (Vietnamese) 2024-10-21 23:42:27 +02:00
9cbc5fe090 New translations en.json (Chinese Traditional) 2024-10-21 23:42:26 +02:00
4cb605f65e New translations en.json (Ukrainian) 2024-10-21 23:42:25 +02:00
b9f7b1b927 New translations en.json (Slovenian) 2024-10-21 23:42:24 +02:00
1ce313ef8d New translations en.json (Russian) 2024-10-21 23:42:23 +02:00
92f40dee15 New translations en.json (Portuguese) 2024-10-21 23:42:22 +02:00
349d4336c4 New translations en.json (Polish) 2024-10-21 23:42:21 +02:00
d678395574 New translations en.json (Punjabi) 2024-10-21 23:42:20 +02:00
699a08aed7 New translations en.json (Dutch) 2024-10-21 23:42:18 +02:00
eb17963a56 New translations en.json (Lithuanian) 2024-10-21 23:42:17 +02:00
0be2c0be9d New translations en.json (Kurdish) 2024-10-21 23:42:16 +02:00
3e52ed7c45 New translations en.json (Japanese) 2024-10-21 23:42:15 +02:00
84a89d4f74 New translations en.json (Italian) 2024-10-21 23:42:14 +02:00
80cc680fff New translations en.json (Hungarian) 2024-10-21 23:42:13 +02:00
255f47483f New translations en.json (Hebrew) 2024-10-21 23:42:12 +02:00
10f5c6b509 New translations en.json (Finnish) 2024-10-21 23:42:11 +02:00
6e0fac82d3 New translations en.json (Basque) 2024-10-21 23:42:10 +02:00
2be2924fa0 New translations en.json (Greek) 2024-10-21 23:42:09 +02:00
9fd4565e4a New translations en.json (German) 2024-10-21 23:42:07 +02:00
4e5ea9c740 New translations en.json (Danish) 2024-10-21 23:42:06 +02:00
0ab0d44cd3 New translations en.json (Czech) 2024-10-21 23:42:05 +02:00
6c26b4e569 New translations en.json (Catalan) 2024-10-21 23:42:04 +02:00
5b0253d3a6 New translations en.json (Bulgarian) 2024-10-21 23:42:03 +02:00
28a654fccc New translations en.json (Arabic) 2024-10-21 23:42:02 +02:00
bda68283d3 New translations en.json (Spanish) 2024-10-21 23:42:00 +02:00
eb7140181d New translations en.json (Romanian) 2024-10-21 23:41:59 +02:00
9b93b1c568 New translations en.json (French) 2024-10-21 23:41:58 +02:00
d32aed4330 New translations en.json (Chinese Simplified) 2024-10-21 23:41:57 +02:00
419f9f2a2f New translations en.json (Korean) 2024-10-21 23:41:56 +02:00
86dfb3dff2 New translations en.json (Slovak) 2024-10-21 23:41:55 +02:00
4a650dc607 New translations en.json (Swedish) 2024-10-21 23:41:54 +02:00
6db2847d10 New translations en.json (Turkish) 2024-10-21 23:41:53 +02:00
0c24264185 New translations en.json (French) 2024-10-21 17:02:51 +02:00
9391e8090a New translations en.json (Slovak) 2024-10-20 19:51:59 +02:00
c0c3ca85d7 New translations en.json (Russian) 2024-10-18 10:39:46 +02:00
d183629ca4 New translations en.json (Chinese Simplified) 2024-10-18 07:52:05 +02:00
cd4846f8aa New translations en.json (Chinese Traditional) 2024-10-18 05:37:32 +02:00
997bd7f6b3 New translations en.json (Polish) 2024-10-17 23:06:53 +02:00
a93a36c94a New translations en.json (Slovenian) 2024-10-17 21:45:50 +02:00
84314ed5ec New translations en.json (German) 2024-10-17 21:45:49 +02:00
ae09870836 New translations en.json (Karakalpak) 2024-10-17 20:17:04 +02:00
bff8aaee01 New translations en.json (Kabyle) 2024-10-17 20:17:02 +02:00
b059d9ac0b New translations en.json (Bengali, India) 2024-10-17 20:17:01 +02:00
46c9b1d2a9 New translations en.json (German, Switzerland) 2024-10-17 20:17:00 +02:00
3e36e07d80 New translations en.json (Occitan) 2024-10-17 20:16:59 +02:00
0080bcfce5 New translations en.json (Norwegian Bokmal) 2024-10-17 20:16:58 +02:00
0bd6ce4b47 New translations en.json (Uzbek) 2024-10-17 20:16:57 +02:00
f4c88d5669 New translations en.json (Sinhala) 2024-10-17 20:16:56 +02:00
b6038126c5 New translations en.json (Chinese Traditional, Hong Kong) 2024-10-17 20:16:55 +02:00
5ab897112c New translations en.json (Burmese) 2024-10-17 20:16:54 +02:00
1b2d4e59a3 New translations en.json (Hindi) 2024-10-17 20:16:53 +02:00
569860cde6 New translations en.json (Azerbaijani) 2024-10-17 20:16:51 +02:00
7de2e0975d New translations en.json (Latvian) 2024-10-17 20:16:50 +02:00
653bcd7898 New translations en.json (Kazakh) 2024-10-17 20:16:49 +02:00
733b0b45ce New translations en.json (Norwegian Nynorsk) 2024-10-17 20:16:48 +02:00
ed2c4ccbba New translations en.json (Thai) 2024-10-17 20:16:47 +02:00
aab15eef3e New translations en.json (Marathi) 2024-10-17 20:16:45 +02:00
ce7ede5fb0 New translations en.json (Bengali) 2024-10-17 20:16:44 +02:00
944ffba66f New translations en.json (Tamil) 2024-10-17 20:16:43 +02:00
e600142ee6 New translations en.json (Khmer) 2024-10-17 20:16:42 +02:00
3a3e9f8701 New translations en.json (Persian) 2024-10-17 20:16:40 +02:00
dfdfeae79f New translations en.json (Indonesian) 2024-10-17 20:16:39 +02:00
a6b49fa014 New translations en.json (Portuguese, Brazilian) 2024-10-17 20:16:38 +02:00
a706962edd New translations en.json (Galician) 2024-10-17 20:16:37 +02:00
e69fd9f2f8 New translations en.json (Vietnamese) 2024-10-17 20:16:36 +02:00
3f7b5034e7 New translations en.json (Chinese Traditional) 2024-10-17 20:16:35 +02:00
fcbecec034 New translations en.json (Ukrainian) 2024-10-17 20:16:34 +02:00
e77fc90d90 New translations en.json (Slovenian) 2024-10-17 20:16:32 +02:00
112b16d9df New translations en.json (Russian) 2024-10-17 20:16:30 +02:00
dc4e625750 New translations en.json (Portuguese) 2024-10-17 20:16:29 +02:00
a25eae3edd New translations en.json (Polish) 2024-10-17 20:16:28 +02:00
7f58444112 New translations en.json (Punjabi) 2024-10-17 20:16:27 +02:00
6527ee5a11 New translations en.json (Dutch) 2024-10-17 20:16:25 +02:00
52a2558d11 New translations en.json (Lithuanian) 2024-10-17 20:16:24 +02:00
21a56e4a0b New translations en.json (Kurdish) 2024-10-17 20:16:23 +02:00
c2fdeda13e New translations en.json (Japanese) 2024-10-17 20:16:22 +02:00
4e0f644a55 New translations en.json (Italian) 2024-10-17 20:16:21 +02:00
257ffe1c07 New translations en.json (Hungarian) 2024-10-17 20:16:20 +02:00
5416ee4c7c New translations en.json (Hebrew) 2024-10-17 20:16:19 +02:00
833314cf7a New translations en.json (Finnish) 2024-10-17 20:16:17 +02:00
359c2c2bc6 New translations en.json (Basque) 2024-10-17 20:16:16 +02:00
e8e734be56 New translations en.json (Greek) 2024-10-17 20:16:15 +02:00
556e38edce New translations en.json (German) 2024-10-17 20:16:14 +02:00
aaeddcf0e1 New translations en.json (Danish) 2024-10-17 20:16:13 +02:00
6139cb6d98 New translations en.json (Czech) 2024-10-17 20:16:12 +02:00
aff50136ef New translations en.json (Catalan) 2024-10-17 20:16:11 +02:00
8a8c60adab New translations en.json (Bulgarian) 2024-10-17 20:16:09 +02:00
c09b46e964 New translations en.json (Arabic) 2024-10-17 20:16:08 +02:00
ed7ffe00a3 New translations en.json (Spanish) 2024-10-17 20:16:07 +02:00
67b8e63637 New translations en.json (Romanian) 2024-10-17 20:16:06 +02:00
c6a8e4de1e New translations en.json (French) 2024-10-17 20:16:05 +02:00
59982f4d84 New translations en.json (Chinese Simplified) 2024-10-17 20:16:04 +02:00
ab6e573497 New translations en.json (Korean) 2024-10-17 20:16:02 +02:00
dd377b2a0f New translations en.json (Slovak) 2024-10-17 20:16:01 +02:00
c6607c4d19 New translations en.json (Swedish) 2024-10-17 20:16:00 +02:00
f881d98ae7 New translations en.json (Turkish) 2024-10-17 20:15:59 +02:00
7a88e72f82 New translations en.json (French) 2024-10-15 13:15:42 +02:00
d132221f9f New translations en.json (Chinese Simplified) 2024-10-14 05:51:53 +02:00
46a7204d41 New translations en.json (Korean) 2024-10-12 10:18:26 +02:00
c46038b47e New translations en.json (Korean) 2024-10-12 09:08:57 +02:00
1ec6828470 New translations en.json (Slovak) 2024-10-05 09:29:19 +02:00
8d5d10b352 New translations en.json (Swedish) 2024-10-04 16:47:21 +02:00
09585d312b New translations en.json (Swedish) 2024-10-04 15:02:33 +02:00
7e8b2ad87e New translations en.json (Turkish) 2024-10-03 15:45:15 +02:00
26c6bd8942 New translations en.json (Portuguese, Brazilian) 2024-10-01 18:35:44 +02:00
d198280f6c New translations en.json (Chinese Simplified) 2024-09-26 12:55:03 +02:00
573adc72a2 New translations en.json (Japanese) 2024-09-26 12:55:01 +02:00
94dcc50578 New translations en.json (Hebrew) 2024-09-20 11:33:55 +02:00
1b8591d297 New translations en.json (Hebrew) 2024-09-20 09:16:14 +02:00
a3afb5551b New translations en.json (Chinese Traditional) 2024-09-16 05:50:12 +02:00
cda10a8aff New translations en.json (Persian) 2024-09-13 23:05:05 +02:00
a0d7a0a178 New translations en.json (Polish) 2024-09-12 18:49:55 +02:00
c94e69abbb New translations en.json (Polish) 2024-09-12 15:08:27 +02:00
c1227e5e65 New translations en.json (Ukrainian) 2024-09-12 14:10:48 +02:00
f535d1a2c1 New translations en.json (Hindi) 2024-09-12 08:06:48 +02:00
a2be6780de New translations en.json (Marathi) 2024-09-12 08:06:47 +02:00
fc174d14c4 New translations en.json (Hindi) 2024-09-12 07:08:04 +02:00
69fef3808b New translations en.json (Marathi) 2024-09-12 07:08:03 +02:00
d63e67f1ef New translations en.json (Russian) 2024-09-11 22:32:08 +02:00
bbbde64199 New translations en.json (Slovenian) 2024-09-11 20:55:49 +02:00
136eb8bbad New translations en.json (German) 2024-09-11 20:55:47 +02:00
220952d014 New translations en.json (Romanian) 2024-09-11 20:55:46 +02:00
789ccd857a New translations en.json (Hindi) 2024-09-11 19:34:29 +02:00
4270b2c013 New translations en.json (Marathi) 2024-09-11 19:34:24 +02:00
98f432ff8e New translations en.json (Chinese Traditional) 2024-09-11 19:34:19 +02:00
3aeb0dde1f New translations en.json (Swedish) 2024-09-11 19:34:15 +02:00
a6e3e4c1d9 New translations en.json (Slovenian) 2024-09-11 19:34:14 +02:00
34defc0327 New translations en.json (Russian) 2024-09-11 19:34:13 +02:00
a76508746a New translations en.json (Portuguese) 2024-09-11 19:34:12 +02:00
624c80e80a New translations en.json (German) 2024-09-11 19:34:03 +02:00
0f695e41e1 New translations en.json (Romanian) 2024-09-11 19:33:58 +02:00
13dbb4fcc5 New translations en.json (Polish) 2024-09-11 19:33:56 +02:00
59d5d7e0b5 New translations en.json (German, Switzerland) 2024-09-11 19:33:55 +02:00
8f6323fd38 New translations en.json (Hindi) 2024-09-11 11:46:51 +02:00
4f5ba867be New translations en.json (Marathi) 2024-09-11 11:46:49 +02:00
2ff791a31b New translations en.json (Polish) 2024-09-11 11:46:48 +02:00
678b8edb87 New translations en.json (Romanian) 2024-09-10 21:20:50 +02:00
6e29b3ad25 New translations en.json (Swedish) 2024-09-10 09:34:34 +02:00
31e812c084 New translations en.json (Slovenian) 2024-09-10 09:34:32 +02:00
4b3dd5ba71 New translations en.json (Chinese Traditional) 2024-09-10 06:19:12 +02:00
941219be23 New translations en.json (Russian) 2024-09-09 23:40:22 +02:00
c74ee59fee New translations en.json (Portuguese) 2024-09-09 21:08:26 +02:00
b35bcdb09e New translations en.json (German) 2024-09-09 19:49:08 +02:00
e3fdaf7e9d New translations en.json (Karakalpak) 2024-09-09 17:31:44 +02:00
55b438017f New translations en.json (Kabyle) 2024-09-09 17:31:43 +02:00
52a95589d6 New translations en.json (Bengali, India) 2024-09-09 17:31:42 +02:00
e1351768c8 New translations en.json (Occitan) 2024-09-09 17:31:40 +02:00
03867d184a New translations en.json (Norwegian Bokmal) 2024-09-09 17:31:39 +02:00
63511c149a New translations en.json (Uzbek) 2024-09-09 17:31:38 +02:00
28aa841d8e New translations en.json (Sinhala) 2024-09-09 17:31:35 +02:00
cbd1d07c91 New translations en.json (Chinese Traditional, Hong Kong) 2024-09-09 17:31:34 +02:00
b8add8f2ed New translations en.json (Burmese) 2024-09-09 17:31:33 +02:00
632e9d492f New translations en.json (Hindi) 2024-09-09 17:31:32 +02:00
5f848e58c3 New translations en.json (Azerbaijani) 2024-09-09 17:31:31 +02:00
f67c30d062 New translations en.json (Latvian) 2024-09-09 17:31:29 +02:00
195b05cd44 New translations en.json (Kazakh) 2024-09-09 17:31:28 +02:00
09ebef19dd New translations en.json (Norwegian Nynorsk) 2024-09-09 17:31:27 +02:00
d465b5df2a New translations en.json (Thai) 2024-09-09 17:31:26 +02:00
8a88c67b60 New translations en.json (Marathi) 2024-09-09 17:31:24 +02:00
4f3acdee72 New translations en.json (Bengali) 2024-09-09 17:31:23 +02:00
dab9274cdd New translations en.json (Tamil) 2024-09-09 17:31:22 +02:00
b0991c13d9 New translations en.json (Khmer) 2024-09-09 17:31:21 +02:00
0d727dd01a New translations en.json (Indonesian) 2024-09-09 17:31:20 +02:00
d4b6a1a89c New translations en.json (Portuguese, Brazilian) 2024-09-09 17:31:19 +02:00
425736cb55 New translations en.json (Galician) 2024-09-09 17:31:18 +02:00
094f35e1a1 New translations en.json (Vietnamese) 2024-09-09 17:31:17 +02:00
6f93afcbd7 New translations en.json (Chinese Traditional) 2024-09-09 17:31:16 +02:00
71678ed812 New translations en.json (Chinese Simplified) 2024-09-09 17:31:14 +02:00
d19c45d42c New translations en.json (Ukrainian) 2024-09-09 17:31:13 +02:00
9d29320bc0 New translations en.json (Turkish) 2024-09-09 17:31:12 +02:00
f083ba7f8d New translations en.json (Swedish) 2024-09-09 17:31:11 +02:00
bfa4205bf7 New translations en.json (Slovenian) 2024-09-09 17:31:10 +02:00
c4d3cb7d4e New translations en.json (Slovak) 2024-09-09 17:31:09 +02:00
1fe128e53b New translations en.json (Russian) 2024-09-09 17:31:07 +02:00
25f3c1486c New translations en.json (Portuguese) 2024-09-09 17:31:06 +02:00
620f837b82 New translations en.json (Punjabi) 2024-09-09 17:31:05 +02:00
65a58cb080 New translations en.json (Dutch) 2024-09-09 17:31:04 +02:00
f9d9d8eefc New translations en.json (Lithuanian) 2024-09-09 17:31:03 +02:00
5f5d8dea8a New translations en.json (Kurdish) 2024-09-09 17:31:01 +02:00
230827cba5 New translations en.json (Korean) 2024-09-09 17:31:00 +02:00
53c7487113 New translations en.json (Japanese) 2024-09-09 17:30:59 +02:00
d5b4287f41 New translations en.json (Italian) 2024-09-09 17:30:58 +02:00
c29b7a5c7a New translations en.json (Hungarian) 2024-09-09 17:30:57 +02:00
a56dd2a529 New translations en.json (Hebrew) 2024-09-09 17:30:55 +02:00
14b59805a2 New translations en.json (Finnish) 2024-09-09 17:30:54 +02:00
e01e1be3de New translations en.json (Basque) 2024-09-09 17:30:53 +02:00
d403251fd7 New translations en.json (German) 2024-09-09 17:30:52 +02:00
d46c9d35b7 New translations en.json (Danish) 2024-09-09 17:30:51 +02:00
5fa9193415 New translations en.json (Czech) 2024-09-09 17:30:50 +02:00
239767be22 New translations en.json (Catalan) 2024-09-09 17:30:49 +02:00
7ce49d3566 New translations en.json (Bulgarian) 2024-09-09 17:30:48 +02:00
e228cca96b New translations en.json (Arabic) 2024-09-09 17:30:47 +02:00
92f2b0b0e1 New translations en.json (Spanish) 2024-09-09 17:30:45 +02:00
01d1639141 New translations en.json (French) 2024-09-09 17:30:44 +02:00
11272a101f New translations en.json (Romanian) 2024-09-09 17:30:43 +02:00
d2bdb7ab0b New translations en.json (Greek) 2024-09-09 17:30:42 +02:00
bc0d3b1a67 New translations en.json (Polish) 2024-09-09 17:30:41 +02:00
e2451d9c7f New translations en.json (German, Switzerland) 2024-09-09 17:30:40 +02:00
670887e3f3 New translations en.json (Persian) 2024-09-09 17:30:38 +02:00
345e3535b4 New translations en.json (Slovak) 2024-09-05 15:45:17 +02:00
5eeeba0333 New translations en.json (Hebrew) 2024-09-03 23:55:19 +02:00
df351f3b30 New translations en.json (Portuguese) 2024-09-03 19:33:06 +02:00
29d5da3e66 New translations en.json (French) 2024-09-03 11:35:20 +02:00
12d35d3da3 New translations en.json (Ukrainian) 2024-08-31 17:08:12 +02:00
a067dd0faa New translations en.json (Greek) 2024-08-31 13:53:33 +02:00
4758d28ac1 New translations en.json (Portuguese, Brazilian) 2024-08-31 07:10:40 +02:00
bfc9692ad1 New translations en.json (Italian) 2024-08-30 14:42:21 +02:00
a23fef8afe New translations en.json (Chinese Traditional) 2024-08-28 16:34:09 +02:00
2827117eb4 New translations en.json (Polish) 2024-08-27 22:22:10 +02:00
e11d71d9c1 New translations en.json (German) 2024-08-27 13:48:03 +02:00
0aacafc032 New translations en.json (Romanian) 2024-08-27 11:46:25 +02:00
573e947b31 New translations en.json (Russian) 2024-08-27 10:37:45 +02:00
128e5a0ef0 New translations en.json (Hindi) 2024-08-27 08:40:04 +02:00
114033dde4 New translations en.json (Marathi) 2024-08-27 08:40:03 +02:00
3cc0f2e452 New translations en.json (Slovenian) 2024-08-27 08:40:01 +02:00
28a08686a8 New translations en.json (Russian) 2024-08-27 08:40:00 +02:00
100e47307b New translations en.json (Chinese Simplified) 2024-08-27 06:53:14 +02:00
254e6f4d30 New translations en.json (Karakalpak) 2024-08-27 00:32:35 +02:00
d63d5a2602 New translations en.json (Kabyle) 2024-08-27 00:32:34 +02:00
729cdc0c2b New translations en.json (Bengali, India) 2024-08-27 00:32:33 +02:00
253ac4af2d New translations en.json (Occitan) 2024-08-27 00:32:32 +02:00
63863f2530 New translations en.json (Norwegian Bokmal) 2024-08-27 00:32:31 +02:00
3bd04e55ab New translations en.json (Uzbek) 2024-08-27 00:32:30 +02:00
8fd9b5c791 New translations en.json (Sinhala) 2024-08-27 00:32:29 +02:00
3c7671f160 New translations en.json (Chinese Traditional, Hong Kong) 2024-08-27 00:32:28 +02:00
16b50fad38 New translations en.json (Burmese) 2024-08-27 00:32:27 +02:00
a09bd51978 New translations en.json (Hindi) 2024-08-27 00:32:26 +02:00
829624199b New translations en.json (Azerbaijani) 2024-08-27 00:32:25 +02:00
3fa3460d1a New translations en.json (Latvian) 2024-08-27 00:32:24 +02:00
309c1252a6 New translations en.json (Kazakh) 2024-08-27 00:32:23 +02:00
444673a54e New translations en.json (Norwegian Nynorsk) 2024-08-27 00:32:22 +02:00
0f58f4dbeb New translations en.json (Thai) 2024-08-27 00:32:21 +02:00
bbb4d88c2a New translations en.json (Marathi) 2024-08-27 00:32:20 +02:00
ad0964116a New translations en.json (Bengali) 2024-08-27 00:32:19 +02:00
91a58912ce New translations en.json (Tamil) 2024-08-27 00:32:18 +02:00
2c8a913770 New translations en.json (Khmer) 2024-08-27 00:32:17 +02:00
c37b4ee3f7 New translations en.json (Indonesian) 2024-08-27 00:32:16 +02:00
85726121a8 New translations en.json (Portuguese, Brazilian) 2024-08-27 00:32:15 +02:00
1b65578c44 New translations en.json (Galician) 2024-08-27 00:32:14 +02:00
24fe9663f0 New translations en.json (Vietnamese) 2024-08-27 00:32:13 +02:00
a54bccf04e New translations en.json (Chinese Traditional) 2024-08-27 00:32:12 +02:00
50777b6b43 New translations en.json (Chinese Simplified) 2024-08-27 00:32:11 +02:00
fde9dfe20f New translations en.json (Ukrainian) 2024-08-27 00:32:10 +02:00
d2ddce8012 New translations en.json (Turkish) 2024-08-27 00:32:09 +02:00
09a3831733 New translations en.json (Swedish) 2024-08-27 00:32:07 +02:00
a036419535 New translations en.json (Slovenian) 2024-08-27 00:32:06 +02:00
e278d51713 New translations en.json (Slovak) 2024-08-27 00:32:05 +02:00
fcfafce65b New translations en.json (Russian) 2024-08-27 00:32:04 +02:00
886eb2c588 New translations en.json (Portuguese) 2024-08-27 00:32:03 +02:00
cfa71f5045 New translations en.json (Punjabi) 2024-08-27 00:32:02 +02:00
f5c100ed62 New translations en.json (Dutch) 2024-08-27 00:32:01 +02:00
bd6f81b088 New translations en.json (Lithuanian) 2024-08-27 00:32:00 +02:00
13f2105589 New translations en.json (Kurdish) 2024-08-27 00:31:59 +02:00
80e9e037ea New translations en.json (Korean) 2024-08-27 00:31:58 +02:00
98a6ea7e3a New translations en.json (Japanese) 2024-08-27 00:31:57 +02:00
83b72ace65 New translations en.json (Italian) 2024-08-27 00:31:56 +02:00
406fb15bd9 New translations en.json (Hungarian) 2024-08-27 00:31:55 +02:00
a50b9be1de New translations en.json (Hebrew) 2024-08-27 00:31:54 +02:00
71cc6a3bfd New translations en.json (Finnish) 2024-08-27 00:31:53 +02:00
ec99637bb2 New translations en.json (Basque) 2024-08-27 00:31:52 +02:00
5d4ee260b3 New translations en.json (German) 2024-08-27 00:31:51 +02:00
32e295ed8c New translations en.json (Danish) 2024-08-27 00:31:50 +02:00
c22843a7f1 New translations en.json (Czech) 2024-08-27 00:31:49 +02:00
be155a676f New translations en.json (Catalan) 2024-08-27 00:31:48 +02:00
7288582ef2 New translations en.json (Bulgarian) 2024-08-27 00:31:47 +02:00
e1376f3f74 New translations en.json (Arabic) 2024-08-27 00:31:46 +02:00
7f25d2f5b5 New translations en.json (Spanish) 2024-08-27 00:31:45 +02:00
e36f9f56d0 New translations en.json (French) 2024-08-27 00:31:44 +02:00
2cf88adca9 New translations en.json (Romanian) 2024-08-27 00:31:43 +02:00
07ad3271b4 New translations en.json (Greek) 2024-08-27 00:31:42 +02:00
6861334dad New translations en.json (Polish) 2024-08-27 00:31:41 +02:00
fbc27a7fd1 New translations en.json (German, Switzerland) 2024-08-27 00:31:40 +02:00
557aa9fa33 New translations en.json (Persian) 2024-08-27 00:31:39 +02:00
376c7590b5 New translations en.json (Catalan) 2024-08-21 08:56:29 +02:00
f258ab3a4e New translations en.json (Karakalpak) 2024-08-20 18:38:10 +02:00
c4f6ff7acc New translations en.json (Kabyle) 2024-08-20 18:38:09 +02:00
b0e7b86670 New translations en.json (Bengali, India) 2024-08-20 18:38:08 +02:00
723e1f7b78 New translations en.json (Occitan) 2024-08-20 18:38:07 +02:00
e6ac11c33d New translations en.json (Norwegian Bokmal) 2024-08-20 18:38:06 +02:00
fbc5f0460d New translations en.json (Uzbek) 2024-08-20 18:38:05 +02:00
4c81264c8c New translations en.json (Sinhala) 2024-08-20 18:38:04 +02:00
fd6750f4cf New translations en.json (Chinese Traditional, Hong Kong) 2024-08-20 18:38:02 +02:00
c5fed6cdf1 New translations en.json (Burmese) 2024-08-20 18:38:01 +02:00
4e9f6f3e0e New translations en.json (Hindi) 2024-08-20 18:38:00 +02:00
b9b37c2b33 New translations en.json (Azerbaijani) 2024-08-20 18:37:59 +02:00
679a293a18 New translations en.json (Latvian) 2024-08-20 18:37:58 +02:00
d51dca6c40 New translations en.json (Kazakh) 2024-08-20 18:37:57 +02:00
a0f0aaab05 New translations en.json (Norwegian Nynorsk) 2024-08-20 18:37:55 +02:00
5af4b4e7ce New translations en.json (Thai) 2024-08-20 18:37:54 +02:00
c688d4cbe4 New translations en.json (Marathi) 2024-08-20 18:37:53 +02:00
c98d4795fb New translations en.json (Bengali) 2024-08-20 18:37:52 +02:00
c3ceace600 New translations en.json (Tamil) 2024-08-20 18:37:51 +02:00
3dd2ef328c New translations en.json (Khmer) 2024-08-20 18:37:50 +02:00
1f75307d2f New translations en.json (Indonesian) 2024-08-20 18:37:48 +02:00
b1b1cacddf New translations en.json (Portuguese, Brazilian) 2024-08-20 18:37:47 +02:00
ed564b64ec New translations en.json (Galician) 2024-08-20 18:37:46 +02:00
6eb4c1e59f New translations en.json (Vietnamese) 2024-08-20 18:37:45 +02:00
4009c4d69c New translations en.json (Chinese Traditional) 2024-08-20 18:37:44 +02:00
c143334183 New translations en.json (Chinese Simplified) 2024-08-20 18:37:43 +02:00
bddacee80d New translations en.json (Ukrainian) 2024-08-20 18:37:42 +02:00
e6d5fa793d New translations en.json (Turkish) 2024-08-20 18:37:40 +02:00
ffc0752cba New translations en.json (Swedish) 2024-08-20 18:37:39 +02:00
a8de15517a New translations en.json (Slovenian) 2024-08-20 18:37:38 +02:00
a6fb388f5d New translations en.json (Slovak) 2024-08-20 18:37:37 +02:00
1a61e8f98a New translations en.json (Russian) 2024-08-20 18:37:35 +02:00
defbbc327c New translations en.json (Portuguese) 2024-08-20 18:37:34 +02:00
12f5d3c516 New translations en.json (Punjabi) 2024-08-20 18:37:33 +02:00
045f75161e New translations en.json (Dutch) 2024-08-20 18:37:32 +02:00
dfcbfaf155 New translations en.json (Lithuanian) 2024-08-20 18:37:31 +02:00
d233f3b60f New translations en.json (Kurdish) 2024-08-20 18:37:30 +02:00
b4e84e1cb9 New translations en.json (Korean) 2024-08-20 18:37:29 +02:00
630991b85a New translations en.json (Japanese) 2024-08-20 18:37:27 +02:00
2afbb7b0cd New translations en.json (Italian) 2024-08-20 18:37:26 +02:00
e95f4bd56a New translations en.json (Hungarian) 2024-08-20 18:37:25 +02:00
88b7830aa7 New translations en.json (Hebrew) 2024-08-20 18:37:24 +02:00
035d6b8b95 New translations en.json (Finnish) 2024-08-20 18:37:22 +02:00
d3f1d67e82 New translations en.json (Basque) 2024-08-20 18:37:21 +02:00
27b3e5ad99 New translations en.json (German) 2024-08-20 18:37:20 +02:00
7512deca3d New translations en.json (Danish) 2024-08-20 18:37:19 +02:00
66eaa610d1 New translations en.json (Czech) 2024-08-20 18:37:17 +02:00
6e4dcd4829 New translations en.json (Catalan) 2024-08-20 18:37:16 +02:00
d24c462d1c New translations en.json (Bulgarian) 2024-08-20 18:37:14 +02:00
070b693163 New translations en.json (Arabic) 2024-08-20 18:37:13 +02:00
12c697a67c New translations en.json (Spanish) 2024-08-20 18:37:11 +02:00
8e260bb8f0 New translations en.json (French) 2024-08-20 18:37:09 +02:00
62c096deb2 New translations en.json (Romanian) 2024-08-20 18:37:08 +02:00
afddbd88c6 New translations en.json (Greek) 2024-08-20 18:37:06 +02:00
e907c2cb98 New translations en.json (Polish) 2024-08-20 18:37:05 +02:00
4f1df9a3bf New translations en.json (German, Switzerland) 2024-08-20 18:37:03 +02:00
3ac658dd26 New translations en.json (Persian) 2024-08-20 18:37:01 +02:00
1c5581be0d New translations en.json (Portuguese) 2024-08-20 16:04:08 +02:00
6a0a34e0e7 New translations en.json (Vietnamese) 2024-08-18 16:30:42 +02:00
f560a7da67 New translations en.json (Greek) 2024-08-15 21:43:42 +02:00
2d4f69f83f New translations en.json (Chinese Simplified) 2024-08-13 07:18:53 +02:00
c124d99010 New translations en.json (Swedish) 2024-08-13 07:18:52 +02:00
59e5678151 New translations en.json (Polish) 2024-08-12 13:40:48 +02:00
a179dd38cf New translations en.json (Chinese Traditional) 2024-08-12 11:58:44 +02:00
e014ffb5b3 New translations en.json (Romanian) 2024-08-12 09:54:49 +02:00
21453a4858 New translations en.json (Slovenian) 2024-08-11 21:52:58 +02:00
58b78e0744 New translations en.json (German) 2024-08-11 21:52:57 +02:00
ba14b526ab New translations en.json (Polish) 2024-08-11 20:55:44 +02:00
3aacd5baba New translations en.json (Karakalpak) 2024-08-11 19:53:34 +02:00
4625f1f01a New translations en.json (Kabyle) 2024-08-11 19:53:33 +02:00
8395c84aa9 New translations en.json (Bengali, India) 2024-08-11 19:53:32 +02:00
ee6d0a2a2c New translations en.json (Occitan) 2024-08-11 19:53:31 +02:00
0d91a3ee98 New translations en.json (Norwegian Bokmal) 2024-08-11 19:53:30 +02:00
5036bac094 New translations en.json (Uzbek) 2024-08-11 19:53:29 +02:00
b82556aafd New translations en.json (Sinhala) 2024-08-11 19:53:27 +02:00
50d04b5802 New translations en.json (Chinese Traditional, Hong Kong) 2024-08-11 19:53:26 +02:00
fd917664e7 New translations en.json (Burmese) 2024-08-11 19:53:25 +02:00
b3da75f525 New translations en.json (Hindi) 2024-08-11 19:53:23 +02:00
93d61a66c1 New translations en.json (Azerbaijani) 2024-08-11 19:53:22 +02:00
bed4fb9556 New translations en.json (Latvian) 2024-08-11 19:53:21 +02:00
7567ea5b20 New translations en.json (Kazakh) 2024-08-11 19:53:20 +02:00
964c253fb8 New translations en.json (Norwegian Nynorsk) 2024-08-11 19:53:19 +02:00
dba1ac4ac6 New translations en.json (Thai) 2024-08-11 19:53:18 +02:00
f30f1e9eff New translations en.json (Marathi) 2024-08-11 19:53:17 +02:00
a74bbb0549 New translations en.json (Bengali) 2024-08-11 19:53:16 +02:00
b5cc1b4ee0 New translations en.json (Tamil) 2024-08-11 19:53:15 +02:00
3df2c55850 New translations en.json (Khmer) 2024-08-11 19:53:14 +02:00
0e0b3c62bb New translations en.json (Indonesian) 2024-08-11 19:53:13 +02:00
ef9b51b47c New translations en.json (Portuguese, Brazilian) 2024-08-11 19:53:12 +02:00
972db67e55 New translations en.json (Galician) 2024-08-11 19:53:10 +02:00
e61102d919 New translations en.json (Vietnamese) 2024-08-11 19:53:09 +02:00
460ea95712 New translations en.json (Chinese Traditional) 2024-08-11 19:53:08 +02:00
be199f7abb New translations en.json (Chinese Simplified) 2024-08-11 19:53:07 +02:00
710bffc99c New translations en.json (Ukrainian) 2024-08-11 19:53:06 +02:00
dec4acdf27 New translations en.json (Turkish) 2024-08-11 19:53:05 +02:00
dfd70691a9 New translations en.json (Swedish) 2024-08-11 19:53:04 +02:00
50f7c9d484 New translations en.json (Slovenian) 2024-08-11 19:53:03 +02:00
f755b09d0d New translations en.json (Slovak) 2024-08-11 19:53:02 +02:00
70db9f695d New translations en.json (Russian) 2024-08-11 19:53:01 +02:00
7523ef5869 New translations en.json (Portuguese) 2024-08-11 19:53:00 +02:00
b7bc8e43ff New translations en.json (Punjabi) 2024-08-11 19:52:59 +02:00
21c4bac6fc New translations en.json (Dutch) 2024-08-11 19:52:58 +02:00
e90f450bce New translations en.json (Lithuanian) 2024-08-11 19:52:57 +02:00
816d3b4b9f New translations en.json (Kurdish) 2024-08-11 19:52:56 +02:00
9c41187f82 New translations en.json (Korean) 2024-08-11 19:52:55 +02:00
24b3f87fb3 New translations en.json (Japanese) 2024-08-11 19:52:54 +02:00
acdae07f35 New translations en.json (Italian) 2024-08-11 19:52:53 +02:00
a8a67eee74 New translations en.json (Hungarian) 2024-08-11 19:52:52 +02:00
88fe797d83 New translations en.json (Hebrew) 2024-08-11 19:52:51 +02:00
d832cfdf71 New translations en.json (Finnish) 2024-08-11 19:52:50 +02:00
4af813173c New translations en.json (Basque) 2024-08-11 19:52:48 +02:00
ceeef17c00 New translations en.json (German) 2024-08-11 19:52:47 +02:00
90a609e7fb New translations en.json (Danish) 2024-08-11 19:52:46 +02:00
4091d1ef45 New translations en.json (Czech) 2024-08-11 19:52:45 +02:00
8bfbb60161 New translations en.json (Catalan) 2024-08-11 19:52:44 +02:00
cea8eb7c35 New translations en.json (Bulgarian) 2024-08-11 19:52:43 +02:00
339904c990 New translations en.json (Arabic) 2024-08-11 19:52:42 +02:00
05a087a83d New translations en.json (Spanish) 2024-08-11 19:52:41 +02:00
c82509b5d2 New translations en.json (French) 2024-08-11 19:52:41 +02:00
b8ba1918c9 New translations en.json (Romanian) 2024-08-11 19:52:40 +02:00
f12bf79694 New translations en.json (Greek) 2024-08-11 19:52:38 +02:00
0b276a371e New translations en.json (Polish) 2024-08-11 19:52:37 +02:00
0902c97806 New translations en.json (German, Switzerland) 2024-08-11 19:52:36 +02:00
32d460878d New translations en.json (Persian) 2024-08-11 19:52:35 +02:00
9a379fb81c New translations en.json (Slovak) 2024-08-11 09:14:17 +02:00
2f207b561a New translations en.json (Slovak) 2024-08-11 07:50:50 +02:00
14304f8402 New translations en.json (Romanian) 2024-08-10 18:30:16 +02:00
d9421730a4 New translations en.json (German) 2024-08-09 20:49:39 +02:00
fe71ee55c6 New translations en.json (Chinese Traditional) 2024-08-09 09:10:20 +02:00
8b9cfc82ea New translations en.json (Chinese Traditional) 2024-08-09 07:50:42 +02:00
2384ac65c3 New translations en.json (Karakalpak) 2024-08-08 23:39:51 +02:00
71d487762e New translations en.json (Kabyle) 2024-08-08 23:39:49 +02:00
089136d6e6 New translations en.json (Bengali, India) 2024-08-08 23:39:48 +02:00
f9955e079e New translations en.json (Occitan) 2024-08-08 23:39:47 +02:00
1471f87845 New translations en.json (Norwegian Bokmal) 2024-08-08 23:39:46 +02:00
9467d53088 New translations en.json (Uzbek) 2024-08-08 23:39:45 +02:00
20eec11057 New translations en.json (Sinhala) 2024-08-08 23:39:44 +02:00
49dd1c376f New translations en.json (Chinese Traditional, Hong Kong) 2024-08-08 23:39:43 +02:00
47b4cc67fc New translations en.json (Burmese) 2024-08-08 23:39:42 +02:00
b4707a1f9f New translations en.json (Hindi) 2024-08-08 23:39:41 +02:00
c79060a5a4 New translations en.json (Azerbaijani) 2024-08-08 23:39:40 +02:00
3881f18b01 New translations en.json (Latvian) 2024-08-08 23:39:38 +02:00
a0d5fbac19 New translations en.json (Kazakh) 2024-08-08 23:39:37 +02:00
56cb6e7b4f New translations en.json (Norwegian Nynorsk) 2024-08-08 23:39:36 +02:00
2cc02f02b1 New translations en.json (Thai) 2024-08-08 23:39:35 +02:00
8f790a65a6 New translations en.json (Marathi) 2024-08-08 23:39:34 +02:00
fcd7f8daf4 New translations en.json (Bengali) 2024-08-08 23:39:33 +02:00
6db4b713eb New translations en.json (Tamil) 2024-08-08 23:39:32 +02:00
f902a93ea1 New translations en.json (Khmer) 2024-08-08 23:39:31 +02:00
a5e07e633d New translations en.json (Indonesian) 2024-08-08 23:39:30 +02:00
484a10779b New translations en.json (Portuguese, Brazilian) 2024-08-08 23:39:29 +02:00
62a9a97323 New translations en.json (Galician) 2024-08-08 23:39:28 +02:00
37d581abb7 New translations en.json (Vietnamese) 2024-08-08 23:39:27 +02:00
036f973fa2 New translations en.json (Chinese Traditional) 2024-08-08 23:39:26 +02:00
f4eeb8038e New translations en.json (Chinese Simplified) 2024-08-08 23:39:24 +02:00
a29c8365d9 New translations en.json (Ukrainian) 2024-08-08 23:39:23 +02:00
5d420f54a7 New translations en.json (Turkish) 2024-08-08 23:39:22 +02:00
35f4ab615f New translations en.json (Swedish) 2024-08-08 23:39:21 +02:00
043eadf13c New translations en.json (Slovenian) 2024-08-08 23:39:20 +02:00
a24077c0be New translations en.json (Slovak) 2024-08-08 23:39:19 +02:00
f958c99a84 New translations en.json (Russian) 2024-08-08 23:39:18 +02:00
cca43eee02 New translations en.json (Portuguese) 2024-08-08 23:39:17 +02:00
0d6e9c9537 New translations en.json (Punjabi) 2024-08-08 23:39:16 +02:00
9c94ea1544 New translations en.json (Dutch) 2024-08-08 23:39:15 +02:00
fb6804fbd3 New translations en.json (Lithuanian) 2024-08-08 23:39:13 +02:00
68c6247272 New translations en.json (Kurdish) 2024-08-08 23:39:12 +02:00
18042a880d New translations en.json (Korean) 2024-08-08 23:39:11 +02:00
ac06d58d48 New translations en.json (Japanese) 2024-08-08 23:39:10 +02:00
05d462a07d New translations en.json (Italian) 2024-08-08 23:39:09 +02:00
ab26013d32 New translations en.json (Hungarian) 2024-08-08 23:39:08 +02:00
2dcb0ccc1a New translations en.json (Hebrew) 2024-08-08 23:39:07 +02:00
73f5f9ce9b New translations en.json (Finnish) 2024-08-08 23:39:06 +02:00
b4fcde00d1 New translations en.json (Basque) 2024-08-08 23:39:05 +02:00
9d1a01d56d New translations en.json (German) 2024-08-08 23:39:04 +02:00
f6375b77d5 New translations en.json (Danish) 2024-08-08 23:39:02 +02:00
ff1c9b3405 New translations en.json (Czech) 2024-08-08 23:39:01 +02:00
9465e45c97 New translations en.json (Catalan) 2024-08-08 23:39:00 +02:00
a573fe6b71 New translations en.json (Bulgarian) 2024-08-08 23:38:59 +02:00
98655e64d5 New translations en.json (Arabic) 2024-08-08 23:38:58 +02:00
d35214c11b New translations en.json (Spanish) 2024-08-08 23:38:57 +02:00
2f813d00ed New translations en.json (French) 2024-08-08 23:38:56 +02:00
580724793b New translations en.json (Romanian) 2024-08-08 23:38:55 +02:00
fcb9b36b96 New translations en.json (Greek) 2024-08-08 23:38:54 +02:00
18e37b3abf New translations en.json (Polish) 2024-08-08 23:38:53 +02:00
379977edbe New translations en.json (German, Switzerland) 2024-08-08 23:38:52 +02:00
bf061edb78 New translations en.json (Persian) 2024-08-08 23:38:51 +02:00
616f84bc22 New translations en.json (Romanian) 2024-08-05 08:20:26 +02:00
a16be8b5c5 New translations en.json (Chinese Traditional) 2024-08-04 18:10:36 +02:00
296e50678a New translations en.json (Chinese Traditional) 2024-08-04 16:52:27 +02:00
a6bfa82517 New translations en.json (Hindi) 2024-08-03 17:31:40 +02:00
050ba515d6 New translations en.json (Marathi) 2024-08-03 17:31:39 +02:00
d5f559803f New translations en.json (German) 2024-08-02 19:51:09 +02:00
d0e64458ad New translations en.json (Swedish) 2024-08-02 11:43:46 +02:00
7715aa6360 New translations en.json (Catalan) 2024-08-02 11:43:45 +02:00
12e196efee New translations en.json (Chinese Simplified) 2024-08-02 01:53:35 +02:00
bae2574225 New translations en.json (Russian) 2024-08-01 23:14:35 +02:00
3137d222ad New translations en.json (Greek) 2024-08-01 23:14:34 +02:00
4dd0273105 New translations en.json (Slovenian) 2024-08-01 21:17:21 +02:00
b52ed3425f New translations en.json (Karakalpak) 2024-08-01 20:17:19 +02:00
9ed6b2576d New translations en.json (Kabyle) 2024-08-01 20:17:18 +02:00
c5d0401fe1 New translations en.json (Bengali, India) 2024-08-01 20:17:17 +02:00
da352d54e3 New translations en.json (Occitan) 2024-08-01 20:17:16 +02:00
40acfd5a25 New translations en.json (Norwegian Bokmal) 2024-08-01 20:17:15 +02:00
469ab67b2b New translations en.json (Uzbek) 2024-08-01 20:17:13 +02:00
94c8ca8ced New translations en.json (Sinhala) 2024-08-01 20:17:12 +02:00
096d6cdb80 New translations en.json (Chinese Traditional, Hong Kong) 2024-08-01 20:17:11 +02:00
a35abe3398 New translations en.json (Burmese) 2024-08-01 20:17:10 +02:00
d987d60c14 New translations en.json (Hindi) 2024-08-01 20:17:09 +02:00
04c2778906 New translations en.json (Azerbaijani) 2024-08-01 20:17:07 +02:00
e823664f11 New translations en.json (Latvian) 2024-08-01 20:17:06 +02:00
e09532fd6d New translations en.json (Kazakh) 2024-08-01 20:17:05 +02:00
26126fd2a5 New translations en.json (Norwegian Nynorsk) 2024-08-01 20:17:04 +02:00
e8bdb88744 New translations en.json (Thai) 2024-08-01 20:17:02 +02:00
b91cebbe52 New translations en.json (Marathi) 2024-08-01 20:17:01 +02:00
90082d3c0d New translations en.json (Bengali) 2024-08-01 20:17:00 +02:00
de6f6e26c2 New translations en.json (Tamil) 2024-08-01 20:16:59 +02:00
8ae8cab963 New translations en.json (Khmer) 2024-08-01 20:16:57 +02:00
436fe171ca New translations en.json (Indonesian) 2024-08-01 20:16:56 +02:00
0f7f5e0f15 New translations en.json (Portuguese, Brazilian) 2024-08-01 20:16:55 +02:00
3da680ad39 New translations en.json (Galician) 2024-08-01 20:16:54 +02:00
91d688d60d New translations en.json (Vietnamese) 2024-08-01 20:16:52 +02:00
eea678f3c2 New translations en.json (Chinese Traditional) 2024-08-01 20:16:51 +02:00
87ddb85ce7 New translations en.json (German, Switzerland) 2024-08-01 20:16:50 +02:00
01619e0dba New translations en.json (Persian) 2024-08-01 20:16:49 +02:00
63289b016b New translations en.json (Chinese Simplified) 2024-08-01 20:16:48 +02:00
466bfc5808 New translations en.json (Ukrainian) 2024-08-01 20:16:46 +02:00
8509ad4ea8 New translations en.json (Turkish) 2024-08-01 20:16:45 +02:00
f607f3ff01 New translations en.json (Swedish) 2024-08-01 20:16:44 +02:00
ac4942e64a New translations en.json (Slovenian) 2024-08-01 20:16:43 +02:00
df32b9e73c New translations en.json (Slovak) 2024-08-01 20:16:42 +02:00
f924b05782 New translations en.json (Russian) 2024-08-01 20:16:40 +02:00
804e408f0b New translations en.json (Portuguese) 2024-08-01 20:16:39 +02:00
5cf811f565 New translations en.json (Punjabi) 2024-08-01 20:16:38 +02:00
b0e307af53 New translations en.json (Dutch) 2024-08-01 20:16:37 +02:00
2b64bea8b8 New translations en.json (Lithuanian) 2024-08-01 20:16:35 +02:00
b938a4eeca New translations en.json (Kurdish) 2024-08-01 20:16:34 +02:00
ce1babba5a New translations en.json (Korean) 2024-08-01 20:16:33 +02:00
bdedd55a41 New translations en.json (Japanese) 2024-08-01 20:16:32 +02:00
fefce6a17b New translations en.json (Italian) 2024-08-01 20:16:30 +02:00
a9f7c54c74 New translations en.json (Hungarian) 2024-08-01 20:16:29 +02:00
77bb5164ed New translations en.json (Hebrew) 2024-08-01 20:16:28 +02:00
aa50fcf3e5 New translations en.json (Finnish) 2024-08-01 20:16:26 +02:00
101616769f New translations en.json (Basque) 2024-08-01 20:16:25 +02:00
d86fc99a00 New translations en.json (German) 2024-08-01 20:16:24 +02:00
d2d1155b18 New translations en.json (Danish) 2024-08-01 20:16:23 +02:00
a96576d1b2 New translations en.json (Czech) 2024-08-01 20:16:22 +02:00
6d7f05414b New translations en.json (Catalan) 2024-08-01 20:16:21 +02:00
f23b6e9350 New translations en.json (Bulgarian) 2024-08-01 20:16:19 +02:00
391db4a941 New translations en.json (Arabic) 2024-08-01 20:16:18 +02:00
eccb403da1 New translations en.json (Spanish) 2024-08-01 20:16:17 +02:00
cd567c3d7e New translations en.json (French) 2024-08-01 20:16:16 +02:00
570d5c3f15 New translations en.json (Romanian) 2024-08-01 20:16:14 +02:00
f5a6dffa0b New translations en.json (Greek) 2024-08-01 20:16:13 +02:00
7507dad1de New translations en.json (Polish) 2024-08-01 20:16:12 +02:00
844b52eff6 New translations en.json (Russian) 2024-08-01 12:06:17 +02:00
1ce7dedf67 New translations en.json (Slovak) 2024-07-29 08:46:17 +02:00
47e3460a0b New translations en.json (Greek) 2024-07-27 23:56:49 +02:00
d8fbc3236e New translations en.json (French) 2024-07-27 22:55:43 +02:00
fb78fee714 New translations en.json (Greek) 2024-07-27 22:55:42 +02:00
27b7338fb8 New translations en.json (Greek) 2024-07-27 21:59:59 +02:00
439319d77b New translations en.json (Ukrainian) 2024-07-27 10:34:54 +02:00
49baa6e291 New translations en.json (Ukrainian) 2024-07-27 09:31:27 +02:00
04eac5ed57 New translations en.json (Chinese Traditional) 2024-07-26 13:44:07 +02:00
3635c88325 New translations en.json (Catalan) 2024-07-26 11:22:23 +02:00
8b4fdd368a New translations en.json (Romanian) 2024-07-26 08:23:59 +02:00
70303a9662 New translations en.json (Russian) 2024-07-25 22:12:04 +02:00
a6b5ee5f91 New translations en.json (German) 2024-07-25 22:12:03 +02:00
fad2dc5f57 New translations en.json (Slovenian) 2024-07-25 20:32:19 +02:00
ffb90b6adb New translations en.json (Karakalpak) 2024-07-25 19:06:18 +02:00
0c63d297bb New translations en.json (Kabyle) 2024-07-25 19:06:17 +02:00
0066c94a74 New translations en.json (Bengali, India) 2024-07-25 19:06:16 +02:00
6c995f172c New translations en.json (Occitan) 2024-07-25 19:06:15 +02:00
0fd575172f New translations en.json (Norwegian Bokmal) 2024-07-25 19:06:14 +02:00
f84766f497 New translations en.json (Uzbek) 2024-07-25 19:06:13 +02:00
2795a33335 New translations en.json (Sinhala) 2024-07-25 19:06:12 +02:00
dc07d39761 New translations en.json (Chinese Traditional, Hong Kong) 2024-07-25 19:06:10 +02:00
074ece4fa4 New translations en.json (Burmese) 2024-07-25 19:06:09 +02:00
affa10abe8 New translations en.json (Hindi) 2024-07-25 19:06:08 +02:00
68712692fb New translations en.json (Azerbaijani) 2024-07-25 19:06:07 +02:00
4764f661a3 New translations en.json (Latvian) 2024-07-25 19:06:06 +02:00
e79d4e8ce6 New translations en.json (Kazakh) 2024-07-25 19:06:05 +02:00
19ecdea035 New translations en.json (Norwegian Nynorsk) 2024-07-25 19:06:04 +02:00
0519f6de47 New translations en.json (Thai) 2024-07-25 19:06:02 +02:00
7407ae0f31 New translations en.json (Marathi) 2024-07-25 19:06:01 +02:00
887de107ef New translations en.json (Bengali) 2024-07-25 19:06:00 +02:00
1c471944d1 New translations en.json (Tamil) 2024-07-25 19:05:59 +02:00
69ee56a228 New translations en.json (Khmer) 2024-07-25 19:05:58 +02:00
5371082087 New translations en.json (Indonesian) 2024-07-25 19:05:57 +02:00
2709ccdb56 New translations en.json (Portuguese, Brazilian) 2024-07-25 19:05:56 +02:00
02361a92dc New translations en.json (Galician) 2024-07-25 19:05:54 +02:00
175c931ddc New translations en.json (Vietnamese) 2024-07-25 19:05:53 +02:00
350ba84864 New translations en.json (Chinese Traditional) 2024-07-25 19:05:52 +02:00
9cca06ac84 New translations en.json (Chinese Simplified) 2024-07-25 19:05:51 +02:00
5eb4a3a448 New translations en.json (Ukrainian) 2024-07-25 19:05:50 +02:00
e2a9974791 New translations en.json (Turkish) 2024-07-25 19:05:49 +02:00
40322d37b6 New translations en.json (Swedish) 2024-07-25 19:05:48 +02:00
e42426655d New translations en.json (Slovenian) 2024-07-25 19:05:47 +02:00
d6b0990e2d New translations en.json (Slovak) 2024-07-25 19:05:46 +02:00
54c1909b9e New translations en.json (Russian) 2024-07-25 19:05:45 +02:00
7c8daea65b New translations en.json (Portuguese) 2024-07-25 19:05:43 +02:00
9b6ba7ada6 New translations en.json (Punjabi) 2024-07-25 19:05:42 +02:00
df389c37a4 New translations en.json (Dutch) 2024-07-25 19:05:41 +02:00
b616db2ab5 New translations en.json (Lithuanian) 2024-07-25 19:05:40 +02:00
c43d16f435 New translations en.json (Kurdish) 2024-07-25 19:05:39 +02:00
9d9c65dcbd New translations en.json (Korean) 2024-07-25 19:05:38 +02:00
3b01f2cfd4 New translations en.json (Japanese) 2024-07-25 19:05:37 +02:00
e29d4cbbdc New translations en.json (Italian) 2024-07-25 19:05:36 +02:00
de73b0df95 New translations en.json (Hungarian) 2024-07-25 19:05:34 +02:00
bdca46fb3f New translations en.json (Hebrew) 2024-07-25 19:05:33 +02:00
89e7e0507f New translations en.json (Finnish) 2024-07-25 19:05:32 +02:00
1092769eaf New translations en.json (Basque) 2024-07-25 19:05:31 +02:00
76c95fadd9 New translations en.json (German) 2024-07-25 19:05:30 +02:00
40a945c5c6 New translations en.json (Danish) 2024-07-25 19:05:29 +02:00
fc029f1581 New translations en.json (Czech) 2024-07-25 19:05:28 +02:00
160e8c6f08 New translations en.json (Catalan) 2024-07-25 19:05:27 +02:00
52ac6020dc New translations en.json (Bulgarian) 2024-07-25 19:05:26 +02:00
966404b2fb New translations en.json (Arabic) 2024-07-25 19:05:25 +02:00
d151c8be9c New translations en.json (Spanish) 2024-07-25 19:05:24 +02:00
bf2852b46b New translations en.json (French) 2024-07-25 19:05:23 +02:00
8d9710795b New translations en.json (Romanian) 2024-07-25 19:05:22 +02:00
a706856b2a New translations en.json (Greek) 2024-07-25 19:05:21 +02:00
5362326d91 New translations en.json (Polish) 2024-07-25 19:05:20 +02:00
a450687669 New translations en.json (German, Switzerland) 2024-07-25 19:05:18 +02:00
ca31245625 New translations en.json (Persian) 2024-07-25 19:05:17 +02:00
ea14136124 New translations en.json (Greek) 2024-07-22 22:45:54 +02:00
69f0b70f65 New translations en.json (Greek) 2024-07-22 21:35:33 +02:00
6998bef4a5 New translations en.json (Polish) 2024-07-21 22:15:48 +02:00
ffbeee5e5e New translations en.json (Polish) 2024-07-21 21:09:52 +02:00
55a203a413 New translations en.json (German, Switzerland) 2024-07-12 10:20:12 +02:00
d6e91d4cdb New translations en.json (Persian) 2024-07-12 10:20:11 +02:00
b70bc98b4b New translations en.json (Slovak) 2024-07-06 13:31:55 +02:00
aaf30dc34e New translations en.json (Slovak) 2024-07-06 11:51:10 +02:00
d44e0071f0 New translations en.json (Bulgarian) 2024-07-05 12:26:22 +02:00
790f1a65dc New translations en.json (Bulgarian) 2024-07-05 10:24:50 +02:00
f7e809c756 New translations en.json (Turkish) 2024-06-29 05:14:14 +02:00
4ee7585115 New translations en.json (Turkish) 2024-06-29 04:12:41 +02:00
5a7dd4da43 New translations en.json (Hindi) 2024-06-24 08:46:30 +02:00
176030fe23 New translations en.json (Marathi) 2024-06-24 08:46:28 +02:00
ecd17e23b8 New translations en.json (Azerbaijani) 2024-06-18 09:10:44 +02:00
26df1db785 New translations en.json (Italian) 2024-06-18 09:10:43 +02:00
5666a0d027 New translations en.json (Azerbaijani) 2024-06-18 07:50:05 +02:00
43956387b6 Auto commit: Calculate translation coverage 2024-06-17 08:17:41 +00:00
a6c594a4fa New translations en.json (Hindi) 2024-06-17 10:17:25 +02:00
733c5881b0 New translations en.json (Marathi) 2024-06-17 10:17:24 +02:00
6017f5b5a3 Auto commit: Calculate translation coverage 2024-06-17 06:34:30 +00:00
db4c6f8901 New translations en.json (Marathi) 2024-06-17 08:34:15 +02:00
73d17e6c08 Auto commit: Calculate translation coverage 2024-06-15 20:24:58 +00:00
8bc520f05f New translations en.json (French) 2024-06-15 22:24:47 +02:00
8794935ecb Auto commit: Calculate translation coverage 2024-06-15 18:39:29 +00:00
9ec989fbef New translations en.json (French) 2024-06-15 20:39:15 +02:00
470fd2e90c Auto commit: Calculate translation coverage 2024-06-15 14:54:20 +00:00
67d9217c2c New translations en.json (Occitan) 2024-06-15 16:54:06 +02:00
fc5f238985 Auto commit: Calculate translation coverage 2024-06-14 19:33:56 +00:00
9442c0c9ed New translations en.json (Portuguese) 2024-06-14 21:33:43 +02:00
5afbf5a459 Auto commit: Calculate translation coverage 2024-06-13 20:16:52 +00:00
a8408a5344 New translations en.json (Chinese Traditional) 2024-06-13 22:16:40 +02:00
ecf5f2a472 Auto commit: Calculate translation coverage 2024-06-13 08:42:20 +00:00
66a635eea3 New translations en.json (Romanian) 2024-06-13 10:42:07 +02:00
316c8b85f8 Auto commit: Calculate translation coverage 2024-06-13 07:34:44 +00:00
7bfb114ca4 New translations en.json (Swedish) 2024-06-13 09:34:32 +02:00
8eddf43b93 New translations en.json (Slovenian) 2024-06-13 09:34:30 +02:00
e83a7b7f93 New translations en.json (Russian) 2024-06-13 09:34:29 +02:00
c370a5bfeb Auto commit: Calculate translation coverage 2024-06-13 05:11:57 +00:00
0a0edfa77d New translations en.json (Slovenian) 2024-06-13 07:11:44 +02:00
e49845e097 Auto commit: Calculate translation coverage 2024-06-13 00:39:11 +00:00
0cef729b9d New translations en.json (Chinese Simplified) 2024-06-13 02:38:57 +02:00
59f9d60230 Auto commit: Calculate translation coverage 2024-06-12 23:32:44 +00:00
8c93c24be5 New translations en.json (Spanish) 2024-06-13 01:32:32 +02:00
c31f1031ba Auto commit: Calculate translation coverage 2024-06-12 21:05:10 +00:00
033d32f2e9 New translations en.json (Occitan) 2024-06-12 23:04:31 +02:00
c9723ca98c Auto commit: Calculate translation coverage 2024-06-12 18:50:51 +00:00
018372206d New translations en.json (Karakalpak) 2024-06-12 20:49:18 +02:00
f55a873706 New translations en.json (Kabyle) 2024-06-12 20:49:17 +02:00
666ad7a867 New translations en.json (Bengali, India) 2024-06-12 20:49:16 +02:00
a032634c31 New translations en.json (Occitan) 2024-06-12 20:49:15 +02:00
a5c07896c0 New translations en.json (Norwegian Bokmal) 2024-06-12 20:49:13 +02:00
c169aebe71 New translations en.json (Uzbek) 2024-06-12 20:49:12 +02:00
24420ca3b0 New translations en.json (Sinhala) 2024-06-12 20:49:11 +02:00
9ac67ea8df New translations en.json (Chinese Traditional, Hong Kong) 2024-06-12 20:49:10 +02:00
23d2c69a7c New translations en.json (Burmese) 2024-06-12 20:49:09 +02:00
06adcc87d2 New translations en.json (Hindi) 2024-06-12 20:49:08 +02:00
8a0bf98c41 New translations en.json (Azerbaijani) 2024-06-12 20:49:06 +02:00
e50436e88c New translations en.json (Latvian) 2024-06-12 20:49:05 +02:00
dc1b99c4fd New translations en.json (Kazakh) 2024-06-12 20:49:04 +02:00
468c30792a New translations en.json (Norwegian Nynorsk) 2024-06-12 20:49:03 +02:00
a9d9457f58 New translations en.json (Thai) 2024-06-12 20:49:02 +02:00
fcc9f611db New translations en.json (Marathi) 2024-06-12 20:49:00 +02:00
ecdf65e937 New translations en.json (Bengali) 2024-06-12 20:48:59 +02:00
643c3da142 New translations en.json (Tamil) 2024-06-12 20:48:58 +02:00
0e7c995af6 New translations en.json (Khmer) 2024-06-12 20:48:57 +02:00
f1738bda97 New translations en.json (Persian) 2024-06-12 20:48:55 +02:00
ede64dc114 New translations en.json (Indonesian) 2024-06-12 20:48:54 +02:00
42938ac5c5 New translations en.json (Portuguese, Brazilian) 2024-06-12 20:48:53 +02:00
d7125c969f New translations en.json (Galician) 2024-06-12 20:48:52 +02:00
37535456c3 New translations en.json (Vietnamese) 2024-06-12 20:48:51 +02:00
afd2efafe4 New translations en.json (Chinese Traditional) 2024-06-12 20:48:50 +02:00
67e2a97bfb New translations en.json (Chinese Simplified) 2024-06-12 20:48:49 +02:00
8d4f5174b2 New translations en.json (Ukrainian) 2024-06-12 20:48:47 +02:00
271466015b New translations en.json (Turkish) 2024-06-12 20:48:46 +02:00
6b52e63c57 New translations en.json (Swedish) 2024-06-12 20:48:45 +02:00
dc5f07105f New translations en.json (Slovenian) 2024-06-12 20:48:44 +02:00
24ea232cdc New translations en.json (Russian) 2024-06-12 20:48:43 +02:00
49cac6ed74 New translations en.json (Portuguese) 2024-06-12 20:48:41 +02:00
680b26f069 New translations en.json (Polish) 2024-06-12 20:48:40 +02:00
cdc2920522 New translations en.json (Punjabi) 2024-06-12 20:48:39 +02:00
b52ff062f8 New translations en.json (Dutch) 2024-06-12 20:48:38 +02:00
1aed1d64f5 New translations en.json (Lithuanian) 2024-06-12 20:48:37 +02:00
971e09ccc2 New translations en.json (Kurdish) 2024-06-12 20:48:35 +02:00
aed3f16d61 New translations en.json (Korean) 2024-06-12 20:48:34 +02:00
56a6563bb3 New translations en.json (Japanese) 2024-06-12 20:48:33 +02:00
18366513e4 New translations en.json (Italian) 2024-06-12 20:48:32 +02:00
b7c5435de0 New translations en.json (Hungarian) 2024-06-12 20:48:31 +02:00
778f2fd540 New translations en.json (Hebrew) 2024-06-12 20:48:29 +02:00
4649bbd853 New translations en.json (Finnish) 2024-06-12 20:48:28 +02:00
572c1e3bba New translations en.json (Greek) 2024-06-12 20:48:27 +02:00
772b232f70 New translations en.json (German) 2024-06-12 20:48:26 +02:00
86ca8872f5 New translations en.json (Danish) 2024-06-12 20:48:24 +02:00
2e001220c0 New translations en.json (Czech) 2024-06-12 20:48:23 +02:00
edf1a62d92 New translations en.json (Catalan) 2024-06-12 20:48:22 +02:00
605d18b9c5 New translations en.json (Bulgarian) 2024-06-12 20:48:21 +02:00
834b254a4a New translations en.json (Arabic) 2024-06-12 20:48:20 +02:00
2513479221 New translations en.json (Spanish) 2024-06-12 20:48:19 +02:00
41bdf1634d New translations en.json (French) 2024-06-12 20:48:18 +02:00
4ff5f9ece3 New translations en.json (Romanian) 2024-06-12 20:48:17 +02:00
6d730443c8 New translations en.json (Basque) 2024-06-12 20:48:16 +02:00
f7d52c580e New translations en.json (Slovak) 2024-06-12 20:48:14 +02:00
f0bc165b62 Auto commit: Calculate translation coverage 2024-06-07 11:23:03 +00:00
d6950a5f88 New translations en.json (Basque) 2024-06-07 13:22:49 +02:00
07c5d52267 Auto commit: Calculate translation coverage 2024-05-31 16:03:00 +00:00
bac18cb22f New translations en.json (Slovak) 2024-05-31 18:02:47 +02:00
f7873520c5 Auto commit: Calculate translation coverage 2024-05-22 10:30:48 +00:00
1acac43403 New translations en.json (Portuguese) 2024-05-22 12:30:36 +02:00
3b6a48e955 Auto commit: Calculate translation coverage 2024-05-16 13:26:35 +00:00
ef51ebb020 New translations en.json (Polish) 2024-05-16 15:26:21 +02:00
05864777df Auto commit: Calculate translation coverage 2024-05-16 07:13:51 +00:00
c8b2916c4f New translations en.json (Romanian) 2024-05-16 09:13:38 +02:00
3f05e42578 Auto commit: Calculate translation coverage 2024-05-16 05:31:07 +00:00
26e046a102 New translations en.json (Swedish) 2024-05-16 07:30:54 +02:00
3fc76b9927 New translations en.json (Chinese Traditional) 2024-05-16 04:26:34 +02:00
85c71304ab Auto commit: Calculate translation coverage 2024-05-15 23:33:43 +00:00
f6ddf56967 New translations en.json (Chinese Simplified) 2024-05-16 01:33:28 +02:00
9a59a18033 Auto commit: Calculate translation coverage 2024-05-15 18:07:51 +00:00
f55dc10b1e New translations en.json (German) 2024-05-15 20:07:39 +02:00
7128c6ed6c Auto commit: Calculate translation coverage 2024-05-15 17:06:58 +00:00
b80290f1c0 New translations en.json (Slovenian) 2024-05-15 19:06:46 +02:00
8fb81d2140 Auto commit: Calculate translation coverage 2024-05-15 13:14:17 +00:00
7a2b187b5f New translations en.json (Karakalpak) 2024-05-15 15:10:41 +02:00
f1728c7889 New translations en.json (Kabyle) 2024-05-15 15:10:40 +02:00
97d6c921a1 New translations en.json (Bengali, India) 2024-05-15 15:10:39 +02:00
e13b82ebe1 New translations en.json (Occitan) 2024-05-15 15:10:37 +02:00
a72c4959b2 New translations en.json (Norwegian Bokmal) 2024-05-15 15:10:36 +02:00
739d947ea3 New translations en.json (Uzbek) 2024-05-15 15:10:35 +02:00
20e8af7298 New translations en.json (Sinhala) 2024-05-15 15:10:34 +02:00
6064aeea72 New translations en.json (Chinese Traditional, Hong Kong) 2024-05-15 15:10:33 +02:00
122f8540a0 New translations en.json (Burmese) 2024-05-15 15:10:31 +02:00
6f0c6ac307 New translations en.json (Hindi) 2024-05-15 15:10:30 +02:00
bf26f39c8e New translations en.json (Azerbaijani) 2024-05-15 15:10:29 +02:00
2d71df249f New translations en.json (Latvian) 2024-05-15 15:10:28 +02:00
2f96c7705e New translations en.json (Kazakh) 2024-05-15 15:10:27 +02:00
1ea422d4b0 New translations en.json (Norwegian Nynorsk) 2024-05-15 15:10:25 +02:00
fb519f5210 New translations en.json (Thai) 2024-05-15 15:10:24 +02:00
5488f8f053 New translations en.json (Marathi) 2024-05-15 15:10:23 +02:00
3e8297b923 New translations en.json (Bengali) 2024-05-15 15:10:22 +02:00
324ff7e6f9 New translations en.json (Tamil) 2024-05-15 15:10:21 +02:00
d5ec2c5036 New translations en.json (Khmer) 2024-05-15 15:10:19 +02:00
2267d52345 New translations en.json (Persian) 2024-05-15 15:10:18 +02:00
3adb3c3943 New translations en.json (Indonesian) 2024-05-15 15:10:17 +02:00
33c7fb9cc3 New translations en.json (Portuguese, Brazilian) 2024-05-15 15:10:16 +02:00
595d2ca370 New translations en.json (Galician) 2024-05-15 15:10:14 +02:00
5f588bb474 New translations en.json (Vietnamese) 2024-05-15 15:10:13 +02:00
96a190538d New translations en.json (Chinese Traditional) 2024-05-15 15:10:12 +02:00
2237e6be7b New translations en.json (Chinese Simplified) 2024-05-15 15:10:11 +02:00
6405585cf6 New translations en.json (Ukrainian) 2024-05-15 15:10:10 +02:00
3116bc4298 New translations en.json (Turkish) 2024-05-15 15:10:09 +02:00
8b7572d70e New translations en.json (Swedish) 2024-05-15 15:10:08 +02:00
d6b0cce4c9 New translations en.json (Slovenian) 2024-05-15 15:10:06 +02:00
f881130398 New translations en.json (Slovak) 2024-05-15 15:10:05 +02:00
266c4626be New translations en.json (Russian) 2024-05-15 15:10:03 +02:00
38290a4887 New translations en.json (Portuguese) 2024-05-15 15:10:02 +02:00
40b10faa7b New translations en.json (Polish) 2024-05-15 15:10:00 +02:00
a17a122951 New translations en.json (Punjabi) 2024-05-15 15:09:59 +02:00
0285684c9e New translations en.json (Dutch) 2024-05-15 15:09:58 +02:00
20c664d9aa New translations en.json (Lithuanian) 2024-05-15 15:09:57 +02:00
861e9fae97 New translations en.json (Kurdish) 2024-05-15 15:09:56 +02:00
d86b27e4cd New translations en.json (Korean) 2024-05-15 15:09:55 +02:00
75f127506e New translations en.json (Japanese) 2024-05-15 15:09:54 +02:00
4616455ce6 New translations en.json (Italian) 2024-05-15 15:09:53 +02:00
255e639ea5 New translations en.json (Hungarian) 2024-05-15 15:09:51 +02:00
1cb1325ee6 New translations en.json (Finnish) 2024-05-15 15:09:50 +02:00
ebe229c8ed New translations en.json (Basque) 2024-05-15 15:09:49 +02:00
63f972a889 New translations en.json (Greek) 2024-05-15 15:09:48 +02:00
e8e03145a3 New translations en.json (German) 2024-05-15 15:09:47 +02:00
d2db5fb4ed New translations en.json (Danish) 2024-05-15 15:09:46 +02:00
b9627e639e New translations en.json (Czech) 2024-05-15 15:09:45 +02:00
9f9678337e New translations en.json (Catalan) 2024-05-15 15:09:44 +02:00
ba5dc117a4 New translations en.json (Bulgarian) 2024-05-15 15:09:43 +02:00
a587e9ab58 New translations en.json (Arabic) 2024-05-15 15:09:42 +02:00
f93f3732f3 New translations en.json (Spanish) 2024-05-15 15:09:40 +02:00
128bc579ce New translations en.json (French) 2024-05-15 15:09:39 +02:00
0dd000ce7e New translations en.json (Romanian) 2024-05-15 15:09:38 +02:00
926d9e6884 New translations en.json (Hebrew) 2024-05-15 15:09:37 +02:00
04c46eb668 Auto commit: Calculate translation coverage 2024-05-13 06:43:28 +00:00
7e09d00d62 New translations en.json (Swedish) 2024-05-13 08:43:12 +02:00
7ef2a08dff Auto commit: Calculate translation coverage 2024-05-10 14:59:37 +00:00
ca6d0bb98a New translations en.json (Spanish) 2024-05-10 16:59:25 +02:00
b70393f947 Auto commit: Calculate translation coverage 2024-05-10 10:46:37 +00:00
df78472681 New translations en.json (French) 2024-05-10 12:46:26 +02:00
22d201d2c3 New translations en.json (Romanian) 2024-05-10 12:46:25 +02:00
3263596166 Auto commit: Calculate translation coverage 2024-05-10 09:07:24 +00:00
43302acd47 New translations en.json (French) 2024-05-10 11:07:14 +02:00
c92fb897b0 Auto commit: Calculate translation coverage 2024-05-09 21:37:35 +00:00
969cdb6fa5 New translations en.json (Portuguese) 2024-05-09 23:37:22 +02:00
b7c273dad3 New translations en.json (Italian) 2024-05-09 19:35:41 +02:00
6c392443fc New translations en.json (Chinese Traditional) 2024-05-09 16:06:43 +02:00
71800f2bdf Auto commit: Calculate translation coverage 2024-05-09 09:15:50 +00:00
81718fb708 New translations en.json (Chinese Simplified) 2024-05-09 11:15:37 +02:00
6420601d00 New translations en.json (Russian) 2024-05-09 11:15:36 +02:00
1ba7399adc New translations en.json (Polish) 2024-05-09 11:15:35 +02:00
2eacd8be18 New translations en.json (German) 2024-05-09 11:15:34 +02:00
f9055ae50e Auto commit: Calculate translation coverage 2024-05-09 07:35:38 +00:00
26718821c0 New translations en.json (Polish) 2024-05-09 09:35:22 +02:00
0339872a2c Auto commit: Calculate translation coverage 2024-05-09 06:31:00 +00:00
86758895fa New translations en.json (Slovenian) 2024-05-09 08:30:42 +02:00
6390aef437 Auto commit: Calculate translation coverage 2024-05-08 20:51:00 +00:00
f782ee3f0e New translations en.json (Karakalpak) 2024-05-08 22:46:17 +02:00
971b46bb0d New translations en.json (Kabyle) 2024-05-08 22:46:16 +02:00
cdda24b859 New translations en.json (Bengali, India) 2024-05-08 22:46:15 +02:00
bdcbdad7ed New translations en.json (Occitan) 2024-05-08 22:46:14 +02:00
ae955d24fa New translations en.json (Norwegian Bokmal) 2024-05-08 22:46:13 +02:00
1787fd8612 New translations en.json (Uzbek) 2024-05-08 22:46:12 +02:00
ea8e86e4a9 New translations en.json (Sinhala) 2024-05-08 22:46:11 +02:00
2965f7ba26 New translations en.json (Chinese Traditional, Hong Kong) 2024-05-08 22:46:10 +02:00
f5e156d0d3 New translations en.json (Burmese) 2024-05-08 22:46:09 +02:00
e14bb1fa3d New translations en.json (Hindi) 2024-05-08 22:46:07 +02:00
3d8b49f913 New translations en.json (Azerbaijani) 2024-05-08 22:46:06 +02:00
3e58bebc04 New translations en.json (Latvian) 2024-05-08 22:46:05 +02:00
69b7e9c80d New translations en.json (Kazakh) 2024-05-08 22:46:04 +02:00
812d27cc7f New translations en.json (Norwegian Nynorsk) 2024-05-08 22:46:03 +02:00
7d383e8c00 New translations en.json (Thai) 2024-05-08 22:46:02 +02:00
036c8c0f59 New translations en.json (Marathi) 2024-05-08 22:46:01 +02:00
c08d7a771c New translations en.json (Bengali) 2024-05-08 22:46:00 +02:00
3bcced5d69 New translations en.json (Tamil) 2024-05-08 22:45:59 +02:00
9d5c90b5af New translations en.json (Khmer) 2024-05-08 22:45:58 +02:00
404f9328b7 New translations en.json (Persian) 2024-05-08 22:45:57 +02:00
35b16fcd6d New translations en.json (Indonesian) 2024-05-08 22:45:56 +02:00
0d83490292 New translations en.json (Portuguese, Brazilian) 2024-05-08 22:45:55 +02:00
3c1c3bbdd7 New translations en.json (Galician) 2024-05-08 22:45:54 +02:00
cc6e945a04 New translations en.json (Vietnamese) 2024-05-08 22:45:53 +02:00
db6ddf6b7c New translations en.json (Chinese Traditional) 2024-05-08 22:45:52 +02:00
faca670156 New translations en.json (Chinese Simplified) 2024-05-08 22:45:51 +02:00
07f39be1ff New translations en.json (Ukrainian) 2024-05-08 22:45:50 +02:00
5e18fe4c7f New translations en.json (Turkish) 2024-05-08 22:45:49 +02:00
a8312ec874 New translations en.json (Swedish) 2024-05-08 22:45:48 +02:00
cef937c880 New translations en.json (Slovenian) 2024-05-08 22:45:46 +02:00
a8e903a3e9 New translations en.json (Slovak) 2024-05-08 22:45:45 +02:00
c57c830316 New translations en.json (Russian) 2024-05-08 22:45:44 +02:00
5b56bfe960 New translations en.json (Portuguese) 2024-05-08 22:45:43 +02:00
7e3eff3b23 New translations en.json (Polish) 2024-05-08 22:45:42 +02:00
43f42ee9f0 New translations en.json (Punjabi) 2024-05-08 22:45:41 +02:00
2674fae183 New translations en.json (Dutch) 2024-05-08 22:45:40 +02:00
17606e6180 New translations en.json (Lithuanian) 2024-05-08 22:45:39 +02:00
e5592d566e New translations en.json (Kurdish) 2024-05-08 22:45:38 +02:00
61768c9d81 New translations en.json (Korean) 2024-05-08 22:45:37 +02:00
65f4537bd0 New translations en.json (Japanese) 2024-05-08 22:45:36 +02:00
acd4eda04b New translations en.json (Italian) 2024-05-08 22:45:35 +02:00
b51369ad97 New translations en.json (Hungarian) 2024-05-08 22:45:34 +02:00
5b9ec81880 New translations en.json (Finnish) 2024-05-08 22:45:33 +02:00
91b71c8c45 New translations en.json (Basque) 2024-05-08 22:45:32 +02:00
cab7c52280 New translations en.json (Greek) 2024-05-08 22:45:31 +02:00
b1f1ae9570 New translations en.json (German) 2024-05-08 22:45:30 +02:00
79dec7adc7 New translations en.json (Danish) 2024-05-08 22:45:29 +02:00
6662cc6828 New translations en.json (Czech) 2024-05-08 22:45:28 +02:00
8511e6d42c New translations en.json (Catalan) 2024-05-08 22:45:27 +02:00
aa0c056b2f New translations en.json (Bulgarian) 2024-05-08 22:45:26 +02:00
bacfe9d327 New translations en.json (Arabic) 2024-05-08 22:45:25 +02:00
193b40ff12 New translations en.json (Spanish) 2024-05-08 22:45:24 +02:00
020b88c77a New translations en.json (French) 2024-05-08 22:45:23 +02:00
77726e6606 New translations en.json (Romanian) 2024-05-08 22:45:22 +02:00
1f055c0bda New translations en.json (Hebrew) 2024-05-08 22:45:21 +02:00
0189a75ff3 Auto commit: Calculate translation coverage 2024-05-08 19:33:58 +00:00
60d55753e9 New translations en.json (Portuguese) 2024-05-08 21:33:46 +02:00
c962575aec Auto commit: Calculate translation coverage 2024-05-08 10:49:45 +00:00
50da3e0873 New translations en.json (Romanian) 2024-05-08 12:49:33 +02:00
8b7a5511b7 Auto commit: Calculate translation coverage 2024-05-08 05:01:04 +00:00
572185898c New translations en.json (Tamil) 2024-05-08 07:00:51 +02:00
f6ea289a0e New translations en.json (Chinese Traditional) 2024-05-08 05:50:02 +02:00
dc9b065689 Auto commit: Calculate translation coverage 2024-05-07 19:33:43 +00:00
a448dc81c4 New translations en.json (German) 2024-05-07 21:33:32 +02:00
d82dae0776 Auto commit: Calculate translation coverage 2024-05-07 18:35:50 +00:00
0447ac624d New translations en.json (Tamil) 2024-05-07 20:35:37 +02:00
b9c040d9ac New translations en.json (Chinese Simplified) 2024-05-07 20:35:36 +02:00
fc926448ac New translations en.json (Spanish) 2024-05-07 19:40:01 +02:00
70d85530c7 Auto commit: Calculate translation coverage 2024-05-07 13:49:47 +00:00
96b515e2fe New translations en.json (Slovenian) 2024-05-07 15:49:36 +02:00
bced18876d New translations en.json (Russian) 2024-05-07 15:49:35 +02:00
1be9d67d8a Auto commit: Calculate translation coverage 2024-05-07 12:32:31 +00:00
bd21a2b57f New translations en.json (Karakalpak) 2024-05-07 14:30:33 +02:00
8cd33a127c New translations en.json (Kabyle) 2024-05-07 14:30:32 +02:00
19f15becfe New translations en.json (Bengali, India) 2024-05-07 14:30:30 +02:00
4f0e0407f1 New translations en.json (Occitan) 2024-05-07 14:30:29 +02:00
dc1f76988a New translations en.json (Norwegian Bokmal) 2024-05-07 14:30:28 +02:00
8289f3e0ed New translations en.json (Uzbek) 2024-05-07 14:30:27 +02:00
a5f517c0d4 New translations en.json (Sinhala) 2024-05-07 14:30:26 +02:00
3c2cd278f7 New translations en.json (Chinese Traditional, Hong Kong) 2024-05-07 14:30:24 +02:00
c77e248aee New translations en.json (Burmese) 2024-05-07 14:30:23 +02:00
2948341728 New translations en.json (Hindi) 2024-05-07 14:30:22 +02:00
9eaf570ae7 New translations en.json (Azerbaijani) 2024-05-07 14:30:20 +02:00
5d3637d157 New translations en.json (Latvian) 2024-05-07 14:30:19 +02:00
955af18a01 New translations en.json (Kazakh) 2024-05-07 14:30:18 +02:00
77d8fd5493 New translations en.json (Norwegian Nynorsk) 2024-05-07 14:30:17 +02:00
40e6f4a7f2 New translations en.json (Thai) 2024-05-07 14:30:16 +02:00
640d838e28 New translations en.json (Marathi) 2024-05-07 14:30:15 +02:00
aa02c7610e New translations en.json (Bengali) 2024-05-07 14:30:13 +02:00
d1179f5ada New translations en.json (Tamil) 2024-05-07 14:30:12 +02:00
6df2d19fbf New translations en.json (Khmer) 2024-05-07 14:30:11 +02:00
52ba265c71 New translations en.json (Persian) 2024-05-07 14:30:10 +02:00
00d9e244c2 New translations en.json (Indonesian) 2024-05-07 14:30:08 +02:00
ee0c58f797 New translations en.json (Portuguese, Brazilian) 2024-05-07 14:30:07 +02:00
2fd1d1c371 New translations en.json (Galician) 2024-05-07 14:30:06 +02:00
7a51bc7f5d New translations en.json (Vietnamese) 2024-05-07 14:30:05 +02:00
28b61d73c8 New translations en.json (Chinese Traditional) 2024-05-07 14:30:03 +02:00
f8af81fb65 New translations en.json (Chinese Simplified) 2024-05-07 14:30:02 +02:00
d474fdd404 New translations en.json (Ukrainian) 2024-05-07 14:30:00 +02:00
1afd2d4030 New translations en.json (Turkish) 2024-05-07 14:29:59 +02:00
94bc8dd018 New translations en.json (Swedish) 2024-05-07 14:29:58 +02:00
f3e85108a8 New translations en.json (Slovenian) 2024-05-07 14:29:57 +02:00
149a7fc32b New translations en.json (Slovak) 2024-05-07 14:29:56 +02:00
7094c4c9b6 New translations en.json (Russian) 2024-05-07 14:29:55 +02:00
e7fb9494cb New translations en.json (Portuguese) 2024-05-07 14:29:53 +02:00
b335a96722 New translations en.json (Polish) 2024-05-07 14:29:52 +02:00
18f539c709 New translations en.json (Punjabi) 2024-05-07 14:29:51 +02:00
2bd173501c New translations en.json (Dutch) 2024-05-07 14:29:50 +02:00
27c47513e8 New translations en.json (Lithuanian) 2024-05-07 14:29:49 +02:00
bafd3d669b New translations en.json (Kurdish) 2024-05-07 14:29:48 +02:00
d9a3ec2680 New translations en.json (Korean) 2024-05-07 14:29:47 +02:00
b28f7b9b81 New translations en.json (Japanese) 2024-05-07 14:29:45 +02:00
f35b909ba9 New translations en.json (Italian) 2024-05-07 14:29:44 +02:00
dbe71af81a New translations en.json (Hungarian) 2024-05-07 14:29:43 +02:00
8a94fd0baf New translations en.json (Finnish) 2024-05-07 14:29:42 +02:00
b9a4bcb4fc New translations en.json (Basque) 2024-05-07 14:29:41 +02:00
11f6dd674c New translations en.json (Greek) 2024-05-07 14:29:40 +02:00
edfdf8ad21 New translations en.json (German) 2024-05-07 14:29:39 +02:00
40a4928f6e New translations en.json (Danish) 2024-05-07 14:29:38 +02:00
b35257ab5b New translations en.json (Czech) 2024-05-07 14:29:36 +02:00
4b9f2a722d New translations en.json (Catalan) 2024-05-07 14:29:35 +02:00
7c88a7c48b New translations en.json (Bulgarian) 2024-05-07 14:29:34 +02:00
a8adca5d98 New translations en.json (Arabic) 2024-05-07 14:29:33 +02:00
ee88a62da8 New translations en.json (Spanish) 2024-05-07 14:29:32 +02:00
acb23a5a7a New translations en.json (French) 2024-05-07 14:29:30 +02:00
1b63aa136b New translations en.json (Romanian) 2024-05-07 14:29:29 +02:00
cea3bb9764 New translations en.json (Hebrew) 2024-05-07 14:29:28 +02:00
1840949a81 Auto commit: Calculate translation coverage 2024-04-23 20:54:02 +00:00
b6678560ec New translations en.json (Hebrew) 2024-04-23 22:53:48 +02:00
01c144de36 Auto commit: Calculate translation coverage 2024-04-23 19:31:24 +00:00
5f387aeed1 New translations en.json (Hebrew) 2024-04-23 21:31:12 +02:00
1faad458f6 Auto commit: Calculate translation coverage 2024-04-22 15:39:31 +00:00
3357340772 New translations en.json (Bengali, India) 2024-04-22 17:39:12 +02:00
053606e460 New translations en.json (Bengali) 2024-04-22 17:39:11 +02:00
280bbc3e58 Auto commit: Calculate translation coverage 2024-04-22 14:43:54 +00:00
6adf3eb827 New translations en.json (Bengali) 2024-04-22 16:43:40 +02:00
2259ea6e80 Auto commit: Calculate translation coverage 2024-04-17 15:16:08 +00:00
51eec9d02c New translations en.json (Finnish) 2024-04-17 17:15:54 +02:00
6dcfe61f2e Auto commit: Calculate translation coverage 2024-04-16 11:45:30 +00:00
066bcddc82 New translations en.json (Portuguese) 2024-04-16 13:45:15 +02:00
67866e70cf Auto commit: Calculate translation coverage 2024-04-15 13:28:35 +00:00
3509c2e812 New translations en.json (Arabic) 2024-04-15 15:28:23 +02:00
4f0ea27632 Auto commit: Calculate translation coverage 2024-04-15 12:14:28 +00:00
5eb7b5a63e New translations en.json (Arabic) 2024-04-15 14:14:10 +02:00
865576946c Auto commit: Calculate translation coverage 2024-04-15 10:53:28 +00:00
5a376e0015 New translations en.json (Romanian) 2024-04-15 12:53:17 +02:00
d34d43d730 Auto commit: Calculate translation coverage 2024-04-15 05:38:15 +00:00
f7b4d9d424 New translations en.json (Swedish) 2024-04-15 07:38:04 +02:00
10b7e96c00 Auto commit: Calculate translation coverage 2024-04-13 21:41:12 +00:00
a5c09041e9 New translations en.json (Chinese Simplified) 2024-04-13 23:40:59 +02:00
c46e268ad0 Auto commit: Calculate translation coverage 2024-04-13 20:27:01 +00:00
5b6ce786a1 New translations en.json (Chinese Traditional) 2024-04-13 22:26:47 +02:00
70a2ccb51a New translations en.json (German) 2024-04-13 22:26:46 +02:00
a89a072cb4 Auto commit: Calculate translation coverage 2024-04-13 17:59:17 +00:00
65c040c075 New translations en.json (Karakalpak) 2024-04-13 19:55:18 +02:00
39b9e1e7a0 New translations en.json (Kabyle) 2024-04-13 19:55:17 +02:00
cb3050294b New translations en.json (Occitan) 2024-04-13 19:55:16 +02:00
455eeb63b4 New translations en.json (Norwegian Bokmal) 2024-04-13 19:55:15 +02:00
be4eb1e37e New translations en.json (Uzbek) 2024-04-13 19:55:14 +02:00
f3ff017e6f New translations en.json (Sinhala) 2024-04-13 19:55:13 +02:00
56c18f44c7 New translations en.json (Chinese Traditional, Hong Kong) 2024-04-13 19:55:12 +02:00
da2695ac35 New translations en.json (Burmese) 2024-04-13 19:55:11 +02:00
5614f1c62f New translations en.json (Azerbaijani) 2024-04-13 19:55:09 +02:00
b7d9e49039 New translations en.json (Latvian) 2024-04-13 19:55:08 +02:00
4da5b9e7b6 New translations en.json (Kazakh) 2024-04-13 19:55:07 +02:00
81958d4a3d New translations en.json (Norwegian Nynorsk) 2024-04-13 19:55:06 +02:00
12a7eb4885 New translations en.json (Thai) 2024-04-13 19:55:05 +02:00
dffc310969 New translations en.json (Marathi) 2024-04-13 19:55:05 +02:00
80ad916f4f New translations en.json (Bengali) 2024-04-13 19:55:04 +02:00
d216420f30 New translations en.json (Tamil) 2024-04-13 19:55:03 +02:00
4cf68fa98f New translations en.json (Khmer) 2024-04-13 19:55:02 +02:00
2996eb0bb5 New translations en.json (Persian) 2024-04-13 19:55:01 +02:00
422e6ad51e New translations en.json (Indonesian) 2024-04-13 19:55:00 +02:00
922675bf53 New translations en.json (Portuguese, Brazilian) 2024-04-13 19:54:59 +02:00
d92f555e93 New translations en.json (Galician) 2024-04-13 19:54:58 +02:00
48433bc9eb New translations en.json (Vietnamese) 2024-04-13 19:54:57 +02:00
db3f73c643 New translations en.json (Chinese Traditional) 2024-04-13 19:54:57 +02:00
ad0f8155a7 New translations en.json (Ukrainian) 2024-04-13 19:54:56 +02:00
060eee3afd New translations en.json (Turkish) 2024-04-13 19:54:55 +02:00
407ef4699d New translations en.json (Slovenian) 2024-04-13 19:54:54 +02:00
1ffb358d59 New translations en.json (Russian) 2024-04-13 19:54:53 +02:00
d9c4e12642 New translations en.json (Portuguese) 2024-04-13 19:54:52 +02:00
310f561488 New translations en.json (Polish) 2024-04-13 19:54:51 +02:00
dcd3636c96 New translations en.json (Punjabi) 2024-04-13 19:54:50 +02:00
a5442f8b7a New translations en.json (Dutch) 2024-04-13 19:54:50 +02:00
1dc32d9e0a New translations en.json (Lithuanian) 2024-04-13 19:54:49 +02:00
a767150e87 New translations en.json (Kurdish) 2024-04-13 19:54:48 +02:00
9691492f38 New translations en.json (Korean) 2024-04-13 19:54:47 +02:00
2f52f28631 New translations en.json (Japanese) 2024-04-13 19:54:46 +02:00
e0bef262a7 New translations en.json (Hungarian) 2024-04-13 19:54:45 +02:00
4cffdf216d New translations en.json (Hebrew) 2024-04-13 19:54:44 +02:00
2628d6807c New translations en.json (Finnish) 2024-04-13 19:54:43 +02:00
3e1012b080 New translations en.json (Basque) 2024-04-13 19:54:43 +02:00
6e575f2f8b New translations en.json (Greek) 2024-04-13 19:54:42 +02:00
ec7fa95672 New translations en.json (German) 2024-04-13 19:54:41 +02:00
753f492c86 New translations en.json (Danish) 2024-04-13 19:54:40 +02:00
8b04af03a1 New translations en.json (Czech) 2024-04-13 19:54:39 +02:00
8830f1138d New translations en.json (Catalan) 2024-04-13 19:54:38 +02:00
4567a16d65 New translations en.json (Bulgarian) 2024-04-13 19:54:37 +02:00
19eaf8240a New translations en.json (Arabic) 2024-04-13 19:54:36 +02:00
4a519f47b5 New translations en.json (Spanish) 2024-04-13 19:54:35 +02:00
edebbffe33 New translations en.json (French) 2024-04-13 19:54:34 +02:00
156285417b New translations en.json (Romanian) 2024-04-13 19:54:33 +02:00
cefc312e85 New translations en.json (Hindi) 2024-04-13 19:54:32 +02:00
c63d5da9e1 New translations en.json (Chinese Simplified) 2024-04-13 19:54:31 +02:00
a934d975e7 New translations en.json (Swedish) 2024-04-13 19:54:30 +02:00
f391e7b11a New translations en.json (Slovak) 2024-04-13 19:54:29 +02:00
7f93f19314 New translations en.json (Italian) 2024-04-13 19:54:29 +02:00
cb1454f8db Merge branch 'master' into l10n_master 2024-04-13 18:52:39 +02:00
da2e507298 fix: allow same origin for all necessary domains (#7889) 2024-04-13 18:51:30 +02:00
df4660c0c1 Auto commit: Calculate translation coverage 2024-04-13 12:29:26 +00:00
8751b38988 New translations en.json (Slovak) 2024-04-13 14:29:12 +02:00
f59b4f6af4 fix: always make sure we render bound text above containers (#7880) 2024-04-12 21:50:02 +02:00
afcde542f9 fix: parse embeddable srcdoc urls strictly (#7884) 2024-04-12 20:51:17 +02:00
4689a6b300 fix: hit test for closed sharp curves (#7881) 2024-04-12 12:58:51 +02:00
0ae9b383d6 fix: Gist embed allowing unsafe html (#7883) 2024-04-12 12:57:43 +02:00
f597bd3e01 fix: command palette tweaks and fixes (#7876) 2024-04-11 11:39:19 +02:00
4987cc53d0 fix: include borders when testing insides of a shape (#7865) 2024-04-09 16:07:36 +02:00
d917db438e fix: external link not opening (#7859) 2024-04-09 16:06:49 +02:00
287836fc6b Auto commit: Calculate translation coverage 2024-04-09 08:38:48 +00:00
4635477f37 New translations en.json (Swedish) 2024-04-09 10:38:34 +02:00
89f77ea24a Auto commit: Calculate translation coverage 2024-04-09 04:32:41 +00:00
3dc38ab06e New translations en.json (Chinese Simplified) 2024-04-09 06:32:30 +02:00
a33a400f01 fix: add safe check for arrow points length in tranformToExcalidrawElements (#7863)
* fix: add safe check for arrow points length in tranformToExcalidrawElements

* add spec

* throw error only for dev mode

* fix lint
2024-04-09 09:56:21 +05:30
66a2dcdedc Auto commit: Calculate translation coverage 2024-04-09 03:32:30 +00:00
fddea948f0 New translations en.json (Marathi) 2024-04-09 05:32:14 +02:00
229ab44918 New translations en.json (Hindi) 2024-04-09 05:32:13 +02:00
a6a958de55 New translations en.json (Chinese Traditional) 2024-04-08 21:16:08 +02:00
c3969dcf12 Auto commit: Calculate translation coverage 2024-04-08 18:06:08 +00:00
d906fe2531 New translations en.json (German) 2024-04-08 20:05:52 +02:00
3eaa573951 Auto commit: Calculate translation coverage 2024-04-08 16:49:55 +00:00
50f98d193d New translations en.json (Slovenian) 2024-04-08 18:49:21 +02:00
7104d7bf17 New translations en.json (Romanian) 2024-04-08 18:49:20 +02:00
8a162a4cb4 fix: import (#7869) 2024-04-08 16:59:03 +02:00
9403ef8656 Auto commit: Calculate translation coverage 2024-04-08 14:55:38 +00:00
c6a045d092 fix: theme toggle shortcut event.code (#7868) 2024-04-08 16:55:33 +02:00
092263b6b1 New translations en.json (Karakalpak) 2024-04-08 16:51:11 +02:00
6adb44ead4 New translations en.json (Kabyle) 2024-04-08 16:51:10 +02:00
b71cbe8352 New translations en.json (Occitan) 2024-04-08 16:51:09 +02:00
576cb578b0 New translations en.json (Norwegian Bokmal) 2024-04-08 16:51:08 +02:00
7198a613dd New translations en.json (Uzbek) 2024-04-08 16:51:07 +02:00
24d4eafbd0 New translations en.json (Sinhala) 2024-04-08 16:51:06 +02:00
8b52f043d5 New translations en.json (Chinese Traditional, Hong Kong) 2024-04-08 16:51:05 +02:00
6e2c5d7e82 New translations en.json (Burmese) 2024-04-08 16:51:04 +02:00
ae82cf1704 New translations en.json (Azerbaijani) 2024-04-08 16:51:03 +02:00
1e0f54b4df New translations en.json (Latvian) 2024-04-08 16:51:02 +02:00
4624dd5041 New translations en.json (Kazakh) 2024-04-08 16:51:01 +02:00
1e54ae0825 New translations en.json (Norwegian Nynorsk) 2024-04-08 16:50:59 +02:00
6bfc4b7212 New translations en.json (Thai) 2024-04-08 16:50:58 +02:00
81634d45e4 New translations en.json (Marathi) 2024-04-08 16:50:57 +02:00
cd1c9391f1 New translations en.json (Bengali) 2024-04-08 16:50:56 +02:00
726ccccb1c New translations en.json (Tamil) 2024-04-08 16:50:55 +02:00
74942af896 New translations en.json (Khmer) 2024-04-08 16:50:54 +02:00
89e52da2fe New translations en.json (Persian) 2024-04-08 16:50:53 +02:00
fcf153e420 New translations en.json (Indonesian) 2024-04-08 16:50:52 +02:00
c22f0896b7 New translations en.json (Portuguese, Brazilian) 2024-04-08 16:50:51 +02:00
b3bf5a215f New translations en.json (Galician) 2024-04-08 16:50:51 +02:00
5a0066ab52 New translations en.json (Vietnamese) 2024-04-08 16:50:49 +02:00
b85c365aa9 New translations en.json (Chinese Traditional) 2024-04-08 16:50:49 +02:00
7b1eaf3f48 New translations en.json (Ukrainian) 2024-04-08 16:50:48 +02:00
16cb262a26 New translations en.json (Turkish) 2024-04-08 16:50:46 +02:00
35e2663504 New translations en.json (Slovenian) 2024-04-08 16:50:44 +02:00
81aaa909af New translations en.json (Russian) 2024-04-08 16:50:43 +02:00
976384a0a7 New translations en.json (Portuguese) 2024-04-08 16:50:42 +02:00
e989f1ff6c New translations en.json (Polish) 2024-04-08 16:50:41 +02:00
4237138392 New translations en.json (Punjabi) 2024-04-08 16:50:40 +02:00
192b67ee73 New translations en.json (Dutch) 2024-04-08 16:50:39 +02:00
7e2c567e33 New translations en.json (Lithuanian) 2024-04-08 16:50:38 +02:00
0659407aa8 New translations en.json (Kurdish) 2024-04-08 16:50:37 +02:00
c2f5ac17a7 New translations en.json (Korean) 2024-04-08 16:50:36 +02:00
ab7c9a4106 New translations en.json (Japanese) 2024-04-08 16:50:35 +02:00
e9e5671356 New translations en.json (Hungarian) 2024-04-08 16:50:34 +02:00
f447cbcc9f New translations en.json (Hebrew) 2024-04-08 16:50:33 +02:00
cea81f15a7 New translations en.json (Finnish) 2024-04-08 16:50:32 +02:00
bae392ce50 New translations en.json (Basque) 2024-04-08 16:50:31 +02:00
5eea304b1d New translations en.json (Greek) 2024-04-08 16:50:30 +02:00
dba82deef4 New translations en.json (German) 2024-04-08 16:50:29 +02:00
14a64cad6e New translations en.json (Danish) 2024-04-08 16:50:28 +02:00
bf73490b78 New translations en.json (Czech) 2024-04-08 16:50:27 +02:00
50462b4956 New translations en.json (Catalan) 2024-04-08 16:50:26 +02:00
64087e6055 New translations en.json (Bulgarian) 2024-04-08 16:50:25 +02:00
8933a677c0 New translations en.json (Arabic) 2024-04-08 16:50:24 +02:00
ac487862e9 New translations en.json (Spanish) 2024-04-08 16:50:23 +02:00
6202f38f70 New translations en.json (French) 2024-04-08 16:50:22 +02:00
a4779bfe73 New translations en.json (Romanian) 2024-04-08 16:50:21 +02:00
40874a88ef New translations en.json (Hindi) 2024-04-08 16:50:20 +02:00
88f6c86c9e New translations en.json (Chinese Simplified) 2024-04-08 16:50:19 +02:00
55bc4a6365 New translations en.json (Swedish) 2024-04-08 16:50:18 +02:00
3fb6ab5e45 New translations en.json (Slovak) 2024-04-08 16:50:17 +02:00
44d7db20e6 New translations en.json (Italian) 2024-04-08 16:50:16 +02:00
cd50aa719f feat: add system mode to the theme selector (#7853)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-04-08 16:46:24 +02:00
92bc08207c fix: remove incorrect check from index.html (#7867) 2024-04-08 16:42:00 +02:00
8ffed1b059 Auto commit: Calculate translation coverage 2024-04-08 09:51:23 +00:00
5cae67c1cb New translations en.json (Vietnamese) 2024-04-08 11:51:09 +02:00
32df5502ae feat: fractional indexing (#7359)
* Introducing fractional indices as part of `element.index`

* Ensuring invalid fractional indices are always synchronized with the array order

* Simplifying reconciliation based on the fractional indices

* Moving reconciliation inside the `@excalidraw/excalidraw` package

---------

Co-authored-by: Marcel Mraz <marcel@excalidraw.com>
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-04-04 13:51:11 +01:00
bbdcd30a73 refactor: update collision from ga to vector geometry (#7636)
* new collision api

* isPointOnShape

* removed redundant code

* new collision methods in app

* curve shape takes starting point

* clean up geometry

* curve rotation

* freedraw

* inside curve

* improve ellipse inside check

* ellipse distance func

* curve inside

* include frame name bounds

* replace previous private methods for getting elements at x,y

* arrow bound text hit detection

* keep iframes on top

* remove dependence on old collision methods from app

* remove old collision functions

* move some hit functions outside of app

* code refactor

* type

* text collision from inside

* fix context menu test

* highest z-index collision

* fix 1px away binding test

* strictly less

* remove unused imports

* lint

* 'ignore' resize flipping test

* more lint fix

* skip 'flips while resizing' test

* more test

* fix merge errors

* fix selection in resize test

* added a bit more comment

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-04-04 16:31:23 +08:00
4c04ce1c48 Auto commit: Calculate translation coverage 2024-04-03 13:45:31 +00:00
a464402919 New translations en.json (Hebrew) 2024-04-03 15:45:17 +02:00
be18f35595 Auto commit: Calculate translation coverage 2024-04-03 12:16:58 +00:00
b4f9ee520a New translations en.json (Hebrew) 2024-04-03 14:16:29 +02:00
455153d728 Auto commit: Calculate translation coverage 2024-04-01 06:34:04 +00:00
1353ef62b8 New translations en.json (Marathi) 2024-04-01 08:33:49 +02:00
6fad1e745a New translations en.json (Hindi) 2024-04-01 08:33:48 +02:00
2c988961f7 New translations en.json (Marathi) 2024-04-01 07:08:38 +02:00
2cd9a7697f New translations en.json (Hindi) 2024-04-01 07:08:37 +02:00
d398528493 Auto commit: Calculate translation coverage 2024-03-30 11:18:17 +00:00
59fe6e7b6d New translations en.json (Marathi) 2024-03-30 12:18:05 +01:00
abaf858f6c Auto commit: Calculate translation coverage 2024-03-29 14:45:52 +00:00
949c5b7af1 New translations en.json (Marathi) 2024-03-29 15:45:40 +01:00
701eb7f9fd Auto commit: Calculate translation coverage 2024-03-29 10:31:55 +00:00
07d92f720b New translations en.json (Catalan) 2024-03-29 11:31:42 +01:00
d16b808bb9 Auto commit: Calculate translation coverage 2024-03-29 09:27:55 +00:00
b2e09157da New translations en.json (Chinese Traditional) 2024-03-29 10:27:44 +01:00
93ee60cd9b New translations en.json (Romanian) 2024-03-29 10:27:43 +01:00
9eb509e068 New translations en.json (Chinese Simplified) 2024-03-29 10:27:42 +01:00
89f3dfb399 New translations en.json (Slovak) 2024-03-29 10:27:41 +01:00
a4c9355b03 Auto commit: Calculate translation coverage 2024-03-29 07:56:59 +00:00
c79cdab613 New translations en.json (Chinese Traditional) 2024-03-29 08:56:48 +01:00
ae3735a150 Auto commit: Calculate translation coverage 2024-03-29 04:28:08 +00:00
38a5c6c01a New translations en.json (Russian) 2024-03-29 05:27:57 +01:00
68caccfc2a Auto commit: Calculate translation coverage 2024-03-29 01:11:19 +00:00
9482c7adc6 New translations en.json (Swedish) 2024-03-29 02:11:07 +01:00
ff23a04e27 Auto commit: Calculate translation coverage 2024-03-29 00:01:13 +00:00
9ea989ee2a New translations en.json (Swedish) 2024-03-29 01:01:01 +01:00
261bff5bea Auto commit: Calculate translation coverage 2024-03-28 21:45:56 +00:00
55740254ed New translations en.json (German) 2024-03-28 22:45:44 +01:00
acb4da9f5c Auto commit: Calculate translation coverage 2024-03-28 20:46:08 +00:00
78131cf48b New translations en.json (Occitan) 2024-03-28 21:45:52 +01:00
415d5d6f6a Auto commit: Calculate translation coverage 2024-03-28 19:44:22 +00:00
0789a3db47 New translations en.json (Slovenian) 2024-03-28 20:44:05 +01:00
7218ddea85 Auto commit: Calculate translation coverage 2024-03-28 18:27:06 +00:00
e94ca414fb New translations en.json (Slovenian) 2024-03-28 19:26:45 +01:00
2b374bfa3d New translations en.json (German) 2024-03-28 19:26:36 +01:00
3e334a67ed feat: show firefox-compatible command palette shortcut alias (#7825) 2024-03-28 18:12:54 +01:00
a140db6244 Auto commit: Calculate translation coverage 2024-03-28 17:01:41 +00:00
07c0753d38 New translations en.json (Karakalpak) 2024-03-28 18:00:31 +01:00
26f3b861d7 New translations en.json (Kabyle) 2024-03-28 18:00:30 +01:00
f115a98333 New translations en.json (Occitan) 2024-03-28 18:00:29 +01:00
f45779c41c New translations en.json (Norwegian Bokmal) 2024-03-28 18:00:28 +01:00
8446097251 New translations en.json (Uzbek) 2024-03-28 18:00:27 +01:00
812dfcf633 New translations en.json (Sinhala) 2024-03-28 18:00:26 +01:00
7b3dcf2f03 New translations en.json (Chinese Traditional, Hong Kong) 2024-03-28 18:00:25 +01:00
aa27d5f8d1 New translations en.json (Burmese) 2024-03-28 18:00:24 +01:00
610ee586cb New translations en.json (Azerbaijani) 2024-03-28 18:00:23 +01:00
7f56e24078 New translations en.json (Latvian) 2024-03-28 18:00:22 +01:00
07bb8c524e New translations en.json (Kazakh) 2024-03-28 18:00:21 +01:00
9bed7b2086 New translations en.json (Norwegian Nynorsk) 2024-03-28 18:00:20 +01:00
5c5e6b851c New translations en.json (Thai) 2024-03-28 18:00:19 +01:00
ca415bca50 New translations en.json (Marathi) 2024-03-28 18:00:18 +01:00
7d6293d5a0 New translations en.json (Bengali) 2024-03-28 18:00:17 +01:00
0d35449faa New translations en.json (Tamil) 2024-03-28 18:00:16 +01:00
dd33aefac3 New translations en.json (Khmer) 2024-03-28 18:00:15 +01:00
8e137d1f72 New translations en.json (Persian) 2024-03-28 18:00:14 +01:00
2888c3bb6e New translations en.json (Indonesian) 2024-03-28 18:00:13 +01:00
aaef4e3402 New translations en.json (Portuguese, Brazilian) 2024-03-28 18:00:12 +01:00
8b0a35c832 New translations en.json (Galician) 2024-03-28 18:00:11 +01:00
ce2da48663 New translations en.json (Vietnamese) 2024-03-28 18:00:10 +01:00
869b89c136 New translations en.json (Chinese Traditional) 2024-03-28 18:00:09 +01:00
8bcbecc0ec New translations en.json (Ukrainian) 2024-03-28 18:00:08 +01:00
c7a0557e98 New translations en.json (Turkish) 2024-03-28 18:00:07 +01:00
c5e75439e4 New translations en.json (Slovenian) 2024-03-28 18:00:06 +01:00
8a07b5b907 New translations en.json (Russian) 2024-03-28 18:00:05 +01:00
584170eec3 New translations en.json (Portuguese) 2024-03-28 18:00:04 +01:00
6dd2501a19 New translations en.json (Polish) 2024-03-28 18:00:03 +01:00
3c3c1e9f8c New translations en.json (Punjabi) 2024-03-28 18:00:02 +01:00
17b01dec90 New translations en.json (Dutch) 2024-03-28 18:00:01 +01:00
eb4d64dcd8 New translations en.json (Lithuanian) 2024-03-28 17:59:59 +01:00
dc9f20c19e New translations en.json (Kurdish) 2024-03-28 17:59:59 +01:00
7c40b5ae3e New translations en.json (Korean) 2024-03-28 17:59:58 +01:00
bda85ff7ef New translations en.json (Japanese) 2024-03-28 17:59:57 +01:00
68b1bd80fa New translations en.json (Hungarian) 2024-03-28 17:59:56 +01:00
5771f5c0b7 New translations en.json (Hebrew) 2024-03-28 17:59:55 +01:00
fbbd953f42 New translations en.json (Finnish) 2024-03-28 17:59:53 +01:00
8d7e8e89db New translations en.json (Basque) 2024-03-28 17:59:53 +01:00
4e52529cbb New translations en.json (Greek) 2024-03-28 17:59:52 +01:00
a77c7bb41a New translations en.json (German) 2024-03-28 17:59:51 +01:00
5e2cdeb699 New translations en.json (Danish) 2024-03-28 17:59:50 +01:00
4d077f7324 New translations en.json (Czech) 2024-03-28 17:59:49 +01:00
7fda1f04cf New translations en.json (Catalan) 2024-03-28 17:59:48 +01:00
bce1d4a0e8 New translations en.json (Bulgarian) 2024-03-28 17:59:47 +01:00
cecd042357 New translations en.json (Arabic) 2024-03-28 17:59:46 +01:00
e4047f89c9 New translations en.json (Spanish) 2024-03-28 17:59:45 +01:00
1b457b3efd New translations en.json (French) 2024-03-28 17:59:44 +01:00
99fe0df4b1 New translations en.json (Romanian) 2024-03-28 17:59:43 +01:00
9f3209c487 New translations en.json (Hindi) 2024-03-28 17:59:42 +01:00
4388c33cd4 New translations en.json (Chinese Simplified) 2024-03-28 17:59:41 +01:00
3e5c45f674 New translations en.json (Swedish) 2024-03-28 17:59:40 +01:00
85bc583696 New translations en.json (Slovak) 2024-03-28 17:59:40 +01:00
2d2c35b6db New translations en.json (Italian) 2024-03-28 17:59:39 +01:00
1d71f84515 fix: stop using lookbehind for backwards compat (#7824) 2024-03-28 17:32:38 +01:00
550a388b2b feat: command palette (#7804)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-03-28 16:16:32 +00:00
6b523563d8 fix: ejs support in html files (#7822) 2024-03-28 14:58:47 +01:00
65bc500598 fix: excalidrawAPI.toggleSidebar not switching between tabs correctly (#7821) 2024-03-28 14:52:23 +01:00
7949aa1f1c feat: upgrade mermaid-to-excalidraw to 0.3.0 (#7819) 2024-03-28 16:44:29 +05:30
b3bc9b9513 Auto commit: Calculate translation coverage 2024-03-21 10:59:59 +00:00
ad5c655b32 New translations en.json (Hebrew) 2024-03-21 11:59:41 +01:00
b91e6b5e4e New translations en.json (Swedish) 2024-03-19 08:12:42 +01:00
06ca0a66de New translations en.json (Chinese Simplified) 2024-03-18 22:31:28 +01:00
f170f8dfc2 New translations en.json (Chinese Traditional) 2024-03-18 19:47:46 +01:00
b6b7518992 New translations en.json (Marathi) 2024-03-18 15:47:50 +01:00
be7b9ce46b New translations en.json (German) 2024-03-18 15:47:49 +01:00
743ae9bef1 New translations en.json (Hindi) 2024-03-18 15:47:48 +01:00
1616535de5 New translations en.json (Catalan) 2024-03-18 14:27:10 +01:00
18471dbdc8 New translations en.json (Slovenian) 2024-03-18 13:01:13 +01:00
2c9302b33f New translations en.json (Russian) 2024-03-18 13:01:12 +01:00
f60ae05858 New translations en.json (Catalan) 2024-03-18 13:01:11 +01:00
b14aeed40e New translations en.json (Romanian) 2024-03-18 13:01:10 +01:00
28a2f33bd3 New translations en.json (Karakalpak) 2024-03-18 11:07:38 +01:00
8183c9a2b9 New translations en.json (Kabyle) 2024-03-18 11:07:37 +01:00
449f57c0c9 New translations en.json (Occitan) 2024-03-18 11:07:36 +01:00
6d3f9b1da1 New translations en.json (Norwegian Bokmal) 2024-03-18 11:07:35 +01:00
a4f9983250 New translations en.json (Uzbek) 2024-03-18 11:07:34 +01:00
cd6f1e7e25 New translations en.json (Sinhala) 2024-03-18 11:07:33 +01:00
fc5668fed0 New translations en.json (Chinese Traditional, Hong Kong) 2024-03-18 11:07:32 +01:00
6cf27e310f New translations en.json (Burmese) 2024-03-18 11:07:31 +01:00
1291a341f1 New translations en.json (Azerbaijani) 2024-03-18 11:07:30 +01:00
989b774e9d New translations en.json (Latvian) 2024-03-18 11:07:29 +01:00
372ef53228 New translations en.json (Kazakh) 2024-03-18 11:07:29 +01:00
279c446ca8 New translations en.json (Norwegian Nynorsk) 2024-03-18 11:07:28 +01:00
afa96620bc New translations en.json (Thai) 2024-03-18 11:07:27 +01:00
acf3847f8d New translations en.json (Marathi) 2024-03-18 11:07:26 +01:00
8882514053 New translations en.json (Bengali) 2024-03-18 11:07:25 +01:00
2eabd48630 New translations en.json (Tamil) 2024-03-18 11:07:24 +01:00
b4f90ab130 New translations en.json (Khmer) 2024-03-18 11:07:23 +01:00
e3698ae541 New translations en.json (Persian) 2024-03-18 11:07:22 +01:00
4cccf1b413 New translations en.json (Indonesian) 2024-03-18 11:07:21 +01:00
e168710885 New translations en.json (Portuguese, Brazilian) 2024-03-18 11:07:20 +01:00
955892aeec New translations en.json (Galician) 2024-03-18 11:07:19 +01:00
a574f4d2e9 New translations en.json (Vietnamese) 2024-03-18 11:07:18 +01:00
022b39c858 New translations en.json (Chinese Traditional) 2024-03-18 11:07:17 +01:00
7f1bfe6179 New translations en.json (Ukrainian) 2024-03-18 11:07:16 +01:00
de6b632fa3 New translations en.json (Turkish) 2024-03-18 11:07:15 +01:00
8a5de5b143 New translations en.json (Slovenian) 2024-03-18 11:07:15 +01:00
3cae9483b0 New translations en.json (Russian) 2024-03-18 11:07:14 +01:00
0c65e60ed1 New translations en.json (Portuguese) 2024-03-18 11:07:12 +01:00
f85ccc1a88 New translations en.json (Polish) 2024-03-18 11:07:12 +01:00
22d9a24ae6 New translations en.json (Punjabi) 2024-03-18 11:07:11 +01:00
f181775371 New translations en.json (Dutch) 2024-03-18 11:07:10 +01:00
a5fbefdc84 New translations en.json (Lithuanian) 2024-03-18 11:07:09 +01:00
d1b10f6276 New translations en.json (Kurdish) 2024-03-18 11:07:08 +01:00
a04a4a42ed New translations en.json (Korean) 2024-03-18 11:07:07 +01:00
a18159226a New translations en.json (Japanese) 2024-03-18 11:07:06 +01:00
0646e4453c New translations en.json (Hungarian) 2024-03-18 11:07:05 +01:00
2352af7196 New translations en.json (Hebrew) 2024-03-18 11:07:04 +01:00
46a6886ac4 New translations en.json (Finnish) 2024-03-18 11:07:03 +01:00
3ddf1c179a New translations en.json (Basque) 2024-03-18 11:07:02 +01:00
a0b2a0e4e6 New translations en.json (Greek) 2024-03-18 11:07:01 +01:00
43c46052f3 New translations en.json (German) 2024-03-18 11:07:00 +01:00
e8832fcb28 New translations en.json (Danish) 2024-03-18 11:06:59 +01:00
bd02772edb New translations en.json (Czech) 2024-03-18 11:06:58 +01:00
d5a38f3799 New translations en.json (Catalan) 2024-03-18 11:06:57 +01:00
921dca9f5b New translations en.json (Bulgarian) 2024-03-18 11:06:56 +01:00
8899453891 New translations en.json (Arabic) 2024-03-18 11:06:55 +01:00
7392af03a3 New translations en.json (Spanish) 2024-03-18 11:06:54 +01:00
7d1f4deb27 New translations en.json (French) 2024-03-18 11:06:53 +01:00
66724ac81d New translations en.json (Romanian) 2024-03-18 11:06:52 +01:00
2368d34ab3 New translations en.json (Hindi) 2024-03-18 11:06:52 +01:00
ddc2d8d2b7 New translations en.json (Chinese Simplified) 2024-03-18 11:06:51 +01:00
a7012a4b8e New translations en.json (Swedish) 2024-03-18 11:06:50 +01:00
88db54e11c New translations en.json (Slovak) 2024-03-18 11:06:49 +01:00
bc85f580ec New translations en.json (Italian) 2024-03-18 11:06:48 +01:00
15bfa626b4 feat: support to not render remote cursor & username (#7130) 2024-03-18 10:41:06 +01:00
068895db0e feat: expose more collaborator status icons (#7777) 2024-03-18 10:20:07 +01:00
02fd58ffc8 New translations en.json (Hindi) 2024-03-18 03:49:55 +01:00
b7babe554b feat: load old library if migration fails 2024-03-11 09:57:01 +01:00
6a385d6663 feat: change LibraryPersistenceAdapter load() source -> priority
to clarify the semantics
2024-03-11 09:40:51 +01:00
93af0ce89d New translations en.json (Swedish) 2024-03-11 07:35:54 +01:00
1c025c166a New translations en.json (Polish) 2024-03-09 23:01:20 +01:00
150e0cef5d New translations en.json (Polish) 2024-03-09 22:05:45 +01:00
7f40852b11 New translations en.json (Bengali) 2024-03-09 20:53:27 +01:00
0b6fae0243 New translations en.json (Chinese Traditional) 2024-03-09 20:53:26 +01:00
37af96a577 New translations en.json (Bengali) 2024-03-09 19:49:38 +01:00
0e718265fa New translations en.json (Romanian) 2024-03-09 14:22:26 +01:00
16b103151b New translations en.json (German) 2024-03-09 08:30:33 +01:00
351db6e2b9 New translations en.json (Russian) 2024-03-09 07:34:41 +01:00
b2fb87cd40 New translations en.json (Marathi) 2024-03-09 06:18:09 +01:00
388ec9f4db New translations en.json (Hindi) 2024-03-09 06:18:08 +01:00
95dd7f0617 New translations en.json (Chinese Simplified) 2024-03-09 06:18:07 +01:00
2349b9dcfe New translations en.json (Slovenian) 2024-03-09 00:41:58 +01:00
ddd05ff030 New translations en.json (Karakalpak) 2024-03-08 22:39:03 +01:00
4bc30fda19 New translations en.json (Kabyle) 2024-03-08 22:39:02 +01:00
285744877c New translations en.json (Occitan) 2024-03-08 22:39:01 +01:00
2169ac6fba New translations en.json (Norwegian Bokmal) 2024-03-08 22:39:00 +01:00
d2b9034f5e New translations en.json (Uzbek) 2024-03-08 22:38:59 +01:00
f1bbd3c5a0 New translations en.json (Sinhala) 2024-03-08 22:38:58 +01:00
aec87f706b New translations en.json (Chinese Traditional, Hong Kong) 2024-03-08 22:38:57 +01:00
7bd06eef1b New translations en.json (Burmese) 2024-03-08 22:38:56 +01:00
3be12ef66c New translations en.json (Azerbaijani) 2024-03-08 22:38:55 +01:00
8dae7772b0 New translations en.json (Latvian) 2024-03-08 22:38:54 +01:00
f69532aebf New translations en.json (Kazakh) 2024-03-08 22:38:53 +01:00
5f4e421001 New translations en.json (Norwegian Nynorsk) 2024-03-08 22:38:52 +01:00
b350917852 New translations en.json (Thai) 2024-03-08 22:38:51 +01:00
d3d1e21107 New translations en.json (Marathi) 2024-03-08 22:38:50 +01:00
11a7d52578 New translations en.json (Bengali) 2024-03-08 22:38:49 +01:00
d8a4736c01 New translations en.json (Tamil) 2024-03-08 22:38:49 +01:00
2a4b70e26c New translations en.json (Khmer) 2024-03-08 22:38:47 +01:00
353c17dc3b New translations en.json (Persian) 2024-03-08 22:38:46 +01:00
f51efffd3a New translations en.json (Indonesian) 2024-03-08 22:38:45 +01:00
2618178a93 New translations en.json (Portuguese, Brazilian) 2024-03-08 22:38:44 +01:00
c57d36ba38 New translations en.json (Galician) 2024-03-08 22:38:44 +01:00
6fa91ecb5c New translations en.json (Vietnamese) 2024-03-08 22:38:43 +01:00
44d61bcb62 New translations en.json (Chinese Traditional) 2024-03-08 22:38:42 +01:00
dfeddba61b New translations en.json (Ukrainian) 2024-03-08 22:38:41 +01:00
d691aa87ce New translations en.json (Turkish) 2024-03-08 22:38:40 +01:00
5a56bbb01d New translations en.json (Slovenian) 2024-03-08 22:38:39 +01:00
675adb6f0d New translations en.json (Russian) 2024-03-08 22:38:38 +01:00
4969de2250 New translations en.json (Portuguese) 2024-03-08 22:38:37 +01:00
8f6d5b3871 New translations en.json (Polish) 2024-03-08 22:38:36 +01:00
7732cd1d87 New translations en.json (Punjabi) 2024-03-08 22:38:35 +01:00
a166aa0ac5 New translations en.json (Dutch) 2024-03-08 22:38:34 +01:00
51fe6a8203 New translations en.json (Lithuanian) 2024-03-08 22:38:33 +01:00
287c3fce76 New translations en.json (Kurdish) 2024-03-08 22:38:32 +01:00
b78404bd85 New translations en.json (Korean) 2024-03-08 22:38:31 +01:00
1e2cc0b6f1 New translations en.json (Japanese) 2024-03-08 22:38:30 +01:00
be303375c4 New translations en.json (Hungarian) 2024-03-08 22:38:29 +01:00
8ba188e429 New translations en.json (Hebrew) 2024-03-08 22:38:28 +01:00
10842ae839 New translations en.json (Finnish) 2024-03-08 22:38:27 +01:00
592b9862e1 New translations en.json (Basque) 2024-03-08 22:38:27 +01:00
01b44663e3 New translations en.json (Greek) 2024-03-08 22:38:26 +01:00
ce59dd6d07 New translations en.json (German) 2024-03-08 22:38:25 +01:00
199d0eec81 New translations en.json (Danish) 2024-03-08 22:38:24 +01:00
176558d6d6 New translations en.json (Czech) 2024-03-08 22:38:22 +01:00
94da21229b New translations en.json (Catalan) 2024-03-08 22:38:21 +01:00
58298a9758 New translations en.json (Bulgarian) 2024-03-08 22:38:20 +01:00
bc53ef2017 New translations en.json (Arabic) 2024-03-08 22:38:19 +01:00
2892c5d77d New translations en.json (Spanish) 2024-03-08 22:38:19 +01:00
833e83d57d New translations en.json (French) 2024-03-08 22:38:17 +01:00
47369822d8 New translations en.json (Romanian) 2024-03-08 22:38:16 +01:00
2da836df9d New translations en.json (Hindi) 2024-03-08 22:38:15 +01:00
c42d3700f0 New translations en.json (Chinese Simplified) 2024-03-08 22:38:14 +01:00
146c599e43 New translations en.json (Swedish) 2024-03-08 22:38:13 +01:00
950651ce0a New translations en.json (Slovak) 2024-03-08 22:38:12 +01:00
50ef5d664c New translations en.json (Italian) 2024-03-08 22:38:11 +01:00
2382fad4f6 feat: store library to IndexedDB & support storage adapters (#7655) 2024-03-08 22:29:19 +01:00
1d1c6f35fa New translations en.json (Hindi) 2024-03-07 18:46:48 +01:00
480572f893 fix: correcting Assistant metrics (#7758)
* Changed Assistant metrics to the corrrect ones from OS/2 table

* Adding more information about font metrics

* Adding branded types to avoid future mistakes
2024-03-07 16:54:36 +01:00
68b1fdb20e fix: add missing font metrics for Assistant (#7752) 2024-03-06 10:53:37 +01:00
a38e82f999 feat: close dropdown on escape (#7750) 2024-03-05 23:22:34 +01:00
a07f6e9e3a feat: show ai badge for discovery (#7749) 2024-03-05 23:22:25 +01:00
7e471b55eb feat: text measurements based on font metrics (#7693)
* Introduced vertical offset based on harcoded font metrics 

* Unified usage of alphabetic baseline for both canvas & svg export

* Removed baseline property

* Removed font-size rounding on Safari

* Removed artificial width offset
2024-03-05 19:33:27 +00:00
fd43439dab New translations en.json (Swedish) 2024-03-04 16:57:04 +01:00
160440b860 feat: improve collab error notification (#7741)
* identify cause

* toast after dialog for error messages in collab

* remove comment

* shake tooltip instead for repeating collab errors

* clear collab error

* empty commit

* simplify & fix reset race condition

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-03-04 20:43:44 +08:00
84ae576ad0 Auto commit: Calculate translation coverage 2024-02-29 16:15:01 +00:00
bc32a00d6a New translations en.json (Slovak) 2024-02-29 17:14:47 +01:00
f207bd0a1c build: export types for @excalidraw/utils (#7736)
* build: export types for @excalidraw/utils

* fix

* add types
2024-02-29 15:43:04 +05:30
99601baffc build: create ESM build for utils package 🥳 (#7500)
* build: create ESM build for utils package

* add deps, exports and import.meta
2024-02-28 19:33:47 +05:30
af1a3d5b76 fix: export utils from excalidraw package in excalidraw library (#7731)
* fix: export utils from excalidraw package in excalidraw library

* don't export utils utilities

* fix import path

* fix export

* don't export export utilites

* fix export paths

* reexport utils from excalidraw package

* add exports from withinBounds

* fix path
2024-02-28 11:14:57 +05:30
441b2ff2fd Auto commit: Calculate translation coverage 2024-02-28 04:48:28 +00:00
941e350245 New translations en.json (Chinese Simplified) 2024-02-28 05:48:15 +01:00
36e56267c9 docs: add missing closing angle bracket in integration.mdx (#7729)
Update integration.mdx: Fix missing closing angle bracket in code sample

 A closing angle bracket was missing in a code sample.

Original code:
<div style={{height:"500px", width:"500px"}}
    <Excalidraw />
</div>

Changes:

<div style={{height:"500px", width:"500px"}}>
    <Excalidraw />
</div>
2024-02-27 07:19:20 +00:00
b09b5cb5f4 fix: split renderScene so that locales aren't imported unnecessarily (#7718)
* fix: split renderScene so that locales aren't imported unnecessarily

* lint

* split export code

* rename renderScene to helpers.ts

* add helpers

* fix typo

* fixes

* move renderElementToSvg to export

* lint

* rename export to staticSvgScene

* fix
2024-02-27 10:37:44 +05:30
e32290e9e1 Auto commit: Calculate translation coverage 2024-02-26 16:46:46 +00:00
231a806257 New translations en.json (Italian) 2024-02-26 17:46:32 +01:00
782daddfcc Auto commit: Calculate translation coverage 2024-02-26 15:47:06 +00:00
51ea204cb7 New translations en.json (Italian) 2024-02-26 16:46:49 +01:00
dd8529743a docs: type mistake in integration of excalidraw (#7723) 2024-02-26 10:24:27 +01:00
606979a539 New translations en.json (Hindi) 2024-02-25 19:30:01 +01:00
f639d44a95 fix: remove dependency of t in blob.ts (#7717)
* remove dependency of t in blob.ts

* fix
2024-02-23 15:05:46 +05:30
f1a51e5512 New translations en.json (Hindi) 2024-02-22 16:05:51 +01:00
2275532d10 New translations en.json (Marathi) 2024-02-22 16:05:49 +01:00
2d03d9b667 New translations en.json (Swedish) 2024-02-22 11:33:28 +01:00
917d5c81e3 Auto commit: Calculate translation coverage 2024-02-21 21:18:11 +00:00
d67ffe20ea New translations en.json (Romanian) 2024-02-21 22:17:56 +01:00
5252cc6f11 Auto commit: Calculate translation coverage 2024-02-21 19:01:07 +00:00
f006df974d New translations en.json (Chinese Traditional) 2024-02-21 20:00:53 +01:00
7bd061d996 Auto commit: Calculate translation coverage 2024-02-21 18:05:14 +00:00
2a3aa69f35 New translations en.json (German) 2024-02-21 19:05:01 +01:00
5908d8c07e Auto commit: Calculate translation coverage 2024-02-21 16:36:25 +00:00
e0fce912d5 New translations en.json (Slovenian) 2024-02-21 17:36:11 +01:00
8a77638f67 Auto commit: Calculate translation coverage 2024-02-21 15:23:40 +00:00
d3c43fb648 New translations en.json (Karakalpak) 2024-02-21 16:22:40 +01:00
1974b49b52 New translations en.json (Kabyle) 2024-02-21 16:22:39 +01:00
e729048c98 New translations en.json (Occitan) 2024-02-21 16:22:38 +01:00
6164bd47f9 New translations en.json (Norwegian Bokmal) 2024-02-21 16:22:37 +01:00
791fbfa2e8 New translations en.json (Sinhala) 2024-02-21 16:22:36 +01:00
fbdbcedf33 New translations en.json (Chinese Traditional, Hong Kong) 2024-02-21 16:22:35 +01:00
ca7c470793 New translations en.json (Burmese) 2024-02-21 16:22:34 +01:00
cf787e8b72 New translations en.json (Hindi) 2024-02-21 16:22:33 +01:00
998789dbe8 New translations en.json (Azerbaijani) 2024-02-21 16:22:32 +01:00
1b7098b775 New translations en.json (Latvian) 2024-02-21 16:22:31 +01:00
152dcae5bc New translations en.json (Kazakh) 2024-02-21 16:22:29 +01:00
42f2e1c5c3 New translations en.json (Norwegian Nynorsk) 2024-02-21 16:22:29 +01:00
a986a4f0bf New translations en.json (Thai) 2024-02-21 16:22:27 +01:00
f2fc6ee067 New translations en.json (Marathi) 2024-02-21 16:22:26 +01:00
043503a739 New translations en.json (Bengali) 2024-02-21 16:22:25 +01:00
83cd933987 New translations en.json (Tamil) 2024-02-21 16:22:24 +01:00
9efa749059 New translations en.json (Khmer) 2024-02-21 16:22:23 +01:00
c8fb8f0b2e New translations en.json (Persian) 2024-02-21 16:22:22 +01:00
ec719c131f New translations en.json (Indonesian) 2024-02-21 16:22:21 +01:00
90375a2f12 New translations en.json (Portuguese, Brazilian) 2024-02-21 16:22:20 +01:00
6051275d0a New translations en.json (Chinese Traditional) 2024-02-21 16:22:19 +01:00
06f0c2388d New translations en.json (Chinese Simplified) 2024-02-21 16:22:18 +01:00
7051bac7d8 New translations en.json (Ukrainian) 2024-02-21 16:22:17 +01:00
44aa5856cd New translations en.json (Swedish) 2024-02-21 16:22:15 +01:00
374dc52601 New translations en.json (Slovenian) 2024-02-21 16:22:14 +01:00
46345e9956 New translations en.json (Slovak) 2024-02-21 16:22:13 +01:00
f3c02d4298 New translations en.json (Russian) 2024-02-21 16:22:13 +01:00
b4cedca7da New translations en.json (Portuguese) 2024-02-21 16:22:11 +01:00
deaf828e84 New translations en.json (Polish) 2024-02-21 16:22:10 +01:00
38a5698bc7 New translations en.json (Punjabi) 2024-02-21 16:22:09 +01:00
70af8a3fa5 New translations en.json (Dutch) 2024-02-21 16:22:08 +01:00
37b172c8ca New translations en.json (Lithuanian) 2024-02-21 16:22:07 +01:00
1eef380425 New translations en.json (Kurdish) 2024-02-21 16:22:06 +01:00
1dcf411626 New translations en.json (Korean) 2024-02-21 16:22:05 +01:00
378a97553c New translations en.json (Italian) 2024-02-21 16:22:04 +01:00
3246b04911 New translations en.json (Hungarian) 2024-02-21 16:22:03 +01:00
dda48a7d6a New translations en.json (Hebrew) 2024-02-21 16:22:02 +01:00
29153f0d8d New translations en.json (Finnish) 2024-02-21 16:22:01 +01:00
70c513f568 New translations en.json (Basque) 2024-02-21 16:22:00 +01:00
56f75b259c New translations en.json (Greek) 2024-02-21 16:21:58 +01:00
f94a3a7711 New translations en.json (German) 2024-02-21 16:21:57 +01:00
5a166ee235 New translations en.json (Danish) 2024-02-21 16:21:56 +01:00
0c199e42c8 New translations en.json (Czech) 2024-02-21 16:21:55 +01:00
a377f55d7f New translations en.json (Bulgarian) 2024-02-21 16:21:54 +01:00
c4759c8ca8 New translations en.json (Arabic) 2024-02-21 16:21:53 +01:00
9d19230033 New translations en.json (Spanish) 2024-02-21 16:21:52 +01:00
5aa2ec962b New translations en.json (French) 2024-02-21 16:21:51 +01:00
b21e7f0a70 New translations en.json (Romanian) 2024-02-21 16:21:50 +01:00
0056d274d5 New translations en.json (Uzbek) 2024-02-21 16:21:49 +01:00
cf5d7f3928 New translations en.json (Catalan) 2024-02-21 16:21:48 +01:00
058eed953e New translations en.json (Vietnamese) 2024-02-21 16:21:47 +01:00
5feb41624d New translations en.json (Turkish) 2024-02-21 16:21:46 +01:00
10a74bf607 New translations en.json (Galician) 2024-02-21 16:21:45 +01:00
0d1bb00270 New translations en.json (Japanese) 2024-02-21 16:21:44 +01:00
f5ab3e4e12 fix: remove dependency of t from clipboard and image (#7712)
* fix: remove dependency of t from clipboard and image

* pass errorMessage to copyTextToSystemClipboard where needed

* wrap copyTextToSystemClipboard and rethrow translated error in caller

* review fix

* typo
2024-02-21 19:45:33 +05:30
361a9449bb fix: remove scene hack from export.ts & remove pass elementsMap to getContainingFrame (#7713)
* fix: remove scene hack from export.ts as its not needed anymore

* remove

* pass elementsMap to getContainingFrame

* remove unused `mapElementIds` param

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-02-21 16:34:20 +05:30
2e719ff671 fix: decouple pure functions from hyperlink to prevent mermaid bundling (#7710)
* move hyperlink code into its folder

* move pure js functions to hyperlink/helpers and move actionLink to actions

* fix tests

* fix
2024-02-20 20:59:01 +05:30
506756f332 Auto commit: Calculate translation coverage 2024-02-20 03:48:35 +00:00
67239c874e New translations en.json (Uzbek) 2024-02-20 04:48:23 +01:00
79d9dc2f8f fix: make bounds independent of scene (#7679)
* fix: make bounds independent of scene

* pass only elements to getCommonBounds

* lint

* pass elementsMap to getVisibleAndNonSelectedElements
2024-02-19 19:39:14 +05:30
d6cf042764 Auto commit: Calculate translation coverage 2024-02-19 13:24:59 +00:00
8e5f3ca841 New translations en.json (Catalan) 2024-02-19 14:24:43 +01:00
9013c84524 fix: make LinearElementEditor independent of scene (#7670)
* fix: make LinearElementEditor independent of scene

* more fixes

* pass elements and elementsMap to maybeBindBindableElement,getHoveredElementForBinding,bindingBorderTest,getElligibleElementsForBindableElementAndWhere,isLinearElementEligibleForNewBindingByBindable

* replace `ElementsMap` with `NonDeletedSceneElementsMap` & remove unused params

* fix lint

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-02-19 11:49:01 +05:30
47f87f4ecb fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap

* lint

* fix

* use non deleted elements where possible

* use non deleted elements map in actions

* pass elementsMap instead of array to elementOverlapsWithFrame

* lint

* fix

* pass elementsMap to getElementsCorners

* pass elementsMap to getEligibleElementsForBinding

* pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements

* pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame

* pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame

* pass elementsMap to getElementWithTransformHandleType

* pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements

* lint

* pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition

* revert changes for bindTextToShapeAfterDuplication
2024-02-16 11:35:01 +05:30
41d325fdd8 Auto commit: Calculate translation coverage 2024-02-15 15:43:56 +00:00
6b6761f654 New translations en.json (Vietnamese) 2024-02-15 16:43:43 +01:00
73bf50e8a8 fix: remove t from getDefaultAppState and allow name to be nullable (#7666)
* fix: remove t and allow name to be nullable

* pass name as required prop

* remove Unnamed

* pass name to excalidrawPlus as well for better type safe

* render once we have excalidrawAPI to avoid defaulting

* rename `getAppName` -> `getName` (temporary)

* stop preventing editing filenames when `props.name` supplied

* keep `name` as optional param for export functions

* keep `appState.name` on `props.name` state separate

* fix lint

* assertive first

* fix lint

* Add TODO

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-02-15 11:11:18 +05:30
fc3ae973be Auto commit: Calculate translation coverage 2024-02-13 11:15:09 +00:00
0c3c4d4f22 New translations en.json (Galician) 2024-02-13 12:14:56 +01:00
4df91b980a Auto commit: Calculate translation coverage 2024-02-10 10:54:58 +00:00
3729104547 New translations en.json (Japanese) 2024-02-10 11:54:46 +01:00
48c3465b19 docs: release patch v0.17.3 (#7673)
* docs: release patch v0.17.3

* update cl
2024-02-09 19:29:50 +05:30
adc4c9f484 fix: prevent panning to trigger history on macos chrome (#7671) 2024-02-08 19:50:50 +01:00
def1df2c68 fix: keep customData when converting to ExcalidrawElement (#7656)
* feat: keep customData when converting to ExcalidrawElement (#7654)

* docs: add changelog for keeping customData when converting to ExcalidrawElement
2024-02-08 17:23:10 +05:30
9fd896c1d1 Auto commit: Calculate translation coverage 2024-02-06 19:24:30 +00:00
e6f4e1f027 New translations en.json (Portuguese) 2024-02-06 20:24:16 +01:00
35424f62ed New translations en.json (Swedish) 2024-02-06 09:32:24 +01:00
70943ae461 Auto commit: Calculate translation coverage 2024-02-05 13:44:35 +00:00
a976aa7123 New translations en.json (French) 2024-02-05 14:44:22 +01:00
e58111d93d New translations en.json (Russian) 2024-02-04 18:14:26 +01:00
311ebaa5a4 Auto commit: Calculate translation coverage 2024-02-04 10:18:20 +00:00
b058b2dff1 New translations en.json (Dutch) 2024-02-04 11:18:10 +01:00
6c77e76c4c Auto commit: Calculate translation coverage 2024-02-04 08:44:00 +00:00
691225f51a New translations en.json (Romanian) 2024-02-04 09:43:48 +01:00
d46c669f64 Auto commit: Calculate translation coverage 2024-02-03 23:48:17 +00:00
7f46da315f New translations en.json (Chinese Simplified) 2024-02-04 00:48:06 +01:00
b7e0d18fae Auto commit: Calculate translation coverage 2024-02-03 16:41:58 +00:00
f9095caa42 New translations en.json (German) 2024-02-03 17:41:47 +01:00
de5c825d01 Auto commit: Calculate translation coverage 2024-02-03 15:29:53 +00:00
5fd26d2a45 New translations en.json (Karakalpak) 2024-02-03 16:28:33 +01:00
06052b1f3e New translations en.json (Kabyle) 2024-02-03 16:28:32 +01:00
98b3fbbc18 New translations en.json (Norwegian Bokmal) 2024-02-03 16:28:31 +01:00
fd29c8dd44 New translations en.json (Sinhala) 2024-02-03 16:28:30 +01:00
f4e90f1888 New translations en.json (Chinese Traditional, Hong Kong) 2024-02-03 16:28:29 +01:00
d9d8a39d6a New translations en.json (Burmese) 2024-02-03 16:28:28 +01:00
aa1a99dcf2 New translations en.json (Azerbaijani) 2024-02-03 16:28:27 +01:00
01f863f268 New translations en.json (Latvian) 2024-02-03 16:28:26 +01:00
8779e7f36f New translations en.json (Kazakh) 2024-02-03 16:28:25 +01:00
703cfc02e9 New translations en.json (Norwegian Nynorsk) 2024-02-03 16:28:25 +01:00
d11c92ffc3 New translations en.json (Thai) 2024-02-03 16:28:24 +01:00
7f381a0d02 New translations en.json (Marathi) 2024-02-03 16:28:23 +01:00
b8b1b9d57f New translations en.json (Bengali) 2024-02-03 16:28:22 +01:00
103c0e5997 New translations en.json (Tamil) 2024-02-03 16:28:21 +01:00
696e3d6836 New translations en.json (Khmer) 2024-02-03 16:28:20 +01:00
07a6b9942e New translations en.json (Persian) 2024-02-03 16:28:19 +01:00
e3d2b854d7 New translations en.json (Indonesian) 2024-02-03 16:28:18 +01:00
5ee88f6c6b New translations en.json (Portuguese, Brazilian) 2024-02-03 16:28:17 +01:00
1681598c7d New translations en.json (Vietnamese) 2024-02-03 16:28:16 +01:00
8f6d92c45c New translations en.json (Chinese Traditional) 2024-02-03 16:28:15 +01:00
3445c340a1 New translations en.json (Chinese Simplified) 2024-02-03 16:28:14 +01:00
a82d3c15ff New translations en.json (Turkish) 2024-02-03 16:28:13 +01:00
8b44b2f2ed New translations en.json (Swedish) 2024-02-03 16:28:12 +01:00
3f4f9e914b New translations en.json (Slovenian) 2024-02-03 16:28:11 +01:00
721565f3c3 New translations en.json (Slovak) 2024-02-03 16:28:10 +01:00
4b8060b093 New translations en.json (Russian) 2024-02-03 16:28:10 +01:00
b61bbfea4e New translations en.json (Portuguese) 2024-02-03 16:28:09 +01:00
6c88eb12d7 New translations en.json (Polish) 2024-02-03 16:28:08 +01:00
5cb46022fb New translations en.json (Punjabi) 2024-02-03 16:28:07 +01:00
afa0f83349 New translations en.json (Dutch) 2024-02-03 16:28:06 +01:00
a3ddac93a6 New translations en.json (Lithuanian) 2024-02-03 16:28:05 +01:00
6dd1406716 New translations en.json (Kurdish) 2024-02-03 16:28:04 +01:00
59f11650f2 New translations en.json (Korean) 2024-02-03 16:28:03 +01:00
fb6e93fe8e New translations en.json (Italian) 2024-02-03 16:28:02 +01:00
b7ddf1ef3a New translations en.json (Hungarian) 2024-02-03 16:28:01 +01:00
5ffc582f76 New translations en.json (Hebrew) 2024-02-03 16:28:01 +01:00
d025f728cc New translations en.json (Finnish) 2024-02-03 16:28:00 +01:00
7172c833cb New translations en.json (Basque) 2024-02-03 16:27:59 +01:00
e22350f745 New translations en.json (Greek) 2024-02-03 16:27:58 +01:00
da9319411b New translations en.json (German) 2024-02-03 16:27:57 +01:00
a3bd43f3b2 New translations en.json (Danish) 2024-02-03 16:27:56 +01:00
4d0fd858be New translations en.json (Czech) 2024-02-03 16:27:55 +01:00
f89325507c New translations en.json (Bulgarian) 2024-02-03 16:27:54 +01:00
3cafe68e2b New translations en.json (Arabic) 2024-02-03 16:27:53 +01:00
e9ea414849 New translations en.json (Romanian) 2024-02-03 16:27:52 +01:00
fef5b41bd9 New translations en.json (Galician) 2024-02-03 16:27:51 +01:00
7a478bd508 New translations en.json (Japanese) 2024-02-03 16:27:50 +01:00
bba0033900 New translations en.json (Occitan) 2024-02-03 16:27:49 +01:00
2e773439ce New translations en.json (Hindi) 2024-02-03 16:27:48 +01:00
3ff668d7ed New translations en.json (French) 2024-02-03 16:27:47 +01:00
1801d9efcb New translations en.json (Catalan) 2024-02-03 16:27:46 +01:00
ecd9d7444f New translations en.json (Spanish) 2024-02-03 16:27:45 +01:00
2dc2b31e36 New translations en.json (Ukrainian) 2024-02-03 16:27:45 +01:00
0513b647ec feat: change collab trigger & add share dialog (#7647) 2024-02-03 14:04:23 +00:00
a289c42830 feat: add loading state to FilledButton (#7650) 2024-02-03 14:53:31 +01:00
d67eaa8710 fix: file save timing out with big file sizes (#7649) 2024-02-03 11:53:35 +01:00
50a5886455 Auto commit: Calculate translation coverage 2024-02-02 19:30:27 +00:00
8d4dde8411 New translations en.json (Galician) 2024-02-02 20:30:14 +01:00
b6c9bd6bfc Auto commit: Calculate translation coverage 2024-02-02 17:29:48 +00:00
a5977368b1 New translations en.json (Occitan) 2024-02-02 18:29:35 +01:00
0c3dffb082 fix: make getEmbedLink independent of t function (#7643)
* fix: make getEmbedLink independent of t function

* rename warning to error and make it type safe
2024-02-01 21:12:10 +05:30
0e0f34edd8 fix: follow mode border for hosts apps (#7642) 2024-02-01 15:03:15 +01:00
4888d9d355 chore: change default port of collab server (#7641) 2024-02-01 14:41:38 +01:00
1c39bd5781 fix: don't bundle react and jotai when importing from scene (#7640)
* don't bundle react and jotai when importing from scene

* fix
2024-02-01 18:24:17 +05:30
90ad885446 feat: support onPointerUp prop (#7638)
* feat: support onPointerUp prop

* update changelog

* Update packages/excalidraw/CHANGELOG.md

Co-authored-by: David Luzar <5153846+dwelle@users.noreply.github.com>

---------

Co-authored-by: David Luzar <5153846+dwelle@users.noreply.github.com>
2024-02-01 12:26:55 +00:00
401281d0eb New translations en.json (Japanese) 2024-02-01 10:44:58 +01:00
1741c234a6 fix: decouple container cache logic to containerCache. (#7637) 2024-01-31 21:17:41 +05:30
63b50b3586 fix: don't bundle react-dom when importing from transformHandles (#7634)
* fix: don't bundle react when importing from transfromHandles

* rename to DEFAULT_TRANSFORM_HANDLE_SPACING
2024-01-31 16:50:35 +05:30
e0fefa8025 fix: don't bundle react-dom when importing from element (#7635) 2024-01-31 16:43:37 +05:30
f7df761f7c Auto commit: Calculate translation coverage 2024-01-31 07:13:49 +00:00
e690653a3a New translations en.json (Occitan) 2024-01-31 08:13:38 +01:00
012094d32f New translations en.json (Hindi) 2024-01-30 03:20:20 +01:00
d426cc968d refactor: remove portal as it is no longer needed (#7623)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-01-29 16:37:09 +01:00
085099b770 Auto commit: Calculate translation coverage 2024-01-29 14:43:01 +00:00
c066a5d65a New translations en.json (French) 2024-01-29 15:42:49 +01:00
2409c091ff feat: support roundness for images (#7558)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-01-29 15:27:07 +01:00
626fe252ab fix: frame name field (#7457)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-01-29 10:57:22 +01:00
0bb4aa58a0 New translations en.json (Ukrainian) 2024-01-27 15:15:12 +01:00
3baf081831 New translations en.json (Ukrainian) 2024-01-27 14:18:19 +01:00
cd07cae68c Auto commit: Calculate translation coverage 2024-01-26 23:20:26 +00:00
f8862ff2b3 New translations en.json (Catalan) 2024-01-27 00:20:14 +01:00
79dd246722 New translations en.json (Ukrainian) 2024-01-26 18:01:08 +01:00
6ba4dd5d86 New translations en.json (Ukrainian) 2024-01-26 16:19:23 +01:00
10bd08ef19 fix: make getBoundTextElement and related helpers pure (#7601)
* fix: make getBoundTextElement pure

* updating args

* fix

* pass boundTextElement to getBoundTextMaxWidth

* fix labelled arrows

* lint

* pass elementsMap to removeElementsFromFrame

* pass elementsMap to getMaximumGroups, alignElements and distributeElements

* lint

* pass allElementsMap to renderElement

* lint

* feat: make more typesafe

* fix: remove unnecessary assertion

* fix: remove unused params

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-01-26 11:29:07 +05:30
2789d08154 docs: update the docs for next js integration (#7605)
* docs: update the docs for next js integration

* update

* update

* update docs with tabbed examples

* fix
2024-01-25 20:26:48 +05:30
da4896077b Auto commit: Calculate translation coverage 2024-01-25 01:58:25 +00:00
0321ea248a New translations en.json (Spanish) 2024-01-25 02:58:13 +01:00
678bb2b819 build(deps-dev): bump vite from 5.0.6 to 5.0.12 (#7586)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.6 to 5.0.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.0.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.0.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-24 19:29:50 +05:30
966f9aead9 build(deps-dev): bump vite from 5.0.6 to 5.0.12 in /examples/excalidraw/with-script-in-browser (#7603)
build(deps-dev): bump vite

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.6 to 5.0.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.0.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.0.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-24 19:28:11 +05:30
4f0a2a9593 docs: add next js with app router example (#7552)
* move the existing example to with-script-in-browser

* Add example with next js app router

* disable ssr for excalidraw client comp

* typo

* update output dir

* don't include nextjs example in tsconfig

* remove meta.json

* lint

* remove example.ts

* port

* move the examples outside packages and use the deps as workspaces in examples

* update gitignore

* fix example

* update path of build dir

* fix

* fix scripts

* try local path

* fix

* update commands

* fix

* fix

* fix script

* skip ts

* disable ts

* add vercel.json

* install

* update tsconfig

* fix lint

* remove console.log

* lets see if this works

* revert

* remove ts nocheck

* add types and some utils in nextjs example

* fix types

* updatw example and remove nextjs dynamic syntax so we don't import excal twice

* move both examples to workspaces and create generic example to be used by browser and next js both

* copy the static assets to nextjs

* fix ts config

* render custom menu items

* fix custom footer

* fix types in browser example

* use regular imports for importing excal and import it using dynamic next js in app router instead

* Add example for pages router

* fix css discrepancies

* fix css

* configure output dir

* fix

* fix css

* rename to with-nextjs

* move components to examples/excalidraw/components
2024-01-24 17:07:54 +05:30
f3f8217125 docs: toggleSidebar api fix (#7575) 2024-01-23 14:50:51 +00:00
89bd6181f2 fix: revert mapElementIds flag removal (#7594) 2024-01-22 17:23:00 +01:00
c6fdac131b ci: add the workspace ignore check to install actions as dependency for auto release (#7593) 2024-01-22 17:01:00 +05:30
0415c616b1 refactor: decoupling global Scene state part-1 (#7577) 2024-01-22 00:23:02 +01:00
740a165452 fix: filter out elements not overlapping frame on paste (#7591) 2024-01-21 20:55:57 +01:00
4997624a3a fix: frame name editing inconvenience (#7437) 2024-01-21 20:55:28 +01:00
b66daae1f3 fix: Truncate collaborator name in dropdown. (#7576) 2024-01-21 20:36:09 +01:00
1e7df58b5b feat: add pasted elements to frame under cursor (#7590) 2024-01-21 14:01:43 +01:00
46da032626 fix: exporting frame-overlapping elements belonging to other frames (#7584) 2024-01-19 14:41:22 +01:00
3b0593baa7 fix: Prevent the library label from being collapsed (#7579) 2024-01-19 14:41:08 +01:00
07415a37c9 Auto commit: Calculate translation coverage 2024-01-17 15:48:05 +00:00
356eb47ca3 New translations en.json (Japanese) 2024-01-17 16:47:46 +01:00
dd530737a2 docs: fix "canvas actions" link in Props page (#7536)
fix "canvas actions" link in Props page
2024-01-17 16:19:42 +05:30
a4e5e46dd1 fix: move default to last so its compatible with nextjs (#7561) 2024-01-15 14:52:04 +05:30
9383e1a983 Auto commit: Calculate translation coverage 2024-01-14 21:44:10 +00:00
43ad9a7da9 New translations en.json (Ukrainian) 2024-01-14 22:43:59 +01:00
b661158a85 Auto commit: Calculate translation coverage 2024-01-14 20:35:38 +00:00
4d5f89fb2a New translations en.json (Norwegian Nynorsk) 2024-01-14 21:35:25 +01:00
0fa5f5de4c fix: translating frames containing grouped text containers (#7557) 2024-01-13 21:28:54 +01:00
41cc746885 fix: host font assets from root (#7548) 2024-01-11 21:29:29 +01:00
8ead8559e0 feat: redirect font requests to cdn (#7549) 2024-01-11 21:08:17 +01:00
5245276409 feat: erase groups atomically (#7545) 2024-01-11 17:43:04 +01:00
0c24a7042f feat: remove ExcalidrawEmbeddableElement.validated flag (#7539) 2024-01-11 17:42:51 +01:00
Are
86cfeb714c feat: add eraser tool trail (#7511)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2024-01-11 16:10:15 +00:00
872973f145 fix: do not modify elements while erasing (#7531) 2024-01-11 16:00:07 +01:00
3ecf72a507 docs: add changelog for ESM build (#7542)
* docs: add changelog for ESM build

* move to breaking change
2024-01-11 16:40:45 +05:30
1aaa400876 docs: fix extra space in UIOptions/tools (#7537)
fix typo in UIOptions/tools
2024-01-11 11:09:33 +00:00
65047cc2cb fix: decouple react and react-dom imports from utils and make it treeshakeable (#7527)
fix: decouple react and react-dom imports from utils and make it tree-shakeable
2024-01-08 21:01:47 +05:30
c8d1cd6cc3 New translations en.json (Italian) 2024-01-06 20:07:42 +01:00
558e9382ae Auto commit: Calculate translation coverage 2024-01-06 10:54:10 +00:00
1ec0b25c3d New translations en.json (Romanian) 2024-01-06 11:53:58 +01:00
4d08a6568b Auto commit: Calculate translation coverage 2024-01-06 04:35:47 +00:00
2ef35fd2f8 New translations en.json (Hindi) 2024-01-06 05:35:33 +01:00
cc44844029 New translations en.json (Marathi) 2024-01-06 05:35:32 +01:00
970903992a Auto commit: Calculate translation coverage 2024-01-05 18:37:25 +00:00
ac160b6a18 New translations en.json (Slovak) 2024-01-05 19:37:11 +01:00
535a99a12f Auto commit: Calculate translation coverage 2024-01-05 08:09:35 +00:00
6415432eb5 New translations en.json (Chinese Simplified) 2024-01-05 09:09:23 +01:00
30e9692158 Auto commit: Calculate translation coverage 2024-01-04 21:12:51 +00:00
148bce498e New translations en.json (Portuguese) 2024-01-04 22:12:39 +01:00
9455b0942b Auto commit: Calculate translation coverage 2024-01-04 20:02:43 +00:00
a279bbb5fd New translations en.json (Portuguese, Brazilian) 2024-01-04 21:02:30 +01:00
3843e24ba0 New translations en.json (Portuguese) 2024-01-04 21:02:28 +01:00
91ada50547 Auto commit: Calculate translation coverage 2024-01-04 18:12:59 +00:00
c969c730a5 New translations en.json (Chinese Traditional) 2024-01-04 19:12:47 +01:00
560cd5ec32 New translations en.json (Russian) 2024-01-04 19:12:46 +01:00
186c3755e9 New translations en.json (Portuguese) 2024-01-04 19:12:45 +01:00
a8113203d4 New translations en.json (German) 2024-01-04 19:12:44 +01:00
8b993d409e feat: render embeds lazily (#7519) 2024-01-04 19:03:04 +01:00
2e1da33411 Auto commit: Calculate translation coverage 2024-01-04 16:21:40 +00:00
053dce7b8b New translations en.json (Swedish) 2024-01-04 17:21:27 +01:00
4941ffdcae New translations en.json (Slovenian) 2024-01-04 17:21:26 +01:00
845d519fc9 New translations en.json (Portuguese) 2024-01-04 17:21:25 +01:00
cb59638222 Auto commit: Calculate translation coverage 2024-01-04 14:48:12 +00:00
1cf00f8f28 New translations en.json (Karakalpak) 2024-01-04 15:46:16 +01:00
3138e75dfe New translations en.json (Kabyle) 2024-01-04 15:46:15 +01:00
c0fd470198 New translations en.json (Occitan) 2024-01-04 15:46:14 +01:00
44dd859a11 New translations en.json (Norwegian Bokmal) 2024-01-04 15:46:13 +01:00
fb207ad1d4 New translations en.json (Sinhala) 2024-01-04 15:46:11 +01:00
238324505f New translations en.json (Chinese Traditional, Hong Kong) 2024-01-04 15:46:09 +01:00
9685ac01a1 New translations en.json (Burmese) 2024-01-04 15:46:08 +01:00
ebf18e369b New translations en.json (Hindi) 2024-01-04 15:46:07 +01:00
d1663324be New translations en.json (Azerbaijani) 2024-01-04 15:46:06 +01:00
37e8eb1211 New translations en.json (Latvian) 2024-01-04 15:46:05 +01:00
d27063eea4 New translations en.json (Kazakh) 2024-01-04 15:46:04 +01:00
77a89d12f2 New translations en.json (Norwegian Nynorsk) 2024-01-04 15:46:03 +01:00
e66d7717ab New translations en.json (Thai) 2024-01-04 15:46:01 +01:00
828772e4f2 New translations en.json (Marathi) 2024-01-04 15:46:00 +01:00
087cfdfb9f New translations en.json (Bengali) 2024-01-04 15:45:59 +01:00
77a7cca80c New translations en.json (Tamil) 2024-01-04 15:45:58 +01:00
d24c875aeb New translations en.json (Khmer) 2024-01-04 15:45:57 +01:00
6c974d033b New translations en.json (Indonesian) 2024-01-04 15:45:56 +01:00
5ee8fd7448 New translations en.json (Portuguese, Brazilian) 2024-01-04 15:45:55 +01:00
23352dd668 New translations en.json (Galician) 2024-01-04 15:45:54 +01:00
60524a49be New translations en.json (Vietnamese) 2024-01-04 15:45:53 +01:00
76665cc7a1 New translations en.json (Chinese Traditional) 2024-01-04 15:45:52 +01:00
6cd8bbf5e2 New translations en.json (Ukrainian) 2024-01-04 15:45:51 +01:00
8602bb66ab New translations en.json (Turkish) 2024-01-04 15:45:50 +01:00
20d40522da New translations en.json (Swedish) 2024-01-04 15:45:48 +01:00
44d4e069e4 New translations en.json (Slovenian) 2024-01-04 15:45:47 +01:00
309790a707 New translations en.json (Russian) 2024-01-04 15:45:46 +01:00
8a17d6287c New translations en.json (Portuguese) 2024-01-04 15:45:45 +01:00
bea2193b82 New translations en.json (Polish) 2024-01-04 15:45:44 +01:00
3819b41865 New translations en.json (Punjabi) 2024-01-04 15:45:42 +01:00
52e7bab8e6 New translations en.json (Dutch) 2024-01-04 15:45:42 +01:00
7916134430 New translations en.json (Lithuanian) 2024-01-04 15:45:40 +01:00
e1944b4d45 New translations en.json (Kurdish) 2024-01-04 15:45:39 +01:00
7fe05e26d6 New translations en.json (Korean) 2024-01-04 15:45:38 +01:00
a654815139 New translations en.json (Japanese) 2024-01-04 15:45:37 +01:00
d7c69316f7 New translations en.json (Hungarian) 2024-01-04 15:45:35 +01:00
a22d237f2a New translations en.json (Hebrew) 2024-01-04 15:45:34 +01:00
f92acf6481 New translations en.json (Finnish) 2024-01-04 15:45:33 +01:00
c7adb02973 New translations en.json (Basque) 2024-01-04 15:45:32 +01:00
ce0ed0bdd3 New translations en.json (Greek) 2024-01-04 15:45:31 +01:00
3b51f9711c New translations en.json (German) 2024-01-04 15:45:30 +01:00
ca0f7f417b New translations en.json (Danish) 2024-01-04 15:45:29 +01:00
9f59e2080d New translations en.json (Czech) 2024-01-04 15:45:28 +01:00
1e6778ec11 New translations en.json (Catalan) 2024-01-04 15:45:27 +01:00
a1cdec0995 New translations en.json (Bulgarian) 2024-01-04 15:45:26 +01:00
6593913c7e New translations en.json (Arabic) 2024-01-04 15:45:25 +01:00
9fb3f7d223 New translations en.json (Spanish) 2024-01-04 15:45:24 +01:00
8a43bc35d7 New translations en.json (Romanian) 2024-01-04 15:45:23 +01:00
2e65fb9441 New translations en.json (French) 2024-01-04 15:45:22 +01:00
f0326c4a82 New translations en.json (Italian) 2024-01-04 15:45:21 +01:00
1deb577b6e New translations en.json (Persian) 2024-01-04 15:45:20 +01:00
60c59a9575 New translations en.json (Slovak) 2024-01-04 15:45:19 +01:00
fddc299b60 New translations en.json (Chinese Simplified) 2024-01-04 15:45:18 +01:00
1cb350b2aa feat: update X brand logo & tweak labels (#7518) 2024-01-04 14:57:31 +01:00
43ccc875fb feat: support multi-embed pasting & x.com domain (#7516) 2024-01-04 13:27:52 +01:00
4249b7dec8 chore: add version for excalidraw-app workspace (#7514) 2024-01-04 13:53:19 +05:30
49f15c736b chore: remove unused files (#7509)
chore remove unused files
2024-01-03 16:25:36 +05:30
a8064ba3ee build: Welcome ESM and Bye Bye UMD (#7441)
* build: Welcome ESM and Bye Bye UMD

* remove package

* create unbundled esm build

* update script for example

* fix typo

* dummy commit

* update autorelease script to build esm

* revert dummy commit

* move react, react-dom and testing library to dev dependencies

* remove entry.js, publicPath and yarn install:deps script

* fix

* upgrade esbuild to fix glob import error for locales

* remove webpack chunk names as thats not needed anymore

* marking the code sideeffects free

* make the library tree-shakeable and move fonts to fonts directory

* allow side effects for css, scss files

* remove tree-shaking

* comment code for tree shaking

* move to vite for example

* bye bye webpack

* ignore ts

* separate build and output dir

* use esbuild for creating bundle for example

* update output dir

* lint

* create browser dev build with source maps and prod with minification

* add dev and prod builds for bundler

* lint

* update script

* remove await

* load prod build

* create minified build in dist

* prod and dev builds using export field

* remove import.meta

* dummy

* define import.meta prod and dev

* fix

* export types

* add types field

* typo

* lint

* Update scripts/buildPackage.js

* move types inside export

* newline
2024-01-01 20:18:44 +05:30
e6c3c06c2e feat: support pen erasing (#7496) 2024-01-01 13:27:03 +01:00
892fe1917e Auto commit: Calculate translation coverage 2023-12-30 16:18:06 +00:00
7979b5e11c New translations en.json (French) 2023-12-30 17:17:53 +01:00
d19b51d4f8 fix: drawing-tablet stylus touch events being prevented (#7494) 2023-12-30 15:00:12 +01:00
c72e853c85 refactor: editor events sub/unsub refactor (#7483) 2023-12-30 11:12:38 +01:00
d5fba1e199 Auto commit: Calculate translation coverage 2023-12-23 13:08:01 +00:00
4629c88279 New translations en.json (Italian) 2023-12-23 14:07:47 +01:00
381809e1bd Auto commit: Calculate translation coverage 2023-12-23 10:34:22 +00:00
a06c103aa7 New translations en.json (Persian) 2023-12-23 11:34:06 +01:00
ae43f480d6 Auto commit: Calculate translation coverage 2023-12-22 10:38:58 +00:00
b7535f0b0e New translations en.json (Slovak) 2023-12-22 11:38:44 +01:00
9d7dd3afef New translations en.json (Slovak) 2023-12-22 09:45:33 +01:00
6e70165e8c Auto commit: Calculate translation coverage 2023-12-22 01:52:18 +00:00
b9759d2c77 New translations en.json (Chinese Simplified) 2023-12-22 02:52:03 +01:00
1cb3feec51 Auto commit: Calculate translation coverage 2023-12-20 17:36:37 +00:00
7c0f1f42f6 New translations en.json (Chinese Traditional) 2023-12-20 18:36:23 +01:00
4b9dae1986 Auto commit: Calculate translation coverage 2023-12-20 11:17:25 +00:00
8e13821456 New translations en.json (Hindi) 2023-12-20 12:17:11 +01:00
9ae10b66ab New translations en.json (Marathi) 2023-12-20 12:17:10 +01:00
f77fcc28d9 Auto commit: Calculate translation coverage 2023-12-20 06:13:39 +00:00
20a6bdb55c New translations en.json (Korean) 2023-12-20 07:13:22 +01:00
5f40a4cad4 fix: missing cross-env from build:umd in package.json (#7460) 2023-12-19 00:02:03 +01:00
7f4bcbe853 Auto commit: Calculate translation coverage 2023-12-18 20:50:20 +00:00
a7e2e053f3 New translations en.json (Russian) 2023-12-18 21:50:07 +01:00
c870c7adab New translations en.json (German) 2023-12-18 21:50:06 +01:00
9075584a3a New translations en.json (Spanish) 2023-12-18 21:50:05 +01:00
d91c98b82e fix: incorrect types in ActionNavigate (#7462) 2023-12-18 21:14:30 +01:00
00f35af572 Auto commit: Calculate translation coverage 2023-12-18 18:13:16 +00:00
24d5be9e8c New translations en.json (Romanian) 2023-12-18 19:13:02 +01:00
57ea4e61d1 fix: mixing clientId & socketId in UserList (#7461) 2023-12-18 18:21:57 +01:00
7b671d0d74 Auto commit: Calculate translation coverage 2023-12-18 17:05:33 +00:00
6ad3077c69 New translations en.json (Swedish) 2023-12-18 18:05:20 +01:00
4f1d578b2f New translations en.json (Slovenian) 2023-12-18 18:05:18 +01:00
685eb8cb50 Auto commit: Calculate translation coverage 2023-12-18 16:00:56 +00:00
998331f937 New translations en.json (Karakalpak) 2023-12-18 16:57:33 +01:00
fdd3ea29e0 New translations en.json (Kabyle) 2023-12-18 16:57:31 +01:00
f25781db38 New translations en.json (Occitan) 2023-12-18 16:57:30 +01:00
8bde613823 New translations en.json (Norwegian Bokmal) 2023-12-18 16:57:29 +01:00
e9db8195e0 New translations en.json (Sinhala) 2023-12-18 16:57:28 +01:00
944f823847 New translations en.json (Chinese Traditional, Hong Kong) 2023-12-18 16:57:27 +01:00
377243b07f New translations en.json (Burmese) 2023-12-18 16:57:26 +01:00
c86c73dd8f New translations en.json (Hindi) 2023-12-18 16:57:25 +01:00
4f453600db New translations en.json (Azerbaijani) 2023-12-18 16:57:24 +01:00
4ff1dbc8b1 New translations en.json (Latvian) 2023-12-18 16:57:23 +01:00
18463b79b3 New translations en.json (Kazakh) 2023-12-18 16:57:22 +01:00
9e19d2d166 New translations en.json (Norwegian Nynorsk) 2023-12-18 16:57:21 +01:00
17e9de9a53 New translations en.json (Thai) 2023-12-18 16:57:19 +01:00
4a0f4fc4ea New translations en.json (Marathi) 2023-12-18 16:57:18 +01:00
124d7a388f New translations en.json (Bengali) 2023-12-18 16:57:17 +01:00
0b34294156 New translations en.json (Tamil) 2023-12-18 16:57:16 +01:00
d296b12f0e New translations en.json (Khmer) 2023-12-18 16:57:15 +01:00
2d62da8dfe New translations en.json (Persian) 2023-12-18 16:57:14 +01:00
6115b9a808 New translations en.json (Indonesian) 2023-12-18 16:57:13 +01:00
e034410a91 New translations en.json (Portuguese, Brazilian) 2023-12-18 16:57:12 +01:00
800a609b4f New translations en.json (Galician) 2023-12-18 16:57:10 +01:00
ce69926f8a New translations en.json (Vietnamese) 2023-12-18 16:57:09 +01:00
e38a33b7b4 New translations en.json (Chinese Traditional) 2023-12-18 16:57:08 +01:00
95ab1256ba New translations en.json (Chinese Simplified) 2023-12-18 16:57:07 +01:00
f7a3dbd9f2 New translations en.json (Ukrainian) 2023-12-18 16:57:06 +01:00
4552db4fa1 New translations en.json (Turkish) 2023-12-18 16:57:05 +01:00
a33bb248a4 New translations en.json (Swedish) 2023-12-18 16:57:04 +01:00
2df55f0be7 New translations en.json (Slovenian) 2023-12-18 16:57:03 +01:00
a0094fce80 New translations en.json (Slovak) 2023-12-18 16:57:02 +01:00
72a525063a New translations en.json (Russian) 2023-12-18 16:57:01 +01:00
0484b8db51 New translations en.json (Portuguese) 2023-12-18 16:56:59 +01:00
c63781abe3 New translations en.json (Polish) 2023-12-18 16:56:58 +01:00
b496e68bf9 New translations en.json (Punjabi) 2023-12-18 16:56:57 +01:00
d0df605151 New translations en.json (Dutch) 2023-12-18 16:56:56 +01:00
0796621702 New translations en.json (Lithuanian) 2023-12-18 16:56:55 +01:00
d883fa7cc0 New translations en.json (Kurdish) 2023-12-18 16:56:54 +01:00
bf68b8b3b2 New translations en.json (Korean) 2023-12-18 16:56:53 +01:00
8136962237 New translations en.json (Japanese) 2023-12-18 16:56:52 +01:00
b8a62be016 New translations en.json (Italian) 2023-12-18 16:56:51 +01:00
f86bc0fab9 New translations en.json (Hungarian) 2023-12-18 16:56:50 +01:00
422941f260 New translations en.json (Hebrew) 2023-12-18 16:56:49 +01:00
b839775904 New translations en.json (Finnish) 2023-12-18 16:56:47 +01:00
69de41c981 New translations en.json (Basque) 2023-12-18 16:56:46 +01:00
037dfadbc2 New translations en.json (Greek) 2023-12-18 16:56:45 +01:00
d6a512f05b New translations en.json (German) 2023-12-18 16:56:44 +01:00
c2f83885cb New translations en.json (Danish) 2023-12-18 16:56:43 +01:00
4c8f41f312 New translations en.json (Czech) 2023-12-18 16:56:42 +01:00
93d66a7958 New translations en.json (Catalan) 2023-12-18 16:56:41 +01:00
8dce1413b9 New translations en.json (Bulgarian) 2023-12-18 16:56:39 +01:00
e4fdab7c96 New translations en.json (Arabic) 2023-12-18 16:56:38 +01:00
2a748aa76a New translations en.json (Spanish) 2023-12-18 16:56:37 +01:00
d8049f3843 New translations en.json (French) 2023-12-18 16:56:36 +01:00
d9edc2e30d New translations en.json (Romanian) 2023-12-18 16:56:35 +01:00
0808532b49 fix: follow mode collaborator status indicator (#7459) 2023-12-18 16:14:25 +01:00
2a0fe2584e fix: empty snapLines arrays would cause re-render (#7454)
Co-authored-by: Lynda Lin <lynda.lin@optoma.com>
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2023-12-18 12:42:17 +00:00
7bd6496854 refactor: Fix Typo (#7445) 2023-12-16 18:23:11 +00:00
537f6e7f68 docs: add steps for local development (#7449)
* docs: add steps for local development #7434

* docs: minor tweaks

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2023-12-16 19:18:35 +01:00
6dfa89e846 fix: emitted visible scene bounds not accounting for offsets (#7450) 2023-12-16 17:32:54 +01:00
561e919a2e fix: import Socket as type (#7446) 2023-12-16 11:15:04 +01:00
20e3acf7a6 feat: bump socket.io-client & collab tweaks (#7444) 2023-12-16 00:23:59 +01:00
2c0929e537 fix: follow-mode tweaks (#7443) 2023-12-15 15:16:25 +01:00
aad8ab0123 feat: follow mode (#6848)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2023-12-15 00:07:11 +01:00
88a2b286c7 feat: move utils to utils package and make @excalidraw/utils a workspace (#7432)
* feat: move utils to utils package and make @excalidraw/utils a workspace

* remove esm and update types path

* remove esm script

* fix package.json and yarn.lock

* update path

* fix

* fix lint and test
2023-12-13 21:51:27 +05:30
f8c48e44e0 Auto commit: Calculate translation coverage 2023-12-13 11:32:16 +00:00
f37bc01fe7 New translations en.json (Polish) 2023-12-13 12:32:03 +01:00
ae460c569a Auto commit: Calculate translation coverage 2023-12-13 10:07:05 +00:00
1e535dd779 New translations en.json (Hindi) 2023-12-13 11:06:51 +01:00
ea8f5a124e New translations en.json (Marathi) 2023-12-13 11:06:49 +01:00
93ad17baa7 Auto commit: Calculate translation coverage 2023-12-13 06:16:20 +00:00
b933ddb315 New translations en.json (Marathi) 2023-12-13 07:16:04 +01:00
e010d12752 New translations en.json (Portuguese, Brazilian) 2023-12-13 07:16:03 +01:00
3e4c51ebf9 Auto commit: Calculate translation coverage 2023-12-13 05:08:26 +00:00
58df7cfe70 New translations en.json (Marathi) 2023-12-13 06:08:08 +01:00
b5ec37b698 Auto commit: Calculate translation coverage 2023-12-12 18:31:08 +00:00
624f17bd3c New translations en.json (German) 2023-12-12 19:30:51 +01:00
744525dcaf Auto commit: Calculate translation coverage 2023-12-12 15:18:00 +00:00
05190598bc New translations en.json (Spanish) 2023-12-12 16:17:43 +01:00
da6f52a155 Auto commit: Calculate translation coverage 2023-12-12 14:11:43 +00:00
e5d639270e New translations en.json (Slovenian) 2023-12-12 15:11:28 +01:00
11da1e5b30 New translations en.json (Spanish) 2023-12-12 15:11:27 +01:00
7cfc7c7811 Auto commit: Calculate translation coverage 2023-12-12 13:02:31 +00:00
cf6af5e70d New translations en.json (Chinese Traditional) 2023-12-12 14:02:16 +01:00
898dfff1a0 Auto commit: Calculate translation coverage 2023-12-12 11:29:53 +00:00
2660e4edde New translations en.json (Karakalpak) 2023-12-12 12:29:43 +01:00
8e05ff0c32 New translations en.json (Occitan) 2023-12-12 12:29:41 +01:00
c4cb94bff8 New translations en.json (Norwegian Bokmal) 2023-12-12 12:29:40 +01:00
10ee9c4019 New translations en.json (Hindi) 2023-12-12 12:29:37 +01:00
042bcf0638 New translations en.json (Azerbaijani) 2023-12-12 12:29:36 +01:00
8c30adaf10 New translations en.json (Norwegian Nynorsk) 2023-12-12 12:29:33 +01:00
2fcd49791e New translations en.json (Thai) 2023-12-12 12:29:32 +01:00
ae0c96b66c New translations en.json (Marathi) 2023-12-12 12:29:31 +01:00
c195bb0739 New translations en.json (Tamil) 2023-12-12 12:29:29 +01:00
6de5305e72 New translations en.json (Khmer) 2023-12-12 12:29:28 +01:00
ca1d426fc0 New translations en.json (Persian) 2023-12-12 12:29:27 +01:00
4fd311364a New translations en.json (Indonesian) 2023-12-12 12:29:26 +01:00
9d6180e2fd New translations en.json (Portuguese, Brazilian) 2023-12-12 12:29:25 +01:00
eeeb7e4ed9 New translations en.json (Galician) 2023-12-12 12:29:24 +01:00
9c248e8ae9 New translations en.json (Vietnamese) 2023-12-12 12:29:23 +01:00
d579328746 New translations en.json (Chinese Traditional) 2023-12-12 12:29:22 +01:00
3b3cfc391e New translations en.json (Chinese Simplified) 2023-12-12 12:29:21 +01:00
222fa328ba New translations en.json (Ukrainian) 2023-12-12 12:29:20 +01:00
a83498fc61 New translations en.json (Turkish) 2023-12-12 12:29:19 +01:00
0bd531b612 New translations en.json (Swedish) 2023-12-12 12:29:18 +01:00
b9b35833d3 New translations en.json (Slovenian) 2023-12-12 12:29:16 +01:00
eac2a23d72 New translations en.json (Slovak) 2023-12-12 12:29:15 +01:00
641a766607 New translations en.json (Russian) 2023-12-12 12:29:14 +01:00
bf38bd6620 New translations en.json (Portuguese) 2023-12-12 12:29:13 +01:00
775e551c3d New translations en.json (Polish) 2023-12-12 12:29:12 +01:00
909cc53c3a New translations en.json (Punjabi) 2023-12-12 12:29:11 +01:00
99e5542f03 New translations en.json (Dutch) 2023-12-12 12:29:10 +01:00
96b8340210 New translations en.json (Kurdish) 2023-12-12 12:29:08 +01:00
f92d025434 New translations en.json (Korean) 2023-12-12 12:29:07 +01:00
bbbed516f2 New translations en.json (Japanese) 2023-12-12 12:29:06 +01:00
c86a878a75 New translations en.json (Italian) 2023-12-12 12:29:05 +01:00
6676f24c4f New translations en.json (Hungarian) 2023-12-12 12:29:04 +01:00
e2e336bd95 New translations en.json (Basque) 2023-12-12 12:29:01 +01:00
c5ec66e585 New translations en.json (Greek) 2023-12-12 12:29:00 +01:00
a0c7aae672 New translations en.json (German) 2023-12-12 12:28:59 +01:00
95c8418dee New translations en.json (Danish) 2023-12-12 12:28:58 +01:00
21f5934e44 New translations en.json (Czech) 2023-12-12 12:28:57 +01:00
d6e2936bf8 New translations en.json (Catalan) 2023-12-12 12:28:56 +01:00
0aa1b62108 New translations en.json (Bulgarian) 2023-12-12 12:28:55 +01:00
c7c41155f6 New translations en.json (Arabic) 2023-12-12 12:28:54 +01:00
492a643506 New translations en.json (Spanish) 2023-12-12 12:28:52 +01:00
1cc8ad6ed9 New translations en.json (French) 2023-12-12 12:28:51 +01:00
8f57c10d9b New translations en.json (Romanian) 2023-12-12 12:28:50 +01:00
b635b10b59 chore: Update translations from Crowdin (#7176)
* New translations en.json (Azerbaijani)

* New translations en.json (Hindi)

* New translations en.json (Burmese)

* New translations en.json (Chinese Traditional, Hong Kong)

* New translations en.json (Sinhala)

* New translations en.json (Norwegian Bokmal)

* New translations en.json (Occitan)

* New translations en.json (Kabyle)

* New translations en.json (Karakalpak)

* Auto commit: Calculate translation coverage

* New translations en.json (Chinese Simplified)

* Auto commit: Calculate translation coverage

* New translations en.json (Marathi)

* New translations en.json (Hindi)

* Auto commit: Calculate translation coverage

* New translations en.json (Marathi)

* New translations en.json (Hindi)

* Auto commit: Calculate translation coverage

* New translations en.json (German)

* New translations en.json (Slovenian)

* Auto commit: Calculate translation coverage

* New translations en.json (Korean)

* Auto commit: Calculate translation coverage

* New translations en.json (Chinese Traditional)

* Auto commit: Calculate translation coverage

* New translations en.json (Russian)

* Auto commit: Calculate translation coverage

* New translations en.json (Romanian)

* New translations en.json (Spanish)

* Auto commit: Calculate translation coverage

* New translations en.json (Arabic)

* New translations en.json (Thai)

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Bulgarian)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (Danish)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Basque)

* New translations en.json (Finnish)

* New translations en.json (Hebrew)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Japanese)

* New translations en.json (Korean)

* New translations en.json (Kurdish)

* New translations en.json (Lithuanian)

* New translations en.json (Dutch)

* New translations en.json (Punjabi)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Slovak)

* New translations en.json (Slovenian)

* New translations en.json (Swedish)

* New translations en.json (Turkish)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Traditional)

* New translations en.json (Vietnamese)

* New translations en.json (Galician)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Indonesian)

* New translations en.json (Persian)

* New translations en.json (Khmer)

* New translations en.json (Tamil)

* New translations en.json (Bengali)

* New translations en.json (Marathi)

* New translations en.json (Norwegian Nynorsk)

* New translations en.json (Kazakh)

* New translations en.json (Latvian)

* New translations en.json (Azerbaijani)

* New translations en.json (Hindi)

* New translations en.json (Burmese)

* New translations en.json (Chinese Traditional, Hong Kong)

* New translations en.json (Sinhala)

* New translations en.json (Norwegian Bokmal)

* New translations en.json (Occitan)

* New translations en.json (Kabyle)

* New translations en.json (Karakalpak)

* Auto commit: Calculate translation coverage

* New translations en.json (Slovenian)

* Auto commit: Calculate translation coverage

* New translations en.json (Chinese Simplified)

* Auto commit: Calculate translation coverage

* New translations en.json (German)

* Auto commit: Calculate translation coverage

* New translations en.json (Russian)

* Auto commit: Calculate translation coverage

* New translations en.json (Polish)

* New translations en.json (Korean)

* Auto commit: Calculate translation coverage

* New translations en.json (Swedish)

* Auto commit: Calculate translation coverage

* New translations en.json (Swedish)

* Auto commit: Calculate translation coverage

* New translations en.json (French)

* Auto commit: Calculate translation coverage

* New translations en.json (Romanian)

* Auto commit: Calculate translation coverage

* New translations en.json (Chinese Simplified)

* New translations en.json (Catalan)

* Auto commit: Calculate translation coverage

* New translations en.json (Basque)

* Auto commit: Calculate translation coverage

* New translations en.json (Chinese Traditional)

* Auto commit: Calculate translation coverage

* New translations en.json (Spanish)

* Auto commit: Calculate translation coverage

* New translations en.json (Arabic)

* New translations en.json (Thai)

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Bulgarian)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (Danish)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Basque)

* New translations en.json (Finnish)

* New translations en.json (Hebrew)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Japanese)

* New translations en.json (Korean)

* New translations en.json (Kurdish)

* New translations en.json (Lithuanian)

* New translations en.json (Dutch)

* New translations en.json (Punjabi)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Slovak)

* New translations en.json (Slovenian)

* New translations en.json (Swedish)

* New translations en.json (Turkish)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Traditional)

* New translations en.json (Vietnamese)

* New translations en.json (Galician)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Indonesian)

* New translations en.json (Persian)

* New translations en.json (Khmer)

* New translations en.json (Tamil)

* New translations en.json (Bengali)

* New translations en.json (Marathi)

* New translations en.json (Norwegian Nynorsk)

* New translations en.json (Kazakh)

* New translations en.json (Latvian)

* New translations en.json (Azerbaijani)

* New translations en.json (Hindi)

* New translations en.json (Burmese)

* New translations en.json (Chinese Traditional, Hong Kong)

* New translations en.json (Sinhala)

* New translations en.json (Norwegian Bokmal)

* New translations en.json (Occitan)

* New translations en.json (Kabyle)

* New translations en.json (Karakalpak)

* Auto commit: Calculate translation coverage

* New translations en.json (Romanian)

* New translations en.json (Spanish)

* Auto commit: Calculate translation coverage

* New translations en.json (Slovenian)

* Auto commit: Calculate translation coverage

* New translations en.json (Chinese Traditional)

* Auto commit: Calculate translation coverage

* New translations en.json (Swedish)

* Auto commit: Calculate translation coverage

* New translations en.json (French)

* Auto commit: Calculate translation coverage

* New translations en.json (German)

* Auto commit: Calculate translation coverage

* New translations en.json (Danish)

* Auto commit: Calculate translation coverage

* New translations en.json (Italian)

* Auto commit: Calculate translation coverage

* New translations en.json (Chinese Simplified)

* Auto commit: Calculate translation coverage

* New translations en.json (Korean)

* Auto commit: Calculate translation coverage

* New translations en.json (Polish)

* New translations en.json (Slovak)

* Auto commit: Calculate translation coverage

* New translations en.json (Karakalpak)

* Auto commit: Calculate translation coverage

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Arabic)

* New translations en.json (Bulgarian)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (Danish)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Basque)

* New translations en.json (Finnish)

* New translations en.json (Hebrew)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Japanese)

* New translations en.json (Korean)

* New translations en.json (Kurdish)

* New translations en.json (Lithuanian)

* New translations en.json (Dutch)

* New translations en.json (Punjabi)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Slovak)

* New translations en.json (Slovenian)

* New translations en.json (Swedish)

* New translations en.json (Turkish)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Traditional)

* New translations en.json (Vietnamese)

* New translations en.json (Galician)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Indonesian)

* New translations en.json (Persian)

* New translations en.json (Khmer)

* New translations en.json (Tamil)

* New translations en.json (Bengali)

* New translations en.json (Marathi)

* New translations en.json (Thai)

* New translations en.json (Norwegian Nynorsk)

* New translations en.json (Kazakh)

* New translations en.json (Latvian)

* New translations en.json (Azerbaijani)

* New translations en.json (Hindi)

* New translations en.json (Burmese)

* New translations en.json (Chinese Traditional, Hong Kong)

* New translations en.json (Sinhala)

* New translations en.json (Norwegian Bokmal)

* New translations en.json (Occitan)

* New translations en.json (Kabyle)

* New translations en.json (Karakalpak)

* New translations en.json (Swedish)

* New translations en.json (Romanian)

* remove packages

---------

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
2023-12-12 16:56:22 +05:30
7ebda02b81 fix: update path of files in docs (#7428)
* fix: update path of files in docs

* remove root yarn install in size limit

* add vercel.json in dev-docs

* update config

* fix lint

* indent

* revert changelog and readme
2023-12-12 14:28:34 +05:30
d6cd8b78f1 build: decouple package deps and introduce yarn workspaces (#7415)
* feat: decouple package deps and introduce yarn workspaces

* update root directory

* fix

* fix scripts

* fix lint

* update path in scripts

* remove yarn.lock files from packages

* ignore workspace

* dummy

* dummy

* remove comment check

* revert workflow changes

* ignore ws when installing gh actions

* remove log

* update path

* fix

* fix typo
2023-12-12 11:32:51 +05:30
b7d7ccc929 fix: env variable for text-to-diagram and use frozen lock file when install deps in excalidraw-app (#7409) 2023-12-07 19:32:19 +05:30
f14ad61bd0 build: move build process and excalidraw-app dependencies in its own package.json (#7021)
* build: move build process and excalidraw-app dependencies in its own package.json

* fix

* fix public path

* move bug-issue-template to excalidraw-app

* make env vars accessible in excalidraw app

* update build script

* install when building

* add ts ignore

* fix build-version script

* update config in vercel.json

* add vercel config for example

* fix vercel config

* update install script in vercel

* update install script in lint.yml

* update install script in test workflows

* push locales to locales folder pwa

* add favicons to manifest

* move react to peer deps in editor

* fix ts

* Enable vite intellisense

* add global.d.ts for excalidraw-app

* remove console.log

* remove react, react-dom and vite from excalidraw-app deps

* increase size limit
2023-12-07 16:39:11 +05:30
8963baf5ad chore: upgrade to vite 5.x and vitest 1.x (#7407)
* chore: upgrade to vite 5.x and vitest 1.x

* fix coverage

* move to ESM for vite config

* use ESM for vitest
2023-12-07 15:30:08 +05:30
557add5bf7 feat: Support Mermaid Class diagrams 🥳 (#7381)
* feat: support mermaid class diagrams

* upgrade mermaid-to-excalidraw

* upgrade mermaid-to-excalidraw

* add sequence diagrams in supported chart types

* upgrade mermaid-to-excalidraw

* update i18n
2023-12-06 21:31:54 +05:30
b9cfbc2077 feat: add support for more UML arrowheads (#7391) 2023-12-06 16:00:00 +01:00
a04cc707c3 build(deps-dev): bump vite from 4.4.2 to 4.4.12 (#7393)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.2 to 4.4.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v4.4.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.4.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-06 15:31:44 +05:30
72ea8022bf docs: changelog instruction removed from docs (#7395)
changelog instruction removed from docs
2023-12-06 11:36:39 +05:30
4bdeaf999b feat: TTD dialog UI tweaks (#7384) 2023-12-04 17:50:30 +01:00
42d8c5a040 chore: update changelog and package.json for v0.17.1 (#7351) 2023-11-28 19:12:39 +05:30
f299514e44 fix: umd build so it can be used in browser (#7349)
* fix: umd build so it can be used in browser

* fix lint

* increase size limit

* update changelog

* use json.stringify for env preact variable so its accessible as string

* update changelog
2023-11-28 18:11:16 +05:30
dd220bcaea feat: TTD dialog tweaks (#7346)
* tweaks to TTD dialog ~ prepping for settings dialog

* tweaks to ttd parsing & error logging
2023-11-27 16:03:03 +01:00
fe75f29c15 fix: disable caching bounds for arrow labels (#7343) 2023-11-25 23:32:05 +01:00
14845a343b feat: text-to-diagram (#7325)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2023-11-25 21:11:03 +00:00
dd8a7d41e2 fix: bounds cached prematurely resulting in incorrectly rendered labels (#7339) 2023-11-24 19:55:56 +01:00
fda5c6fdf7 fix: t2c settings dialog spacing for apps that use CSS resets (#7337) 2023-11-24 16:32:00 +01:00
3d1631f375 feat: d2c tweaks (#7336) 2023-11-24 14:02:11 +01:00
c7ee46e7f8 feat: wireframe-to-code (#7334) 2023-11-23 23:07:53 +01:00
d1e4421823 feat: Expose ActionManager.registerAction through ExcalidrawImperativeAPI (#6995)
* feat: Expose `ActionManager` through `ExcalidrawImperativeAPI`

* Only expose `registerAction` instead of `ActionManager`
2023-11-22 15:22:49 -06:00
7c9cf30909 fix: make zoomToFit fitToViewport account for sidebar (#7298) 2023-11-17 15:56:19 +01:00
1e37dbd60e feat: change frame resizing behavior (#7307) 2023-11-17 14:37:43 +01:00
f8d5c2a1b6 build: allow a range of major node versions (#7306) 2023-11-17 14:23:19 +01:00
23b24ea5c3 build: use caret for specifying node version to avoid major upgrades automatically (#7297) 2023-11-16 16:18:38 +05:30
a528769b68 docs: upgrade to @excalidraw/excalidraw@0.17.0 (#7285) 2023-11-14 20:10:19 +05:30
ddb7585057 docs: Docs for v0.17.0 🚀 (#7248)
* feat: add docs for getCommonBounds

* docs: add docs for frames api support

* docs: update docs for regenerateIds opts in convertToExcalidrawElements

* add docs for ref removal

* add docs for lock support and insertOnCanvasDirectly in setActiveTool

* fix broken links

* update docs for next js support

* update docs for Preact

* add faq

* docs: add `onChange`, `onPointerDown`, `onPointerUp` docs

* docs: update `useDevice` docs

* update docs for disabling image tool

* add docs for withinBounds helpers

* fix lint

* upgrade excal

* add docusaurus2-dotenv for expose env vars

* fix env variable and upgrade excal

* Update dev-docs/docs/@excalidraw/excalidraw/api/excalidraw-element-skeleton.mdx

Co-authored-by: David Luzar <5153846+dwelle@users.noreply.github.com>

* update docs

Co-authored-by: David Luzar <5153846+dwelle@users.noreply.github.com>

* update docs for process.env

---------

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2023-11-14 19:54:34 +05:30
111a48ffb1 docs: release @excalidraw/excalidraw@0.17.0 🎉 (#7284) 2023-11-14 19:53:59 +05:30
54153629c0 chore: update release scripts (#7282)
* chore: update release scripts

* update docs
2023-11-14 16:37:57 +05:30
9c425224c7 feat: support disabling image tool (#6320)
Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
2023-11-14 10:25:41 +01:00
9d1d45a8ea chore: update changelog (#7279)
* chore: update changelog

* fix

* Update CHANGELOG.md
2023-11-14 13:11:05 +05:30
029c3c48ba fix: image insertion bugs (#7278) 2023-11-13 15:34:59 +01:00
adfd95be33 build: support preact 🥳 (#7255)
* build: support preact

* add log

* Simplify the config and generate prod and dev builds for preact

* update changelog

* remove logs

* use env variable so its available during build time

* update cl

* fix
2023-11-13 16:18:36 +05:30
ceb255e8ee fix: exportToSvg to honor frameRendering also for name not only for frame itself (#7270)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2023-11-12 22:34:05 +00:00
ae5b9a4ffd fix: not cloning elements on export polluting Scene mapping (#7276) 2023-11-12 23:32:12 +01:00
3d4ff59f40 fix: Can't toggle penMode off due to missing typecheck in togglePenMode (#7273)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2023-11-12 13:24:13 +01:00
7b00089314 chore: bump @excalidraw/random-username (#7272) 2023-11-11 19:23:22 +01:00
af6b81df40 fix: Replace hard coded font family with const value in addFrameLabelsAsTextElements (#7269) 2023-11-11 10:04:02 +01:00
02cc8440c4 feat: allow D&D dice app domain for embeds (#7263)
Co-authored-by: David Luzar <5153846+dwelle@users.noreply.github.com>
2023-11-10 15:29:19 +00:00
6363492cee fix: perf issue when ungrouping elements within frame (#7265)
Co-authored-by: Ryan Di <ryan.weihao.di@gmail.com>
2023-11-10 16:13:08 +01:00
900b317bf3 feat: remove full screen shortcut (#7222) 2023-11-10 14:44:02 +00:00
68179356e6 fix: Fixes the shortcut collision between "toggleHandTool" and "distributeHorizontally" (#7189)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
2023-11-10 15:33:02 +01:00
3ed15e95da Small typo fix frames.mdx (#7216) 2023-11-10 15:23:43 +01:00
798e1fd858 fix: allow pointer events when editing a linear element (#7238) 2023-11-10 15:21:59 +01:00
f66c93633c feat: make adaptive-roughness less aggressive (#7250) 2023-11-10 13:32:34 +01:00
cee00767df feat: support excalidrawAPI and remove refs support (#7251)
* feat: support excalidrawAPI and remove refs support

* update changelog

* remove ready and readyPromise

* update changelog

* update changelog
2023-11-10 15:33:43 +05:30
864c0b3ea8 feat: render frames on export (#7210) 2023-11-09 17:00:21 +01:00
a9a6f8eafb docs: update the docs with next js dynamic import support (#7252) 2023-11-09 16:03:35 +05:30
3c96943db3 test: fix mermaid test flake (#7249) 2023-11-07 18:06:15 +01:00
9006caff39 fix: make modal use viewport breakpoints (#7246) 2023-11-07 10:10:12 +01:00
ce7a847668 feat: export getCommonBounds util (#7247)
* feat: export getCommonBounds util

* add pr link

* fix
2023-11-07 14:19:13 +05:30
b1037b342d feat: make device breakpoints more specific (#7243) 2023-11-06 16:29:00 +01:00
18a7b97515 chore: Fix typo in comment in LocalData file (#7235) 2023-11-04 18:15:09 +01:00
e8def8da8d feat: Support mermaid flowchart and sequence diagrams to excalidraw diagrams 🥳 (#6920)
* feat: integrate mermaidToExcalidraw

* create mermaid to excal dialog

* allow mermaid syntax and export in preview

* fix

* fix webpack config

* fix markdown error by using named export

* center preview

* set elements as selected when inserted onto canvas

* persist mermaid data to storage

* store canvas data in refs

* load mermaid lazily

* tweak design

* compute width, height correctly for arrows

* fix undefined vertex issue

* add mermaid icon in dropdown

* add a note in dialog

* reset preview when error

* show error in preview when error

* show mermaid error messgae react way

* design tweaks

* add example and docs link

* fix

* tweak design to remove scroll bar

* show a spinner unless mermaid loaded

* regenerate ids when needed via programmatic api, this makes sure for mermaid diagrams ids are regenerated

* tweak

* add option to transform viewport to scene coords in transform api

* make opts optional and use 100% zoom when inserting to canvas

* fix arrow bindings in safari and firefox

* fix elements insert position and viewport centering

* fix: Update start/end points by 0.5 so bindings don't overlap with start/end bound element coordinates.

* defer rendering the preview

* tweak text

* fix tests

* remove only

* make design responsive

* fix: show extra tools dropdown in mobile

* fix mobile css

* width auto

* upgrade mermaid-to-excalidraw

* don't pass appState in deps as its not used

* upgrade mermaid-to-excalidraw to fix firefox issue

* use types from mermaid-to-excalidraw

* upgrade mermaid-to-excalidraw

* use stable version of mermaid-to-excalidraw

* upgrade mermaid-to-excalidraw

* fix width of shapes toolbar for smaller screen size and also fix regression of mobile menu

* use i18n

* better api

* enable test coverage in ui

* Add tests

* use common utils to update and get text editor

* updgrade mermaid-to-excalidraw to support sequence diagrams

* fix test

* don't update arrow container height anytime in when redrawing text bounding box

* increase size limit

* increase size limit of vendor to 900kb

* use openDialog for mermaid

* upgrade mermaid-to-excalidraw

* update frame id post generation

* upgrade mermaid-to-excalidraw to add entity codes support

* update size limit

* upgrade mermaid-to-excalidraw package with frame api changes

* upgrade mermaid-to-excalidraw to remove directive and use config

* don't highlight mermaid tool and remove unused api setSelection

* stop using loading state to update text area

* move some styling to scss

* review fixes

* use modifiedTableIcon props and remove stale snap

* css

* dialog css

* fix snap

* use dialog border

* change mermaidToExcalidrawLib to state

* better styling of errors

* make modal bigger

* fix mobile

* update snaps

* fix icon color

* fix dark mode insert button color

* horizontally center spinner

* render canvas conditionally on loaded state

* rd tweaks

* tweak class names

* remove max height

* typo in example

* upgrade mermaid-to-excalidraw

* simplify error state

* fix height & overflow on vertical breakpoint

* fix lint

* show errors in overlay

* set textarea font family

* reduce opacity

* update snap

* upgrade to mermaid  0.1.2

---------

Co-authored-by: dwelle <luzar.david@gmail.com>
2023-11-03 17:41:34 +05:30
a7db41c5ba fix: align input :hover/:focus with spec (#7225) 2023-11-02 16:06:26 +01:00
d8166d9e1d fix: dialog remounting on className updates (#7224) 2023-11-02 16:06:15 +01:00
81c0259041 docs: add npm downloads rate badge to README.md file (#7127) 2023-11-01 13:27:57 +01:00
f5c91c3a0f feat: support frames via programmatic API (#7205)
* update frame id post generation

* support frames via programmatic API

* fix types

* add test for frames

* throw error when element doesn't exist

* naming tweaks

* update the api to use children

* consider max of frame dimensions and calculated bounds of elements

* consider bound elements in frame api
2023-11-01 17:14:04 +05:30
9b8de8a12e test: disable flaky test (#7213) 2023-10-31 12:05:08 +01:00
ea677d4581 feat: make clipboard more robust and reintroduce contextmenu actions (#7198) 2023-10-28 19:29:28 +00:00
ec2de7205f fix: don't update label position when dragging labelled arrows (#6891)
* fix: don't update label position when dragging labelled arrows

* lint

* add test

* don't update coords for label when labelled arrow inside frame

* increase locales bundle size limit
2023-10-27 12:06:11 +05:30
Are
d5e3f436dc feat: add approximate elements in bbox detection (#6727)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-26 23:33:00 +02:00
dcf4592e79 feat: regenerate ids by default when using transform api and also update bindings by 0.5px to avoid possible overlapping (#7195)
* feat: regenerate ids by default when using transform api and also update bindings by 0.5px to avoid possible overlapping

* type

* increase limit as some past PR(s) increased the bundle size

* review fixes

* update changelog
2023-10-27 00:43:48 +05:30
d1f8eec174 feat: support giphy.com embed domain (#7192) 2023-10-26 00:00:50 +02:00
0f81c30276 fix: frame add/remove/z-index ordering changes (#7194) 2023-10-25 23:16:02 +02:00
f098789d16 fix: element relative position when dragging multiple elements on grid (#7107)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-25 22:48:03 +02:00
f794b0bb90 fix: freedraw non-solid bg hitbox not working (#7193) 2023-10-25 17:21:01 +02:00
104f64f1dc revert: remove bound-arrows from frames (#7190) 2023-10-25 10:39:19 +02:00
71ad3c5356 fix: Actions panel ux improvement (#6850)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-24 18:36:13 +00:00
afea0df141 feat: renderer tweaks (#6698) 2023-10-20 17:45:37 +02:00
d2a508104e fix: Better fill rendering with latest RoughJS (#7031)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-20 15:08:24 +02:00
3697618266 feat: support props.locked for setActiveTool (#7153)
Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
2023-10-20 13:16:23 +02:00
e7cc2337ea feat: add onChange, onPointerDown, onPointerUp api subs (#7154) 2023-10-20 13:08:22 +02:00
9eb89f9960 build(deps): bump @babel/traverse from 7.18.9 to 7.23.2 in /dev-docs (#7165)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-20 11:31:27 +02:00
ab1bcc7615 chore: Update translations from Crowdin (#6695) 2023-10-20 11:29:28 +02:00
b1cac35269 feat: Closing of "Save to.." Dialog on Save To Disk (#7168)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-19 17:51:50 +00:00
83f86e2b86 fix: Fix for Strange Symbol Appearing on Canvas after Deleting Grouped Graphics (Issue #7116) (#7170)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-19 12:59:39 +02:00
7e38cab76e build(deps): bump @babel/traverse from 7.21.4 to 7.23.2 (#7171)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-19 12:33:16 +02:00
2cabb1f1f4 fix: attempt to fix flake in wysiwyg tests (#7173) 2023-10-19 12:32:31 +02:00
63650f82d1 feat: Added Copy/Paste from Google Docs (#7136)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-19 12:14:23 +02:00
dde3dac931 feat: remove bound-arrows from frames (#7157) 2023-10-17 18:18:20 +02:00
5b94cffc74 fix: ensure ClipboardItem created in the same tick to fix safari (#7066) 2023-10-16 11:38:57 +02:00
aaf73c8ff3 fix: double image dialog shown on insert (#7152) 2023-10-16 00:19:46 +02:00
44d9d5fcac fix: wysiwyg left in undefined state on reload (#7123) 2023-10-13 14:29:54 +02:00
89a3bbddb7 test: add more resizing tests (#7028)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-12 20:59:02 +02:00
b86184a849 fix: ensure relative z-index of elements added to frame is retained (#7134) 2023-10-12 15:00:23 +02:00
b552166924 feat: new dark mode theme & light theme tweaks (#7104)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-12 14:58:33 +02:00
26ff3993bb feat: better laser cursor for dark mode (#7132) 2023-10-11 11:17:27 +02:00
7ad02c359a fix: memoize static canvas on props.renderConfig (#7131) 2023-10-10 23:31:23 +02:00
2523fe82e3 feat: laser pointer improvements (#7128) 2023-10-10 13:55:55 +02:00
4ea079eb85 fix: regression from #6739 preventing redirect link in view mode (#7120)
Co-authored-by: dwelle <luzar.david@gmail.com>
2023-10-09 12:26:49 +02:00
f20ba90ffa perf: improve element in frame check (#7124) 2023-10-09 16:32:27 +08:00
03da9112cf fix: update links to excalidraw-app (#7072) 2023-10-08 19:37:17 -05:00
a249f332a2 fix: ensure we do not stop laser update prematurely (#7100) 2023-10-06 12:00:35 +02:00
712 changed files with 58641 additions and 26876 deletions

View File

@ -6,6 +6,6 @@
!.prettierrc
!package.json
!public/
!src/
!packages/
!tsconfig.json
!yarn.lock

View File

@ -7,12 +7,11 @@ VITE_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfu
# collaboration WebSocket server (https://github.com/excalidraw/excalidraw-room)
VITE_APP_WS_SERVER_URL=http://localhost:3002
# set this only if using the collaboration workflow we use on excalidraw.com
VITE_APP_PORTAL_URL=
VITE_APP_PLUS_LP=https://plus.excalidraw.com
VITE_APP_PLUS_APP=https://app.excalidraw.com
VITE_APP_AI_BACKEND=http://localhost:3015
VITE_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8","authDomain":"excalidraw-oss-dev.firebaseapp.com","projectId":"excalidraw-oss-dev","storageBucket":"excalidraw-oss-dev.appspot.com","messagingSenderId":"664559512677","appId":"1:664559512677:web:a385181f2928d328a7aa8c"}'
# put these in your .env.local, or make sure you don't commit!

View File

@ -4,14 +4,13 @@ VITE_APP_BACKEND_V2_POST_URL=https://json.excalidraw.com/api/v2/post/
VITE_APP_LIBRARY_URL=https://libraries.excalidraw.com
VITE_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries
VITE_APP_PORTAL_URL=https://portal.excalidraw.com
VITE_APP_PLUS_LP=https://plus.excalidraw.com
VITE_APP_PLUS_APP=https://app.excalidraw.com
# Fill to set socket server URL used for collaboration.
# Meant for forks only: excalidraw.com uses custom VITE_APP_PORTAL_URL flow
VITE_APP_WS_SERVER_URL=
VITE_APP_AI_BACKEND=https://oss-ai.excalidraw.com
# socket server URL used for collaboration
VITE_APP_WS_SERVER_URL=https://oss-collab.excalidraw.com
VITE_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyAd15pYlMci_xIp9ko6wkEsDzAAA0Dn0RU","authDomain":"excalidraw-room-persistence.firebaseapp.com","databaseURL":"https://excalidraw-room-persistence.firebaseio.com","projectId":"excalidraw-room-persistence","storageBucket":"excalidraw-room-persistence.appspot.com","messagingSenderId":"654800341332","appId":"1:654800341332:web:4a692de832b55bd57ce0c1"}'

View File

@ -5,4 +5,4 @@ package-lock.json
firebase/
dist/
public/workbox
src/packages/excalidraw/types
packages/excalidraw/types

View File

@ -23,5 +23,5 @@ jobs:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Auto release
run: |
yarn add @actions/core
yarn add @actions/core -W
yarn autorelease

View File

@ -44,7 +44,7 @@ jobs:
- name: Auto release preview
id: "autorelease"
run: |
yarn add @actions/core
yarn add @actions/core -W
yarn autorelease preview ${{ github.event.issue.number }}
- name: Post comment post release
if: always()

View File

@ -16,7 +16,7 @@ jobs:
- name: Install and lint
run: |
yarn --frozen-lockfile
yarn install
yarn test:other
yarn test:code
yarn test:typecheck

View File

@ -22,11 +22,11 @@ jobs:
- name: Create report file
run: |
yarn locales-coverage
FILE_CHANGED=$(git diff src/locales/percentages.json)
FILE_CHANGED=$(git diff packages/excalidraw/locales/percentages.json)
if [ ! -z "${FILE_CHANGED}" ]; then
git config --global user.name 'Excalidraw Bot'
git config --global user.email 'bot@excalidraw.com'
git add src/locales/percentages.json
git add packages/excalidraw/locales/percentages.json
git commit -am "Auto commit: Calculate translation coverage"
git push
fi

View File

@ -15,16 +15,14 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18.x
- name: Install
run: yarn --frozen-lockfile
- name: Install in src/packages/excalidraw
run: yarn --frozen-lockfile
working-directory: src/packages/excalidraw
- name: Install in packages/excalidraw
run: yarn
working-directory: packages/excalidraw
env:
CI: true
- uses: andresz1/size-limit-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
build_script: build:umd
build_script: build:esm
skip_step: install
directory: src/packages/excalidraw
directory: packages/excalidraw

View File

@ -16,7 +16,7 @@ jobs:
with:
node-version: "18.x"
- name: "Install Deps"
run: yarn --frozen-lockfile
run: yarn install
- name: "Test Coverage"
run: yarn test:coverage
- name: "Report Coverage"

View File

@ -13,5 +13,5 @@ jobs:
node-version: 18.x
- name: Install and test
run: |
yarn --frozen-lockfile
yarn install
yarn test:app

7
.gitignore vendored
View File

@ -21,10 +21,9 @@ npm-debug.log*
package-lock.json
yarn-debug.log*
yarn-error.log*
src/packages/excalidraw/types
src/packages/excalidraw/example/public/bundle.js
src/packages/excalidraw/example/public/excalidraw-assets-dev
src/packages/excalidraw/example/public/excalidraw.development.js
packages/excalidraw/types
coverage
dev-dist
html
examples/**/bundle.*
meta*.json

View File

@ -1,3 +0,0 @@
## 2020-10-13
- Added ability to embed scene source into exported PNG/SVG files so you can import the scene from them (open via `Load` button or drag & drop). #2219

View File

@ -25,6 +25,9 @@
<a href="https://github.com/excalidraw/excalidraw/blob/master/LICENSE">
<img alt="Excalidraw is released under the MIT license." src="https://img.shields.io/badge/license-MIT-blue.svg" />
</a>
<a href="https://www.npmjs.com/package/@excalidraw/excalidraw">
<img alt="npm downloads/month" src="https://img.shields.io/npm/dm/@excalidraw/excalidraw" />
</a>
<a href="https://docs.excalidraw.com/docs/introduction/contributing">
<img alt="PRs welcome!" src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" />
</a>
@ -82,7 +85,7 @@ We'll be adding these features as drop-in plugins for the npm package in the fut
## Quick start
Install the [Excalidraw npm package](https://www.npmjs.com/package/@excalidraw/excalidraw):
**Note:** following instructions are for installing the Excalidraw [npm package](https://www.npmjs.com/package/@excalidraw/excalidraw) when integrating Excalidraw into your own app. To run the repository locally for development, please refer to our [Development Guide](https://docs.excalidraw.com/docs/introduction/development).
```
npm install react react-dom @excalidraw/excalidraw
@ -94,7 +97,7 @@ or via yarn
yarn add react react-dom @excalidraw/excalidraw
```
Don't forget to check out our [Documentation](https://docs.excalidraw.com)!
Check out our [documentation](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/installation) for more details!
## Contributing

View File

@ -1,3 +1,3 @@
files:
- source: /src/locales/en.json
translation: /src/locales/%locale%.json
- source: /packages/excalidraw/locales/en.json
translation: /packages/excalidraw/locales/%locale%.json

View File

@ -34,7 +34,7 @@ Open the `Menu` in the below playground and you will see the `custom footer` ren
```jsx live noInline
const MobileFooter = ({}) => {
const device = useDevice();
if (device.isMobile) {
if (device.editor.isMobile) {
return (
<Footer>
<button

View File

@ -133,7 +133,7 @@ function App() {
}
```
Here is a [complete list](https://github.com/excalidraw/excalidraw/blob/master/src/components/mainMenu/DefaultItems.tsx) of the default items.
Here is a [complete list](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/components/mainMenu/DefaultItems.tsx) of the default items.
### MainMenu.Group

View File

@ -80,7 +80,7 @@ A given tab trigger button that switches to a given sidebar tab. It must be rend
| `className` | `string` | No | |
| `style` | `React.CSSProperties` | No | |
You can use the [`ref.toggleSidebar({ name: "custom" })`](/docs/@excalidraw/excalidraw/api/props/ref#toggleSidebar) api to control the sidebar, but we export a trigger button to make UI use cases easier.
You can use the [`ref.toggleSidebar({ name: "custom" })`](/docs/@excalidraw/excalidraw/api/props/excalidraw-api#toggleSidebar) api to control the sidebar, but we export a trigger button to make UI use cases easier.
## Example

View File

@ -37,7 +37,7 @@ Defaults to `THEME.LIGHT` unless passed in `initialData.appState.theme`
### MIME_TYPES
[`MIME_TYPES`](https://github.com/excalidraw/excalidraw/blob/master/src/constants.ts#L101) contains all the mime types supported by `Excalidraw`.
[`MIME_TYPES`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/constants.ts#L101) contains all the mime types supported by `Excalidraw`.
**How to use **

View File

@ -2,21 +2,25 @@
We support a simplified API to make it easier to generate Excalidraw elements programmatically. This API is in beta and subject to change before stable. You can check the [PR](https://github.com/excalidraw/excalidraw/pull/6546) for more details.
For this purpose we introduced a new type [`ExcalidrawElementSkeleton`](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L133). This is the simplified version of [`ExcalidrawElement`](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L134) type with the minimum possible attributes so that creating elements programmatically is much easier (especially for cases like binding arrows or creating text containers).
For this purpose we introduced a new type [`ExcalidrawElementSkeleton`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133). This is the simplified version of [`ExcalidrawElement`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L134) type with the minimum possible attributes so that creating elements programmatically is much easier (especially for cases like binding arrows or creating text containers).
The [`ExcalidrawElementSkeleton`](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L133) can be converted to fully qualified Excalidraw elements by using [`convertToExcalidrawElements`](/docs/@excalidraw/excalidraw/api/excalidraw-element-skeleton#converttoexcalidrawelements).
The [`ExcalidrawElementSkeleton`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133) can be converted to fully qualified Excalidraw elements by using [`convertToExcalidrawElements`](/docs/@excalidraw/excalidraw/api/excalidraw-element-skeleton#converttoexcalidrawelements).
## convertToExcalidrawElements
**_Signature_**
<pre>
convertToExcalidrawElements(elements:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L133">
ExcalidrawElementSkeleton
</a>
)
</pre>
```ts
convertToExcalidrawElements(
elements: ExcalidrawElementSkeleton,
opts?: { regenerateIds: boolean }
): ExcalidrawElement[]
```
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `elements` | [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L137) | | The Excalidraw element Skeleton which needs to be converted to Excalidraw elements. |
| `opts` | `{ regenerateIds: boolean }` | ` {regenerateIds: true}` | By default `id` will be regenerated for all the elements irrespective of whether you pass the `id` so if you don't want the ids to regenerated, you can set this attribute to `false`. |
**_How to use_**
@ -24,13 +28,13 @@ The [`ExcalidrawElementSkeleton`](https://github.com/excalidraw/excalidraw/blob/
import { convertToExcalidrawElements } from "@excalidraw/excalidraw";
```
This function converts the Excalidraw Element Skeleton to excalidraw elements which could be then rendered on the canvas. Hence calling this function is necessary before passing it to APIs like [`initialData`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/initialdata), [`updateScene`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/ref#updatescene) if you are using the Skeleton API
This function converts the Excalidraw Element Skeleton to excalidraw elements which could be then rendered on the canvas. Hence calling this function is necessary before passing it to APIs like [`initialData`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/initialdata), [`updateScene`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/excalidraw-api#updatescene) if you are using the Skeleton API
## Supported Features
### Rectangle, Ellipse, and Diamond
To create these shapes you need to pass its `type` and `x` and `y` coordinates for position. The rest of the attributes are optional_.
To create these shapes you need to pass its `type` and `x` and `y` coordinates for position. The rest of the attributes are optional\_.
For the Skeleton API to work, `convertToExcalidrawElements` needs to be called before passing it to Excalidraw Component via initialData, updateScene or any such API.
@ -67,7 +71,7 @@ function App() {
}
```
You can pass additional [`properties`](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L27) as well to decorate the shapes.
You can pass additional [`properties`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L27) as well to decorate the shapes.
:::info
@ -188,7 +192,7 @@ convertToExcalidrawElements([
### Text Containers
In addition to `type`, `x` and `y` properties, [`label`](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L124C7-L130C59) property is required for text containers. The `text` property in `label` is required, rest of the attributes are optional.
In addition to `type`, `x` and `y` properties, [`label`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L124C7-L130C59) property is required for text containers. The `text` property in `label` is required, rest of the attributes are optional.
If you don't provide the dimensions of container, we calculate it based of the label dimensions.
@ -322,7 +326,7 @@ convertToExcalidrawElements([
### Arrow bindings
To bind arrow to a shape you need to specify its [`start`](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L86) and [`end`](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L54) properties. You need to pass either `type` or `id` property in `start` and `end` properties, rest of the attributes are optional
To bind arrow to a shape you need to specify its [`start`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L86) and [`end`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L54) properties. You need to pass either `type` or `id` property in `start` and `end` properties, rest of the attributes are optional
```js
convertToExcalidrawElements([
@ -427,3 +431,45 @@ convertToExcalidrawElements([
```
![image](https://github.com/excalidraw/excalidraw/assets/11256141/a8b047c8-2eed-4aea-82a2-e1e6bbddb8d4)
### Frames
To create a frame, you need to pass `type`, `children` (list of Excalidraw element ids). The rest of the attributes are optional.
```ts
{
type: "frame";
children: readonly ExcalidrawElement["id"][];
name?: string;
} & Partial<ExcalidrawFrameElement>);
```
```ts
convertToExcalidrawElements([
{
"type": "rectangle",
"x": 10,
"y": 10,
"strokeWidth": 2,
"id": "1"
},
{
"type": "diamond",
"x": 120,
"y": 20,
"backgroundColor": "#fff3bf",
"strokeWidth": 2,
"label": {
"text": "HELLO EXCALIDRAW",
"strokeColor": "#099268",
"fontSize": 30
},
"id": "2"
},
{
"type": "frame",
"children": ["1", "2"],
"name": "My frame"
}]
}
```

View File

@ -1,27 +1,26 @@
# ref
# excalidrawAPI
<pre>
<a href="https://reactjs.org/docs/refs-and-the-dom.html#creating-refs">
createRef
</a>{" "}
&#124;{" "}
<a href="https://reactjs.org/docs/hooks-reference.html#useref">useRef</a>{" "}
&#124;{" "}
<a href="https://reactjs.org/docs/refs-and-the-dom.html#callback-refs">
callbackRef
</a>{" "}
&#124; <br />
&#123; current: &#123; readyPromise: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L460">
resolvablePromise
</a> } }
(api:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L616">
ExcalidrawAPI
</a>
) => void;
</pre>
You can pass a `ref` when you want to access some excalidraw APIs. We expose the below APIs:
Once the callback is triggered, you will need to store the api in state to access it later.
```jsx showLineNumbers
export default function App() {
const [excalidrawAPI, setExcalidrawAPI] = useState(null);
return <Excalidraw excalidrawAPI={{(api)=> setExcalidrawAPI(api)}} />;
}
```
You can use this prop when you want to access some [Excalidraw APIs](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L616). We expose the below APIs :point_down:
| API | Signature | Usage |
| --- | --- | --- |
| ready | `boolean` | This is set to true once Excalidraw is rendered |
| [readyPromise](#readypromise) | `function` | This promise will be resolved with the api once excalidraw has rendered. This will be helpful when you want do some action on the host app once this promise resolves. For this to work you will have to pass ref as shown [here](#readypromise) |
| [updateScene](#updatescene) | `function` | updates the scene with the sceneData |
| [updateLibrary](#updatelibrary) | `function` | updates the scene with the sceneData |
| [addFiles](#addfiles) | `function` | add files data to the appState |
@ -38,61 +37,22 @@ You can pass a `ref` when you want to access some excalidraw APIs. We expose the
| [setActiveTool](#setactivetool) | `function` | This API can be used to set the active tool |
| [setCursor](#setcursor) | `function` | This API can be used to set customise the mouse cursor on the canvas |
| [resetCursor](#resetcursor) | `function` | This API can be used to reset to default mouse cursor on the canvas |
| [toggleMenu](#togglemenu) | `function` | Toggles specific menus on/off |
| [toggleSidebar](#toggleSidebar) | `function` | Toggles specific sidebar on/off |
| [onChange](#onChange) | `function` | Subscribes to change events |
| [onPointerDown](#onPointerDown) | `function` | Subscribes to `pointerdown` events |
| [onPointerUp](#onPointerUp) | `function` | Subscribes to `pointerup` events |
## readyPromise
:::info The `Ref` support has been removed in v0.17.0 so if you are using refs, please update the integration to use the `excalidrawAPI`.
<pre>
const excalidrawRef = &#123; current:&#123; readyPromise:
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L460">
&nbsp;resolvablePromise
</a>
&nbsp;&#125; &#125;
</pre>
Additionally `ready` and `readyPromise` from the API have been discontinued. These APIs were found to be superfluous, and as part of the effort to streamline the APIs and maintain simplicity, they were removed in version v0.17.0.
Since plain object is passed as a `ref`, the `readyPromise` is resolved as soon as the component is mounted. Most of the time you will not need this unless you have a specific use case where you can't pass the `ref` in the react way and want to do some action on the host when this promise resolves.
```jsx showLineNumbers
const resolvablePromise = () => {
let resolve;
let reject;
const promise = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
promise.resolve = resolve;
promise.reject = reject;
return promise;
};
const App = () => {
const excalidrawRef = useMemo(
() => ({
current: {
readyPromise: resolvablePromise(),
},
}),
[],
);
useEffect(() => {
excalidrawRef.current.readyPromise.then((api) => {
console.log("loaded", api);
});
}, [excalidrawRef]);
return (
<div style={{ height: "500px" }}>
<Excalidraw ref={excalidrawRef} />
</div>
);
};
```
:::
## updateScene
<pre>
(scene:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L339">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L339">
sceneData
</a>
) => void
@ -102,9 +62,9 @@ You can use this function to update the scene with the sceneData. It accepts the
| Name | Type | Description |
| --- | --- | --- |
| `elements` | [`ImportedDataState["elements"]`](https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L38) | The `elements` to be updated in the scene |
| `appState` | [`ImportedDataState["appState"]`](https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L39) | The `appState` to be updated in the scene. |
| `collaborators` | <code>Map<string, <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37">Collaborator></a></code> | The list of collaborators to be updated in the scene. |
| `elements` | [`ImportedDataState["elements"]`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L38) | The `elements` to be updated in the scene |
| `appState` | [`ImportedDataState["appState"]`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L39) | The `appState` to be updated in the scene. |
| `collaborators` | <code>Map<string, <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L37">Collaborator></a></code> | The list of collaborators to be updated in the scene. |
| `commitToHistory` | `boolean` | Implies if the `history (undo/redo)` should be recorded. Defaults to `false`. |
```jsx live
@ -165,13 +125,13 @@ function App() {
<pre>
(opts: &#123; <br /> libraryItems:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L249">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L249">
LibraryItemsSource
</a>
;<br /> merge?: boolean; <br /> prompt?: boolean;
<br /> openLibraryMenu?: boolean;
<br /> defaultStatus?: "unpublished" | "published"; <br /> &#125;) => Promise&lt;
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L246">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L246">
LibraryItems
</a>
&gt;
@ -181,7 +141,7 @@ You can use this function to update the library. It accepts the below attributes
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `libraryItems` | [LibraryItemsSource](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L249) | \_ | The `libraryItems` to be replaced/merged with current library |
| `libraryItems` | [LibraryItemsSource](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L249) | \_ | The `libraryItems` to be replaced/merged with current library |
| `merge` | boolean | `false` | Whether to merge with existing library items. |
| `prompt` | boolean | `false` | Whether to prompt user for confirmation. |
| `openLibraryMenu` | boolean | `false` | Keep the library menu open after library is updated. |
@ -229,7 +189,7 @@ function App() {
</button>
<Excalidraw
ref={(api) => setExcalidrawAPI(api)}
// initial data retrieved from https://github.com/excalidraw/excalidraw/blob/master/dev-docs/src/initialData.js
// initial data retrieved from https://github.com/excalidraw/excalidraw/blob/master/dev-docs/packages/excalidraw/initialData.js
initialData={{
libraryItems: initialData.libraryItems,
appState: { openSidebar: "library" },
@ -244,7 +204,7 @@ function App() {
<pre>
(files:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L59">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L59">
BinaryFileData
</a>
) => void
@ -264,7 +224,7 @@ Resets the scene. If `resetLoadingState` is passed as true then it will also for
<pre>
() =>{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L115">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L115">
ExcalidrawElement[]
</a>
</pre>
@ -275,7 +235,7 @@ Returns all the elements including the deleted in the scene.
<pre>
() => NonDeleted&#60;
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L115">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L115">
ExcalidrawElement
</a>
[]&#62;
@ -287,7 +247,7 @@ Returns all the elements excluding the deleted in the scene
<pre>
() =>{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">
AppState
</a>
</pre>
@ -328,7 +288,7 @@ Scroll the nearest element out of the elements supplied to the center of the vie
| Attribute | type | default | Description |
| --- | --- | --- | --- |
| target | [ExcalidrawElement](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L115) &#124; [ExcalidrawElement[]](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L115) | All scene elements | The element(s) to scroll to. |
| target | [ExcalidrawElement](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L115) &#124; [ExcalidrawElement[]](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L115) | All scene elements | The element(s) to scroll to. |
| opts.fitToContent | boolean | false | Whether to fit the elements to viewport by automatically changing zoom as needed. Note that the zoom range is between 10%-100%. |
| opts.fitToViewport | boolean | false | Similar to fitToContent but the zoom range is not limited. If elements are smaller than the viewport, zoom will go above 100%. |
| opts.viewportZoomFactor | number | 0.7 | when fitToViewport=true, how much screen should the content cover, between 0.1 (10%) and 1 (100%) |
@ -376,7 +336,7 @@ The unique id of the excalidraw component. This can be used to identify the exca
<pre>
() =>{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L82">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L82">
files
</a>
</pre>
@ -387,14 +347,25 @@ This API can be used to get the files present in the scene. It may contain files
This API has the below signature. It sets the `tool` passed in param as the active tool.
<pre>
(tool: <br /> &#123; type:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/shapes.tsx#L15">
SHAPES
</a>
[number]["value"]&#124; "eraser" &#125; &#124;
<br /> &#123; type: "custom"; customType: string &#125;) => void
</pre>
```ts
(
tool: (
| (
| { type: Exclude<ToolType, "image"> }
| {
type: Extract<ToolType, "image">;
insertOnCanvasDirectly?: boolean;
}
)
| { type: "custom"; customType: string }
) & { locked?: boolean },
) => {};
```
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `type` | [ToolType](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L91) | `selection` | The tool type which should be set as active tool. When setting `image` as active tool, the insertion onto canvas when using image tool is disabled by default, so you can enable it by setting `insertOnCanvasDirectly` to `true` |
| `locked` | `boolean` | `false` | Indicates whether the the active tool should be locked. It behaves the same way when using the `lock` tool in the editor interface |
## setCursor
@ -421,3 +392,51 @@ This API is especially useful when you render a custom [`<Sidebar/>`](/docs/@exc
```
This API can be used to reset to default mouse cursor.
## onChange
```tsx
(
callback: (
elements: readonly ExcalidrawElement[],
appState: AppState,
files: BinaryFiles,
) => void
) => () => void
```
Subscribes to change events, similar to [`props.onChange`](/docs/@excalidraw/excalidraw/api/props#onchange).
Returns an unsubscribe function.
## onPointerDown
```tsx
(
callback: (
activeTool: AppState["activeTool"],
pointerDownState: PointerDownState,
event: React.PointerEvent<HTMLElement>,
) => void,
) => () => void
```
Subscribes to canvas `pointerdown` events.
Returns an unsubscribe function.
## onPointerUp
```tsx
(
callback: (
activeTool: AppState["activeTool"],
pointerDownState: PointerDownState,
event: PointerEvent,
) => void,
) => () => void
```
Subscribes to canvas `pointerup` events.
Returns an unsubscribe function.

View File

@ -1,18 +1,18 @@
# initialData
<pre>
&#123; elements?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement[]</a>, appState?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">AppState</a> &#125;
&#123; elements?: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a>, appState?: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a> &#125;
</pre>
This helps to load Excalidraw with `initialData`. It must be an object or a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) which resolves to an object containing the below optional fields.
| Name | Type | Description |
| --- | --- | --- |
| `elements` | [ExcalidrawElement[]](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114) | The `elements` with which `Excalidraw` should be mounted. |
| `appState` | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95) | The `AppState` with which `Excalidraw` should be mounted. |
| `elements` | [ExcalidrawElement[]](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114) | The `elements` with which `Excalidraw` should be mounted. |
| `appState` | [AppState](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95) | The `AppState` with which `Excalidraw` should be mounted. |
| `scrollToContent` | `boolean` | This attribute indicates whether to `scroll` to the nearest element to center once `Excalidraw` is mounted. By default, it will not scroll the nearest element to the center. Make sure you pass `initialData.appState.scrollX` and `initialData.appState.scrollY` when `scrollToContent` is false so that scroll positions are retained |
| `libraryItems` | [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L247) &#124; Promise&lt;[LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200)&gt; | This library items with which `Excalidraw` should be mounted. |
| `files` | [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L82) | The `files` added to the scene. |
| `libraryItems` | [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L247) &#124; Promise&lt;[LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L200)&gt; | This library items with which `Excalidraw` should be mounted. |
| `files` | [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L82) | The `files` added to the scene. |
You might want to use this when you want to load excalidraw with some initial elements and app state.

View File

@ -1,11 +1,11 @@
# Props
All `props` are *optional*.
All `props` are _optional_.
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| [`initialData`](/docs/@excalidraw/excalidraw/api/props/initialdata) | `object` &#124; `null` &#124; <code>Promise<object &#124; null></code> | `null` | The initial data with which app loads. |
| [`ref`](/docs/@excalidraw/excalidraw/api/props/ref) | `object` | _ | `Ref` to be passed to Excalidraw |
| [`initialData`](/docs/@excalidraw/excalidraw/api/props/initialdata) | `object` &#124; `null` &#124; <code>Promise<object &#124; null></code> | `null` | The initial data with which app loads. |
| [`excalidrawAPI`](/docs/@excalidraw/excalidraw/api/props/excalidraw-api) | `function` | _ | Callback triggered with the excalidraw api once rendered |
| [`isCollaborating`](#iscollaborating) | `boolean` | _ | This indicates if the app is in `collaboration` mode |
| [`onChange`](#onchange) | `function` | _ | This callback is triggered whenever the component updates due to any change. This callback will receive the excalidraw `elements` and the current `app state`. |
| [`onPointerUpdate`](#onpointerupdate) | `function` | _ | Callback triggered when mouse pointer is updated. |
@ -23,7 +23,7 @@ All `props` are *optional*.
| [`libraryReturnUrl`](#libraryreturnurl) | `string` | _ | What URL should [libraries.excalidraw.com](https://libraries.excalidraw.com) be installed to |
| [`theme`](#theme) | `"light"` &#124; `"dark"` | `"light"` | The theme of the Excalidraw component |
| [`name`](#name) | `string` | | Name of the drawing |
| [`UIOptions`](/docs/@excalidraw/excalidraw/api/props/ui-options) | `object` | [DEFAULT UI OPTIONS](https://github.com/excalidraw/excalidraw/blob/master/src/constants.ts#L151) | To customise UI options. Currently we support customising [`canvas actions`](#canvasactions) |
| [`UIOptions`](/docs/@excalidraw/excalidraw/api/props/ui-options) | `object` | [DEFAULT UI OPTIONS](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/constants.ts#L151) | To customise UI options. Currently we support customising [`canvas actions`](/docs/@excalidraw/excalidraw/api/props/ui-options#canvasactions) |
| [`detectScroll`](#detectscroll) | `boolean` | `true` | Indicates whether to update the offsets when nearest ancestor is scrolled. |
| [`handleKeyboardGlobally`](#handlekeyboardglobally) | `boolean` | `false` | Indicates whether to bind the keyboard events to document. |
| [`autoFocus`](#autofocus) | `boolean` | `false` | indicates whether to focus the Excalidraw component on page load |
@ -33,11 +33,11 @@ All `props` are *optional*.
### Storing custom data on Excalidraw elements
Beyond attributes that Excalidraw elements already support, you can store `custom` data on each `element` in a `customData` object. The type of the attribute is [`Record<string, any>`](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L66) and is optional.
Beyond attributes that Excalidraw elements already support, you can store `custom` data on each `element` in a `customData` object. The type of the attribute is [`Record<string, any>`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L66) and is optional.
You can use this to add any extra information you need to keep track of.
You can add `customData` to elements when passing them as [`initialData`](/docs/@excalidraw/excalidraw/api/props/initialdata), or using [`updateScene`](/docs/@excalidraw/excalidraw/api/props/ref#updatescene) / [`updateLibrary`](/docs/@excalidraw/excalidraw/api/props/ref#updatelibrary) afterwards.
You can add `customData` to elements when passing them as [`initialData`](/docs/@excalidraw/excalidraw/api/props/initialdata), or using [`updateScene`](/docs/@excalidraw/excalidraw/api/props/excalidraw-api#updatescene) / [`updateLibrary`](/docs/@excalidraw/excalidraw/api/props/excalidraw-api#updatelibrary) afterwards.
```js showLineNumbers
{
@ -59,11 +59,11 @@ Every time component updates, this callback if passed will get triggered and has
(excalidrawElements, appState, files) => void;
```
1. `excalidrawElements`: Array of [excalidrawElements](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114) in the scene.
1. `excalidrawElements`: Array of [excalidrawElements](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114) in the scene.
2. `appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95) of the scene.
2. `appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95) of the scene.
3. `files`: The [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64) which are added to the scene.
3. `files`: The [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L64) which are added to the scene.
Here you can try saving the data to your backend or local storage for example.
@ -79,22 +79,30 @@ This callback is triggered when mouse pointer is updated.
2.`button`: The position of the button. This will be one of `["down", "up"]`
3.`pointersMap`: [`pointers`](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L131) map of the scene
3.`pointersMap`: [`pointers`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L131) map of the scene
```js
(exportedElements, appState, canvas) => void
```
1. `exportedElements`: An array of [non deleted elements](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L87) which needs to be exported.
2. `appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95) of the scene.
1. `exportedElements`: An array of [non deleted elements](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L87) which needs to be exported.
2. `appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95) of the scene.
3. `canvas`: The `HTMLCanvasElement` of the scene.
### onPointerDown
This prop if passed will be triggered on pointer down events and has the below signature.
<pre>
(activeTool: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L115"> AppState["activeTool"]</a>, pointerDownState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L424">PointerDownState</a>) => void
(activeTool:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L115">
{" "}
AppState["activeTool"]
</a>
, pointerDownState: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L424">
PointerDownState
</a>) => void
</pre>
### onScrollChange
@ -110,7 +118,11 @@ This prop if passed will be triggered when canvas is scrolled and has the below
This callback is triggered if passed when something is pasted into the scene. You can use this callback in case you want to do something additional when the paste event occurs.
<pre>
(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L18">ClipboardData</a>, event: ClipboardEvent &#124; null) => boolean
(data:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/clipboard.ts#L18">
ClipboardData
</a>
, event: ClipboardEvent &#124; null) => boolean
</pre>
This callback must return a `boolean` value or a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) which resolves to a boolean value.
@ -123,7 +135,7 @@ This callback if supplied will get triggered when the library is updated and has
<pre>
(items:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L200">
LibraryItems
</a>
) => void | Promise&lt;any&gt;
@ -136,8 +148,11 @@ It is invoked with empty items when user clears the library. You can use this ca
This prop if passed will be triggered when clicked on `link`. To handle the redirect yourself (such as when using your own router for internal links), you must call `event.preventDefault()`.
<pre>
(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement</a>,
event: CustomEvent&lt;&#123; nativeEvent: MouseEvent }&gt;) => void
(element:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">
ExcalidrawElement
</a>
, event: CustomEvent&lt;&#123; nativeEvent: MouseEvent }&gt;) => void
</pre>
Example:
@ -167,7 +182,7 @@ const onLinkOpen: ExcalidrawProps["onLinkOpen"] = useCallback(
### langCode
Determines the `language` of the UI. It should be one of the [available language codes](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L14). Defaults to `en` (English). We also export default language and supported languages which you can import as shown below.
Determines the `language` of the UI. It should be one of the [available language codes](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/i18n.ts#L14). Defaults to `en` (English). We also export default language and supported languages which you can import as shown below.
```js
import { defaultLang, languages } from "@excalidraw/excalidraw";
@ -176,34 +191,34 @@ import { defaultLang, languages } from "@excalidraw/excalidraw";
| name | type |
| --- | --- |
| `defaultLang` | `string` |
| `languages` | [`Language[]`](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L15) |
| `languages` | [`Language[]`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/i18n.ts#L15) |
### viewModeEnabled
This prop indicates whether the app is in `view mode`. When supplied, the value takes precedence over *intialData.appState.viewModeEnabled*, the `view mode` will be fully controlled by the host app, and users won't be able to toggle it from within the app.
This prop indicates whether the app is in `view mode`. When supplied, the value takes precedence over _intialData.appState.viewModeEnabled_, the `view mode` will be fully controlled by the host app, and users won't be able to toggle it from within the app.
### zenModeEnabled
This prop indicates whether the app is in `zen mode`. When supplied, the value takes precedence over *intialData.appState.zenModeEnabled*, the `zen mode` will be fully controlled by the host app, and users won't be able to toggle it from within the app.
This prop indicates whether the app is in `zen mode`. When supplied, the value takes precedence over _intialData.appState.zenModeEnabled_, the `zen mode` will be fully controlled by the host app, and users won't be able to toggle it from within the app.
### gridModeEnabled
This prop indicates whether the shows the grid. When supplied, the value takes precedence over *intialData.appState.gridModeEnabled*, the grid will be fully controlled by the host app, and users won't be able to toggle it from within the app.
This prop indicates whether the shows the grid. When supplied, the value takes precedence over _intialData.appState.gridModeEnabled_, the grid will be fully controlled by the host app, and users won't be able to toggle it from within the app.
### libraryReturnUrl
If supplied, this URL will be used when user tries to install a library from [libraries.excalidraw.com](https://libraries.excalidraw.com).
Defaults to *window.location.origin + window.location.pathname*. To install the libraries in the same tab from which it was opened, you need to set `window.name` (to any alphanumeric string) — if it's not set it will open in a new tab.
Defaults to _window.location.origin + window.location.pathname_. To install the libraries in the same tab from which it was opened, you need to set `window.name` (to any alphanumeric string) — if it's not set it will open in a new tab.
### theme
This prop controls Excalidraw's theme. When supplied, the value takes precedence over *intialData.appState.theme*, the theme will be fully controlled by the host app, and users won't be able to toggle it from within the app unless *UIOptions.canvasActions.toggleTheme* is set to `true`, in which case the `theme` prop will control Excalidraw's default theme with ability to allow theme switching (you must take care of updating the `theme` prop when you detect a change to `appState.theme` from the [onChange](#onchange) callback).
This prop controls Excalidraw's theme. When supplied, the value takes precedence over _intialData.appState.theme_, the theme will be fully controlled by the host app, and users won't be able to toggle it from within the app unless _UIOptions.canvasActions.toggleTheme_ is set to `true`, in which case the `theme` prop will control Excalidraw's default theme with ability to allow theme switching (you must take care of updating the `theme` prop when you detect a change to `appState.theme` from the [onChange](#onchange) callback).
You can use [`THEME`](/docs/@excalidraw/excalidraw/api/utils#theme) to specify the theme.
### name
This prop sets the `name` of the drawing which will be used when exporting the drawing. When supplied, the value takes precedence over *intialData.appState.name*, the `name` will be fully controlled by host app and the users won't be able to edit from within Excalidraw.
This prop sets the `name` of the drawing which will be used when exporting the drawing. When supplied, the value takes precedence over _intialData.appState.name_, the `name` will be fully controlled by host app and the users won't be able to edit from within Excalidraw.
### detectScroll
@ -236,4 +251,4 @@ validateEmbeddable?: boolean | string[] | RegExp | RegExp[] | ((link: string) =>
This is an optional property. By default we support a handful of well-known sites. You may allow additional sites or disallow the default ones by supplying a custom validator. If you pass `true`, all URLs will be allowed. You can also supply a list of hostnames, RegExp (or list of RegExp objects), or a function. If the function returns `undefined`, the built-in validator will be used.
Supplying a list of hostnames (with or without `www.`) is the preferred way to allow a specific list of domains.
Supplying a list of hostnames (with or without `www.`) is the preferred way to allow a specific list of domains.

View File

@ -4,7 +4,7 @@
<pre>
(isMobile: boolean, appState:
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">
AppState
</a>) => JSX | null
</pre>
@ -66,7 +66,7 @@ function App() {
<pre>
(element: NonDeleted&lt;ExcalidrawEmbeddableElement&gt;, appState:{" "}
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">
AppState
</a>
) => JSX.Element | null

View File

@ -1,10 +1,10 @@
# UIOptions
This prop can be used to customise UI of Excalidraw. Currently we support customising [`canvasActions`](#canvasactions), [`dockedSidebarBreakpoint`](#dockedsidebarbreakpoint) and [`welcomeScreen`](#welcmescreen).
This prop can be used to customise UI of Excalidraw. Currently we support customising [`canvasActions`](#canvasactions), [`dockedSidebarBreakpoint`](#dockedsidebarbreakpoint) [`welcomeScreen`](#welcmescreen) and [`tools`](#tools).
<pre>
&#123;
<br /> canvasActions?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L372">
<br /> canvasActions?: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L372">
CanvasActions
</a>, <br /> dockedSidebarBreakpoint?: number, <br /> welcomeScreen?: boolean <br />
@ -55,7 +55,7 @@ If `UIOptions.canvasActions.export` is `false` the export button will not be ren
## dockedSidebarBreakpoint
This prop indicates at what point should we break to a docked, permanent sidebar. If not passed it defaults to [`MQ_RIGHT_SIDEBAR_MAX_WIDTH_PORTRAIT`](https://github.com/excalidraw/excalidraw/blob/master/src/constants.ts#L161).
This prop indicates at what point should we break to a docked, permanent sidebar. If not passed it defaults to [`MQ_RIGHT_SIDEBAR_MAX_WIDTH_PORTRAIT`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/constants.ts#L161).
If the _width_ of the _excalidraw_ container exceeds _dockedSidebarBreakpoint_, the sidebar will be `dockable` and the button to `dock` the sidebar will be shown
If user choses to `dock` the sidebar, it will push the right part of the UI towards the left, making space for the sidebar as shown below.
@ -70,3 +70,12 @@ function App() {
);
}
```
## tools
This `prop` controls the visibility of the tools in the editor.
Currently you can control the visibility of `image` tool via this prop.
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| image | boolean | true | Decides whether `image` tool should be visible.

View File

@ -20,16 +20,16 @@ exportToCanvas(&#123;<br/>&nbsp;
getDimensions,<br/>&nbsp;
files,<br/>&nbsp;
exportPadding?: number;<br/>
&#125;: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L21">ExportOpts</a>
&#125;: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/packages/utils.ts#L21">ExportOpts</a>
</pre>
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `elements` | [Excalidraw Element []](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114) | | The elements to be exported to canvas. |
| `appState` | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L23) | [Default App State](https://github.com/excalidraw/excalidraw/blob/master/src/appState.ts#L17) | The app state of the scene. |
| `elements` | [Excalidraw Element []](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114) | | The elements to be exported to canvas. |
| `appState` | [AppState](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/packages/utils.ts#L23) | [Default App State](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/appState.ts#L17) | The app state of the scene. |
| [`getDimensions`](#getdimensions) | `function` | _ | A function which returns the `width`, `height`, and optionally `scale` (defaults to `1`), with which canvas is to be exported. |
| `maxWidthOrHeight` | `number` | _ | The maximum `width` or `height` of the exported image. If provided, `getDimensions` is ignored. |
| `files` | [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L59) | _ | The files added to the scene. |
| `files` | [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L59) | _ | The files added to the scene. |
| `exportPadding` | `number` | `10` | The `padding` to be added on canvas. |
@ -105,7 +105,7 @@ function App() {
<pre>
exportToBlob(<br/>&nbsp;
opts: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L14">ExportOpts</a> & &#123;<br/>&nbsp;
opts: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/packages/utils.ts#L14">ExportOpts</a> & &#123;<br/>&nbsp;
mimeType?: string,<br/>&nbsp;
quality?: number,<br/>&nbsp;
exportPadding?: number;<br/>
@ -134,16 +134,16 @@ Returns a promise which resolves with a [blob](https://developer.mozilla.org/en-
<pre>
exportToSvg(&#123;<br/>&nbsp;
elements:&nbsp;
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">
ExcalidrawElement[]
</a>,<br/>&nbsp;
appState:
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95"> AppState
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95"> AppState
</a>,<br/>&nbsp;
exportPadding: number,<br/>&nbsp;
metadata: string,<br/>&nbsp;
files:&nbsp;
<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L59">
<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L59">
BinaryFiles
</a>,<br/>
&#125;);
@ -151,10 +151,10 @@ exportToSvg(&#123;<br/>&nbsp;
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| elements | [Excalidraw Element []](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114) | | The elements to exported as `svg `|
| appState | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95) | [defaultAppState](https://github.com/excalidraw/excalidraw/blob/master/src/appState.ts#L11) | The `appState` of the scene |
| elements | [Excalidraw Element []](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114) | | The elements to exported as `svg `|
| appState | [AppState](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95) | [defaultAppState](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/appState.ts#L11) | The `appState` of the scene |
| exportPadding | number | 10 | The `padding` to be added on canvas |
| files | [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64) | undefined | The `files` added to the scene. |
| files | [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L64) | undefined | The `files` added to the scene. |
This function returns a promise which resolves to `svg` of the exported drawing.
@ -164,7 +164,7 @@ This function returns a promise which resolves to `svg` of the exported drawing.
<pre>
exportToClipboard(<br/>&nbsp;
opts: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L21">ExportOpts</a> & &#123;<br/>&nbsp;
opts: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/packages/utils.ts#L21">ExportOpts</a> & &#123;<br/>&nbsp;
mimeType?: string,<br/>&nbsp;
quality?: number;<br/>&nbsp;
type: 'png' | 'svg' |'json'<br/>

View File

@ -8,7 +8,7 @@ id: "restore"
**_Signature_**
<pre>
restoreAppState(appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L34">ImportedDataState["appState"]</a>,<br/>&nbsp; localAppState: Partial&lt;<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">AppState</a>> | null): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">AppState</a>
restoreAppState(appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L34">ImportedDataState["appState"]</a>,<br/>&nbsp; localAppState: Partial&lt;<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a>> | null): <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a>
</pre>
**_How to use_**
@ -17,7 +17,7 @@ restoreAppState(appState: <a href="https://github.com/excalidraw/excalidraw/blob
import { restoreAppState } from "@excalidraw/excalidraw";
```
This function will make sure all the `keys` have appropriate `values` in [appState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95) and if any key is missing, it will be set to its `default` value.
This function will make sure all the `keys` have appropriate `values` in [appState](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95) and if any key is missing, it will be set to its `default` value.
When `localAppState` is supplied, it's used in place of values that are missing (`undefined`) in `appState` instead of the defaults.
Use this as a way to not override user's defaults if you persist them.
@ -29,16 +29,16 @@ You can pass `null` / `undefined` if not applicable.
<pre>
restoreElements(
elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ImportedDataState["elements"]</a>,<br/>&nbsp;
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement[]</a> | null | undefined): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement[]</a>,<br/>&nbsp;
elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ImportedDataState["elements"]</a>,<br/>&nbsp;
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a> | null | undefined): <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a>,<br/>&nbsp;
opts: &#123; refreshDimensions?: boolean, repairBindings?: boolean }<br/>
)
</pre>
| Prop | Type | Description |
| ---- | ---- | ---- |
| `elements` | <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ImportedDataState["elements"]</a> | The `elements` to be restored |
| [`localElements`](#localelements) | <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement[]</a> &#124; null &#124; undefined | When `localElements` are supplied, they are used to ensure that existing restored elements reuse `version` (and increment it), and regenerate `versionNonce`. |
| `elements` | <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ImportedDataState["elements"]</a> | The `elements` to be restored |
| [`localElements`](#localelements) | <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a> &#124; null &#124; undefined | When `localElements` are supplied, they are used to ensure that existing restored elements reuse `version` (and increment it), and regenerate `versionNonce`. |
| [`opts`](#opts) | `Object` | The extra optional parameter to configure restored elements
#### localElements
@ -70,15 +70,15 @@ Parameter `refreshDimensions` indicates whether we should also `recalculate` tex
<pre>
restore(
data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L34">ImportedDataState</a>,<br/>&nbsp;
localAppState: Partial&lt;<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">AppState</a>> | null | undefined,<br/>&nbsp;
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement[]</a> | null | undefined<br/>): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L4">DataState</a><br/>
data: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L34">ImportedDataState</a>,<br/>&nbsp;
localAppState: Partial&lt;<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a>> | null | undefined,<br/>&nbsp;
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a> | null | undefined<br/>): <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L4">DataState</a><br/>
opts: &#123; refreshDimensions?: boolean, repairBindings?: boolean }<br/>
)
</pre>
See [`restoreAppState()`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#restoreAppState) about `localAppState`, and [`restoreElements()`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#restoreElements) about `localElements`.
See [`restoreAppState()`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/packages/excalidraw/README.md#restoreAppState) about `localAppState`, and [`restoreElements()`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/packages/excalidraw/README.md#restoreElements) about `localElements`.
**_How to use_**
@ -93,7 +93,7 @@ This function makes sure elements and state is set to appropriate values and set
**_Signature_**
<pre>
restoreLibraryItems(libraryItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L34">ImportedDataState["libraryItems"]</a>,<br/>&nbsp;
restoreLibraryItems(libraryItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L34">ImportedDataState["libraryItems"]</a>,<br/>&nbsp;
defaultStatus: "published" | "unpublished")
</pre>

View File

@ -8,7 +8,7 @@ These are pure Javascript functions exported from the @excalidraw/excalidraw [`@
### serializeAsJSON
Takes the scene elements and state and returns a JSON string. `Deleted` elements as well as most properties from `AppState` are removed from the resulting JSON. (see [`serializeAsJSON()`](https://github.com/excalidraw/excalidraw/blob/master/src/data/json.ts#L42) source for details).
Takes the scene elements and state and returns a JSON string. `Deleted` elements as well as most properties from `AppState` are removed from the resulting JSON. (see [`serializeAsJSON()`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/json.ts#L42) source for details).
If you want to overwrite the `source` field in the `JSON` string, you can set `window.EXCALIDRAW_EXPORT_SOURCE` to the desired value.
@ -16,8 +16,8 @@ If you want to overwrite the `source` field in the `JSON` string, you can set `w
<pre>
serializeAsJSON(&#123;<br/>&nbsp;
elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement[]</a>,<br/>&nbsp;
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">AppState</a>,<br/>
elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a>,<br/>&nbsp;
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a>,<br/>
}): string
</pre>
@ -37,7 +37,7 @@ If you want to overwrite the source field in the JSON string, you can set `windo
<pre>
serializeLibraryAsJSON(
libraryItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200">LibraryItems[]</a>)
libraryItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L200">LibraryItems[]</a>)
</pre>
**How to use**
@ -53,7 +53,7 @@ Returns `true` if element is invisibly small (e.g. width & height are zero).
**_Signature_**
<pre>
isInvisiblySmallElement(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement</a>): boolean
isInvisiblySmallElement(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement</a>): boolean
</pre>
**How to use**
@ -80,10 +80,10 @@ excalidrawAPI.updateScene(scene);
<pre>
loadFromBlob(<br/>&nbsp;
blob: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>,<br/>&nbsp;
localAppState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">AppState</a> | null,<br/>&nbsp;
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement[]</a> | null,<br/>&nbsp;
localAppState: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a> | null,<br/>&nbsp;
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a> | null,<br/>&nbsp;
fileHandle?: FileSystemHandle | null <br/>
) => Promise&lt;<a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/restore.ts#L61">RestoredDataState</a>>
) => Promise&lt;<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/restore.ts#L61">RestoredDataState</a>>
</pre>
### loadLibraryFromBlob
@ -129,11 +129,11 @@ if (contents.type === MIME_TYPES.excalidraw) {
<pre>
loadSceneOrLibraryFromBlob(<br/>&nbsp;
blob: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>,
localAppState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">AppState</a> | null,<br/>&nbsp;
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement[]</a> | null,<br/>&nbsp;
blob: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>,<br/>&nbsp;
localAppState: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a> | null,<br/>&nbsp;
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a> | null,<br/>&nbsp;
fileHandle?: FileSystemHandle | null<br/>
) => Promise&lt;&#123; type: string, data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/restore.ts#L53">RestoredDataState</a> | <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L33">ImportedLibraryState</a>}>
) => Promise&lt;&#123; type: string, data: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/restore.ts#L53">RestoredDataState</a> | <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L33">ImportedLibraryState</a>}>
</pre>
### getFreeDrawSvgPath
@ -149,7 +149,7 @@ import { getFreeDrawSvgPath } from "@excalidraw/excalidraw";
**Signature**
<pre>
getFreeDrawSvgPath(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L182">ExcalidrawFreeDrawElement</a>)
getFreeDrawSvgPath(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L182">ExcalidrawFreeDrawElement</a>)
</pre>
### isLinearElement
@ -164,9 +164,9 @@ import { isLinearElement } from "@excalidraw/excalidraw";
**Signature**
```tsx
isLinearElement(elementType?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L80">ExcalidrawElement</a>): boolean
```
<pre>
isLinearElement(elementType?: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L80">ExcalidrawElement</a>): boolean
</pre>
### getNonDeletedElements
@ -181,7 +181,7 @@ import { getNonDeletedElements } from "@excalidraw/excalidraw";
**Signature**
<pre>
getNonDeletedElements(elements:<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114"> readonly ExcalidrawElement[]</a>): as readonly <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L125">NonDeletedExcalidrawElement[]</a>
getNonDeletedElements(elements:<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114"> readonly ExcalidrawElement[]</a>): as readonly <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L125">NonDeletedExcalidrawElement[]</a>
</pre>
### mergeLibraryItems
@ -195,8 +195,10 @@ import { mergeLibraryItems } from "@excalidraw/excalidraw";
**_Signature_**
<pre>
mergeLibraryItems(localItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L250">LibraryItems</a>,<br/>&nbsp;
otherItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200">LibraryItems</a>) => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L250">LibraryItems</a>
mergeLibraryItems(<br/>&nbsp;
localItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L250">LibraryItems</a>,<br/>&nbsp;
otherItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L200">LibraryItems</a><br/>
): <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L250">LibraryItems</a>
</pre>
### parseLibraryTokensFromUrl
@ -237,8 +239,8 @@ export const App = () => {
<pre>
useHandleLibrary(opts: &#123;<br/>&nbsp;
excalidrawAPI: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L494">ExcalidrawAPI</a>,<br/>&nbsp;
getInitialLibraryItems?: () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L253">LibraryItemsSource</a><br/>
excalidrawAPI: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L494">ExcalidrawAPI</a>,<br/>&nbsp;
getInitialLibraryItems?: () => <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L253">LibraryItemsSource</a><br/>
});
</pre>
@ -251,7 +253,7 @@ This function returns the current `scene` version.
**_Signature_**
<pre>
getSceneVersion(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114">ExcalidrawElement[]</a>)
getSceneVersion(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a>)
</pre>
**How to use**
@ -272,7 +274,7 @@ import { sceneCoordsToViewportCoords } from "@excalidraw/excalidraw";
<pre>
sceneCoordsToViewportCoords(&#123; sceneX: number, sceneY: number },<br/>&nbsp;
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">AppState</a><br/>): &#123; x: number, y: number }
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a><br/>): &#123; x: number, y: number }
</pre>
### viewportCoordsToSceneCoords
@ -287,7 +289,7 @@ import { viewportCoordsToSceneCoords } from "@excalidraw/excalidraw";
<pre>
viewportCoordsToSceneCoords(&#123; clientX: number, clientY: number },<br/>&nbsp;
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95">AppState</a><br/>): &#123;x: number, y: number}
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a><br/>): &#123;x: number, y: number}
</pre>
### useDevice
@ -299,7 +301,7 @@ Open the `main menu` in the below example to view the footer.
```jsx live noInline
const MobileFooter = ({}) => {
const device = useDevice();
if (device.isMobile) {
if (device.editor.isMobile) {
return (
<Footer>
<button
@ -331,14 +333,15 @@ const App = () => (
render(<App />);
```
The `device` has the following `attributes`
The `device` has the following `attributes`, some grouped into `viewport` and `editor` objects, per context.
| Name | Type | Description |
| --- | --- | --- |
| `isSmScreen` | `boolean` | Set to `true` when the device small screen is small (Width < `640px` ) |
| `isMobile` | `boolean` | Set to `true` when the device is `mobile` |
| `isTouchScreen` | `boolean` | Set to `true` for `touch` devices |
| `canDeviceFitSidebar` | `boolean` | Implies whether there is enough space to fit the `sidebar` |
| `viewport.isMobile` | `boolean` | Set to `true` when viewport is in `mobile` breakpoint |
| `viewport.isLandscape` | `boolean` | Set to `true` when the viewport is in `landscape` mode |
| `editor.canFitSidebar` | `boolean` | Set to `true` if there's enough space to fit the `sidebar` |
| `editor.isMobile` | `boolean` | Set to `true` when editor container is in `mobile` breakpoint |
| `isTouchScreen` | `boolean` | Set to `true` for `touch` when touch event detected |
### i18n
@ -347,8 +350,8 @@ To help with localization, we export the following.
| name | type |
| --- | --- |
| `defaultLang` | `string` |
| `languages` | [`Language[]`](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L15) |
| `useI18n` | [`() => { langCode, t }`](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L15) |
| `languages` | [`Language[]`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/i18n.ts#L15) |
| `useI18n` | [`() => { langCode, t }`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/i18n.ts#L15) |
```js
import { defaultLang, languages, useI18n } from "@excalidraw/excalidraw";
@ -383,3 +386,94 @@ function App() {
);
}
```
### getCommonBounds
This util can be used to get the common bounds of the passed elements.
**_Signature_**
```ts
getCommonBounds(
elements: readonly ExcalidrawElement[]
): readonly [
minX: number,
minY: number,
maxX: number,
maxY: number,
]
```
**_How to use_**
```js
import { getCommonBounds } from "@excalidraw/excalidraw";
```
### elementsOverlappingBBox
To filter `elements` that are inside, overlap, or contain the `bounds` rectangle.
The bounds check is approximate and does not precisely follow the element's shape. You can also supply `errorMargin` which effectively makes the `bounds` larger by that amount.
This API has 3 `type`s of operation: `overlap`, `contain`, and `inside`:
- `overlap` - filters elements that are overlapping or inside bounds.
- `contain` - filters elements that are inside bounds or bounds inside elements.
- `inside` - filters elements that are inside bounds.
**_Signature_**
<pre>
elementsOverlappingBBox(<br/>&nbsp;
elements: readonly NonDeletedExcalidrawElement[];<br/>&nbsp;
bounds: <a href="https://github.com/excalidraw/excalidraw/blob/9c425224c789d083bf16e0597ce4a429b9ee008e/src/element/bounds.ts#L37-L42">Bounds</a> | ExcalidrawElement;<br/>&nbsp;
errorMargin?: number;<br/>&nbsp;
type: "overlap" | "contain" | "inside";<br/>
): NonDeletedExcalidrawElement[];
</pre>
**_How to use_**
```js
import { elementsOverlappingBBox } from "@excalidraw/excalidraw";
```
### isElementInsideBBox
Lower-level API than `elementsOverlappingBBox` to check if a single `element` is inside `bounds`. If `eitherDirection=true`, returns `true` if `element` is fully inside `bounds` rectangle, or vice versa. When `false`, it returns `true` only for the former case.
**_Signature_**
<pre>
isElementInsideBBox(<br/>&nbsp;
element: NonDeletedExcalidrawElement,<br/>&nbsp;
bounds: <a href="https://github.com/excalidraw/excalidraw/blob/9c425224c789d083bf16e0597ce4a429b9ee008e/src/element/bounds.ts#L37-L42">Bounds</a>,<br/>&nbsp;
eitherDirection = false,<br/>
): boolean
</pre>
**_How to use_**
```js
import { isElementInsideBBox } from "@excalidraw/excalidraw";
```
### elementPartiallyOverlapsWithOrContainsBBox
Checks if `element` is overlapping the `bounds` rectangle, or is fully inside.
**_Signature_**
<pre>
elementPartiallyOverlapsWithOrContainsBBox(<br/>&nbsp;
element: NonDeletedExcalidrawElement,<br/>&nbsp;
bounds: <a href="https://github.com/excalidraw/excalidraw/blob/9c425224c789d083bf16e0597ce4a429b9ee008e/src/element/bounds.ts#L37-L42">Bounds</a>,<br/>
): boolean
</pre>
**_How to use_**
```js
import { elementPartiallyOverlapsWithOrContainsBBox } from "@excalidraw/excalidraw";
```

View File

@ -21,7 +21,7 @@ Most notably, you can customize the primary colors, by overriding these variable
- `--color-primary-light`
- `--color-primary-contrast-offset` — a slightly darker (in light mode), or lighter (in dark mode) `--color-primary` color to fix contrast issues (see [Chubb illusion](https://en.wikipedia.org/wiki/Chubb_illusion)). It will fall back to `--color-primary` if not present.
For a complete list of variables, check [theme.scss](https://github.com/excalidraw/excalidraw/blob/master/src/css/theme.scss), though most of them will not make sense to override.
For a complete list of variables, check [theme.scss](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/css/theme.scss), though most of them will not make sense to override.
```css showLineNumbers
.custom-styles .excalidraw {

View File

@ -13,7 +13,7 @@ To start the example app using the `@excalidraw/excalidraw` package, follow the
1. Install the dependencies
```bash
cd src/packages/excalidraw && yarn
cd packages/excalidraw && yarn
```
2. Start the example app
@ -43,7 +43,7 @@ Once the version is released `@excalibot` will post a comment with the release v
To release the next stable version follow the below steps:
```bash
yarn prerelease version
yarn prerelease:excalidraw
```
You need to pass the `version` for which you want to create the release. This will make the changes needed before making the release like updating `package.json`, `changelog` and more.
@ -51,7 +51,7 @@ You need to pass the `version` for which you want to create the release. This wi
The next step is to run the `release` script:
```bash
yarn release
yarn release:excalidraw
```
This will publish the package.

View File

@ -2,7 +2,7 @@
### Does this package support collaboration ?
No, Excalidraw package doesn't come with collaboration built in, since the implementation is specific to each host app. We expose APIs which you can use to communicate with Excalidraw which you can use to implement it. You can check our own implementation [here](https://github.com/excalidraw/excalidraw/blob/master/src/excalidraw-app/index.tsx). Here is a [detailed answer](https://github.com/excalidraw/excalidraw/discussions/3879#discussioncomment-1110524) on how you can achieve the same.
No, Excalidraw package doesn't come with collaboration built in, since the implementation is specific to each host app. We expose APIs which you can use to communicate with Excalidraw which you can use to implement it. You can check our own implementation [here](https://github.com/excalidraw/excalidraw/blob/master/excalidraw-app/index.tsx). Here is a [detailed answer](https://github.com/excalidraw/excalidraw/discussions/3879#discussioncomment-1110524) on how you can achieve the same.
### Turning off Aggressive Anti-Fingerprinting in Brave browser
@ -18,7 +18,7 @@ We strongly recommend turning it off. You can follow the steps below on how to d
2. Once opened, look for **Aggressively Block Fingerprinting**
![Aggresive block fingerprinting](../../assets/aggressive-block-fingerprint.png)
![Aggressive block fingerprinting](../../assets/aggressive-block-fingerprint.png)
3. Switch to **Block Fingerprinting**
@ -31,6 +31,17 @@ We strongly recommend turning it off. You can follow the steps below on how to d
If disabling this setting doesn't fix the display of text elements, please consider opening an [issue](https://github.com/excalidraw/excalidraw/issues/new) on our GitHub, or message us on [Discord](https://discord.gg/UexuTaE).
### ReferenceError: process is not defined
When using `vite` or any build tools, you will have to make sure the `process` is accessible as we are accessing `process.env.IS_PREACT` to decide whether to use `preact` build.
Since Vite removes env variables by default, you can update the vite config to ensure its available :point_down:
```
define: {
"process.env.IS_PREACT": JSON.stringify("true"),
},
```
## Need help?

View File

@ -30,25 +30,131 @@ function App() {
}
```
### Rendering Excalidraw only on client
### Next.js
Since _Excalidraw_ doesn't support server side rendering, you should render the component once the host is `mounted`.
Since Excalidraw doesn't support `server side rendering` so it should be rendered only on `client`. The way to achieve this in next.js is using `next.js dynamic import`.
The following workflow shows one way how to render Excalidraw on Next.js. We'll add more detailed and alternative Next.js examples, soon.
If you want to only import `Excalidraw` component you can do :point_down:
```jsx showLineNumbers
import { useState, useEffect } from "react";
import dynamic from "next/dynamic";
const Excalidraw = dynamic(
async () => (await import("@excalidraw/excalidraw")).Excalidraw,
{
ssr: false,
},
);
export default function App() {
const [Excalidraw, setExcalidraw] = useState(null);
useEffect(() => {
import("@excalidraw/excalidraw").then((comp) => setExcalidraw(comp.Excalidraw));
}, []);
return <>{Excalidraw && <Excalidraw />}</>;
return <Excalidraw />;
}
```
However the above component only works for named component exports. If you want to import some util / constant or something else apart from Excalidraw, then this approach will not work. Instead you can write a wrapper over Excalidraw and import the wrapper dynamically.
If you are using `pages router` then importing the wrapper dynamically would work, where as if you are using `app router` then you will have to also add `useClient` directive on top of the file in addition to dynamically importing the wrapper as shown :point_down:
<Tabs>
<TabItem value="Excalidraw Wrapper" label="Excalidraw Wrapper" >
```jsx showLineNumbers
"use client";
import { Excalidraw, convertToExcalidrawElements } from "@excalidraw/excalidraw";
import "@excalidraw/excalidraw/index.css";
const ExcalidrawWrapper: React.FC = () => {
console.info(convertToExcalidrawElements([{
type: "rectangle",
id: "rect-1",
width: 186.47265625,
height: 141.9765625,
},]));
return (
<div style={{height:"500px", width:"500px"}}>
<Excalidraw />
</div>
);
};
export default ExcalidrawWrapper;
```
</TabItem>
<TabItem value="pages" label="Pages router">
```jsx showLineNumbers
import dynamic from "next/dynamic";
// Since client components get prerenderd on server as well hence importing
// the excalidraw stuff dynamically with ssr false
const ExcalidrawWrapper = dynamic(
async () => (await import("../excalidrawWrapper")).default,
{
ssr: false,
},
);
export default function Page() {
return (
<ExcalidrawWrapper />
);
}
```
</TabItem>
<TabItem value="app" label="App router">
```jsx showLineNumbers
import dynamic from "next/dynamic";
// Since client components get prerenderd on server as well hence importing
// the excalidraw stuff dynamically with ssr false
const ExcalidrawWrapper = dynamic(
async () => (await import("../excalidrawWrapper")).default,
{
ssr: false,
},
);
export default function Page() {
return (
<ExcalidrawWrapper />
);
}
```
</TabItem>
</Tabs>
Here is a [source code](https://github.com/excalidraw/excalidraw/tree/master/examples/excalidraw/with-nextjs) for the example with app and pages router. You you can try it out [here](https://excalidraw-package-example-with-nextjs-gh6smrdnq-excalidraw.vercel.app/).
The `types` are available at `@excalidraw/excalidraw/types`, you can view [example for typescript](https://codesandbox.io/s/excalidraw-types-9h2dm)
### Preact
Since we support `umd` build ships with `react/jsx-runtime` and `react-dom/client` inlined with the package. This conflicts with `Preact` and hence the build doesn't work directly with `Preact`.
However we have shipped a separate build for `Preact` so if you are using `Preact` you need to set `process.env.IS_PREACT` to `true` to use the `Preact` build.
Once the above `env` variable is set, you will be able to use the package in `Preact` as well.
:::info
When using `vite` or any build tools, you will have to make sure the `process` is accessible as we are accessing `process.env.IS_PREACT` to decide whether to use `preact` build.
Since Vite removes env variables by default, you can update the vite config to ensure its available :point_down:
```
define: {
"process.env.IS_PREACT": JSON.stringify("true"),
},
```
:::
## Browser
To use it in a browser directly:
@ -99,7 +205,7 @@ import TabItem from "@theme/TabItem";
<h1>Excalidraw Embed Example</h1>
<div id="app"></div>
</div>
<script type="text/javascript" src="src/index.js"></script>
<script type="text/javascript" src="packages/excalidraw/index.js"></script>
</body>
</html>
```

View File

@ -38,9 +38,9 @@ Add the diagram type in switch case in [`parseMermaid`](https://github.com/excal
## Writing the Excalidraw Skeleton Convertor
With the completion of previous step, we have all the data, now we need to transform it so to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L133) format.
With the completion of previous step, we have all the data, now we need to transform it so to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133) format.
Similar to [`FlowChartToExcalidrawSkeletonConverter`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/converter/types/flowchart.ts#L24), you have to write the `{{diagramType}}ToExcalidrawSkeletonConverter` which parses the data received in previous step and returns the [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L133).
Similar to [`FlowChartToExcalidrawSkeletonConverter`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/converter/types/flowchart.ts#L24), you have to write the `{{diagramType}}ToExcalidrawSkeletonConverter` which parses the data received in previous step and returns the [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133).
Thats it, you have added the new diagram type 🥳, now lets test it out!

View File

@ -6,7 +6,7 @@ In this section we will be diving into how the [flowchart parser](https://github
![image](https://github.com/excalidraw/excalidraw/assets/11256141/2a097bbb-64bf-49d6-bf7f-21172bdb538d)
We use `diagram.parser.yy` attribute to parse the data. If you want to know more about how the `diagram.parse.yy` attribute looks like, you can check it [here](https://github.com/mermaid-js/mermaid/blob/00d06c7282a701849793680c1e97da1cfdfcce62/packages/mermaid/src/diagrams/flowchart/flowDb.js#L768), however for scope of flowchart we are using **3** APIs from this parser to compute `vertices`, `edges` and `clusters` as we need these data to transform to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L133C13-L133C38).
We use `diagram.parser.yy` attribute to parse the data. If you want to know more about how the `diagram.parse.yy` attribute looks like, you can check it [here](https://github.com/mermaid-js/mermaid/blob/00d06c7282a701849793680c1e97da1cfdfcce62/packages/mermaid/src/diagrams/flowchart/flowDb.js#L768), however for scope of flowchart we are using **3** APIs from this parser to compute `vertices`, `edges` and `clusters` as we need these data to transform to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133C13-L133C38).
For computing `vertices` and `edge`s lets consider the below svg generated by mermaid
@ -42,7 +42,7 @@ Considering the same example this is the response from the API
}
}
```
The dimensions and position is missing in this response and we need that to transform to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L133C13-L133C38), for this we have our own parser [`parseVertex`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/parseMermaid.ts#L178) which takes the above response and uses the `svg` together to compute position, dimensions and cleans up the response.
The dimensions and position is missing in this response and we need that to transform to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133C13-L133C38), for this we have our own parser [`parseVertex`](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/parseMermaid.ts#L178) which takes the above response and uses the `svg` together to compute position, dimensions and cleans up the response.
The final output from `parseVertex` looks like :point_down:

View File

@ -55,11 +55,11 @@ If you want to understand how flowchart parser works, you can navigate to [Flowc
## Converting to ExcalidrawElementSkeleton
Now we have all the data, we just need to transform it to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L133C13-L133C38) API so it can be rendered in Excalidraw.
Now we have all the data, we just need to transform it to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133C13-L133C38) API so it can be rendered in Excalidraw.
For this we have `converters` which takes the parsed mermaid data and gives back the Excalidraw Skeleton.
For Unsupported types, we have already mentioned above that we convert it to `dataURL` and return the ExcalidrawImageSkeleton.
For supported types, currently only flowchart, we have [flowchartConverter](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/converter/types/flowchart.ts#L24) which parses the data and converts to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/src/data/transform.ts#L133C13-L133C38).
For supported types, currently only flowchart, we have [flowchartConverter](https://github.com/excalidraw/mermaid-to-excalidraw/blob/master/src/converter/types/flowchart.ts#L24) which parses the data and converts to [ExcalidrawElementSkeleton](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/transform.ts#L133C13-L133C38).
![image](https://github.com/excalidraw/excalidraw/assets/11256141/00226e9d-043d-4a08-989a-3ad9d2a574f1)

View File

@ -0,0 +1,22 @@
# Frames
## Ordering
Frames should be ordered where frame children come first, followed by the frame element itself:
```
[
other_element,
frame1_child1,
frame1_child2,
frame1,
other_element,
frame2_child1,
frame2_child2,
frame2,
other_element,
...
]
```
If not ordered correctly, the editor will still function, but the elements may not be rendered and clipped correctly. Further, the renderer relies on this ordering for performance optimizations.

View File

@ -52,15 +52,6 @@ Make sure the title starts with a semantic prefix:
- **chore**: Other changes that don't modify src or test files
- **revert**: Reverts a previous commit
### Changelog
Add a brief description of your pull request to the changelog located here: [changelog](https://github.com/excalidraw/excalidraw/blob/master/CHANGELOG.md)
Notes:
- Make sure to prepend to the section corresponding with the semantic prefix you selected in the title
- Link to your pull request - this will require updating the CHANGELOG _after_ creating the pull request
### Testing
Once you submit your pull request it will automatically be tested. Be sure to check the results of the test and fix any issues that arise.

View File

@ -1,6 +1,11 @@
// @ts-check
// Note: type annotations allow type checking and IDEs autocompletion
// Set the env variable to false so the excalidraw npm package doesn't throw
// process undefined as docusaurus doesn't expose env variables by default
process.env.IS_PREACT = "false";
/** @type {import('@docusaurus/types').Config} */
const config = {
title: "Excalidraw developer docs",
@ -36,10 +41,7 @@ const config = {
showLastUpdateTime: true,
},
theme: {
customCss: [
require.resolve("./src/css/custom.scss"),
require.resolve("../src/packages/excalidraw/example/App.scss"),
],
customCss: [require.resolve("./src/css/custom.scss")],
},
}),
],
@ -139,7 +141,15 @@ const config = {
},
}),
themes: ["@docusaurus/theme-live-codeblock"],
plugins: ["docusaurus-plugin-sass"],
plugins: [
"docusaurus-plugin-sass",
[
"docusaurus2-dotenv",
{
systemvars: true,
},
],
],
};
module.exports = config;

View File

@ -18,7 +18,7 @@
"@docusaurus/core": "2.2.0",
"@docusaurus/preset-classic": "2.2.0",
"@docusaurus/theme-live-codeblock": "2.2.0",
"@excalidraw/excalidraw": "0.15.2-eb020d0",
"@excalidraw/excalidraw": "0.17.0",
"@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1",
"docusaurus-plugin-sass": "0.2.3",
@ -30,6 +30,7 @@
"devDependencies": {
"@docusaurus/module-type-aliases": "2.0.0-rc.1",
"@tsconfig/docusaurus": "^1.0.5",
"docusaurus2-dotenv": "1.4.0",
"typescript": "^4.7.4"
},
"browserslist": {

View File

@ -23,7 +23,11 @@ const sidebars = {
},
items: ["introduction/development", "introduction/contributing"],
},
{ type: "category", label: "Codebase", items: ["codebase/json-schema"] },
{
type: "category",
label: "Codebase",
items: ["codebase/json-schema", "codebase/frames"],
},
{
type: "category",
label: "@excalidraw/excalidraw",
@ -49,7 +53,7 @@ const sidebars = {
},
items: [
"@excalidraw/excalidraw/api/props/initialdata",
"@excalidraw/excalidraw/api/props/ref",
"@excalidraw/excalidraw/api/props/excalidraw-api",
"@excalidraw/excalidraw/api/props/render-props",
"@excalidraw/excalidraw/api/props/ui-options",
],

4
dev-docs/vercel.json Normal file
View File

@ -0,0 +1,4 @@
{
"outputDirectory": "build",
"installCommand": "yarn install"
}

View File

@ -145,6 +145,14 @@
dependencies:
"@babel/highlight" "^7.18.6"
"@babel/code-frame@^7.22.13":
version "7.22.13"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
dependencies:
"@babel/highlight" "^7.22.13"
chalk "^2.4.2"
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8":
version "7.18.8"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d"
@ -202,6 +210,16 @@
"@jridgewell/gen-mapping" "^0.3.2"
jsesc "^2.5.1"
"@babel/generator@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
dependencies:
"@babel/types" "^7.23.0"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/helper-annotate-as-pure@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
@ -265,6 +283,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
"@babel/helper-environment-visitor@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
"@babel/helper-explode-assignable-expression@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096"
@ -280,6 +303,14 @@
"@babel/template" "^7.18.6"
"@babel/types" "^7.18.9"
"@babel/helper-function-name@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
dependencies:
"@babel/template" "^7.22.15"
"@babel/types" "^7.23.0"
"@babel/helper-hoist-variables@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
@ -287,6 +318,13 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-hoist-variables@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-member-expression-to-functions@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
@ -374,11 +412,28 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-split-export-declaration@^7.22.6":
version "7.22.6"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-string-parser@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
"@babel/helper-validator-identifier@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
"@babel/helper-validator-identifier@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
"@babel/helper-validator-option@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
@ -412,11 +467,25 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/highlight@^7.22.13":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
dependencies:
"@babel/helper-validator-identifier" "^7.22.20"
chalk "^2.4.2"
js-tokens "^4.0.0"
"@babel/parser@^7.12.7", "@babel/parser@^7.18.6", "@babel/parser@^7.18.8", "@babel/parser@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.9.tgz#f2dde0c682ccc264a9a8595efd030a5cc8fd2539"
integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==
"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
@ -1147,19 +1216,28 @@
"@babel/parser" "^7.18.6"
"@babel/types" "^7.18.6"
"@babel/traverse@^7.12.9", "@babel/traverse@^7.18.8", "@babel/traverse@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.9.tgz#deeff3e8f1bad9786874cb2feda7a2d77a904f98"
integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==
"@babel/template@^7.22.15":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
dependencies:
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.18.9"
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-function-name" "^7.18.9"
"@babel/helper-hoist-variables" "^7.18.6"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/parser" "^7.18.9"
"@babel/types" "^7.18.9"
"@babel/code-frame" "^7.22.13"
"@babel/parser" "^7.22.15"
"@babel/types" "^7.22.15"
"@babel/traverse@^7.12.9", "@babel/traverse@^7.18.8", "@babel/traverse@^7.18.9":
version "7.23.2"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
dependencies:
"@babel/code-frame" "^7.22.13"
"@babel/generator" "^7.23.0"
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-function-name" "^7.23.0"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/parser" "^7.23.0"
"@babel/types" "^7.23.0"
debug "^4.1.0"
globals "^11.1.0"
@ -1171,6 +1249,15 @@
"@babel/helper-validator-identifier" "^7.18.6"
to-fast-properties "^2.0.0"
"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
"@colors/colors@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
@ -1631,10 +1718,10 @@
url-loader "^4.1.1"
webpack "^5.73.0"
"@excalidraw/excalidraw@0.15.2-eb020d0":
version "0.15.2-eb020d0"
resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.15.2-eb020d0.tgz#25bd61e6f23da7c084fb16a3e0fe0dd9ad8e6533"
integrity sha512-TKGLzpOVqFQcwK1GFKTDXgg1s2U6tc5KE3qXuv87osbzOtftQn3x4+VH61vwdj11l00nEN80SMdXUC43T9uJqQ==
"@excalidraw/excalidraw@0.17.0":
version "0.17.0"
resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.17.0.tgz#3c64aa8e36406ac171b008cfecbdce5bb0755725"
integrity sha512-NzP22v5xMqxYW27ZtTHhiGFe7kE8NeBk45aoeM/mDSkXiOXPDH+PcvwzHRN/Ei+Vj/0sTPHxejn8bZyRWKGjXg==
"@hapi/hoek@^9.0.0":
version "9.3.0"
@ -1670,6 +1757,11 @@
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
"@jridgewell/resolve-uri@^3.1.0":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
@ -1688,6 +1780,19 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/sourcemap-codec@^1.4.14":
version "1.4.15"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@^0.3.17":
version "0.3.20"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f"
integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
dependencies:
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9":
version "0.3.14"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
@ -3462,6 +3567,13 @@ docusaurus-plugin-sass@0.2.3:
dependencies:
sass-loader "^10.1.1"
docusaurus2-dotenv@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/docusaurus2-dotenv/-/docusaurus2-dotenv-1.4.0.tgz#9ab900e29de9081f9f1f28f7224ff63760385641"
integrity sha512-iWqem5fnBAyeBBtX75Fxp71uUAnwFaXzOmade8zAhN4vL3RG9m27sLSRwjJGVVgIkEo3esjGyCcTGTiCjfi+sg==
dependencies:
dotenv-webpack "1.7.0"
dom-converter@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
@ -3547,6 +3659,25 @@ dot-prop@^5.2.0:
dependencies:
is-obj "^2.0.0"
dotenv-defaults@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/dotenv-defaults/-/dotenv-defaults-1.1.1.tgz#032c024f4b5906d9990eb06d722dc74cc60ec1bd"
integrity sha512-6fPRo9o/3MxKvmRZBD3oNFdxODdhJtIy1zcJeUSCs6HCy4tarUpd+G67UTU9tF6OWXeSPqsm4fPAB+2eY9Rt9Q==
dependencies:
dotenv "^6.2.0"
dotenv-webpack@1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/dotenv-webpack/-/dotenv-webpack-1.7.0.tgz#4384d8c57ee6f405c296278c14a9f9167856d3a1"
integrity sha512-wwNtOBW/6gLQSkb8p43y0Wts970A3xtNiG/mpwj9MLUhtPCQG6i+/DSXXoNN7fbPCU/vQ7JjwGmgOeGZSSZnsw==
dependencies:
dotenv-defaults "^1.0.2"
dotenv@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064"
integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==
duplexer3@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e"

View File

@ -15,14 +15,23 @@
border-radius: 50%;
}
}
.app-title {
margin-block-start: 0.83em;
margin-block-end: 0.83em;
}
}
.button-wrapper button {
z-index: 1;
height: 40px;
max-width: 200px;
margin: 10px;
padding: 5px;
.button-wrapper {
input[type="checkbox"] {
margin: 5px;
}
button {
z-index: 1;
height: 40px;
max-width: 200px;
margin: 10px;
padding: 5px;
}
}
.excalidraw .App-menu_top .buttonList {

View File

@ -1,23 +1,31 @@
import { useEffect, useState, useRef, useCallback } from "react";
import React, {
useEffect,
useState,
useRef,
useCallback,
Children,
cloneElement,
} from "react";
import ExampleSidebar from "./sidebar/ExampleSidebar";
import type * as TExcalidraw from "../index";
import type * as TExcalidraw from "@excalidraw/excalidraw";
import "./App.scss";
import initialData from "./initialData";
import { nanoid } from "nanoid";
import {
resolvablePromise,
ResolvablePromise,
distance2d,
fileOpen,
withBatchedUpdates,
withBatchedUpdatesThrottled,
} from "../../../utils";
import { EVENT, ROUNDNESS } from "../../../constants";
import { distance2d } from "../../../math";
import { fileOpen } from "../../../data/filesystem";
import { loadSceneOrLibraryFromBlob } from "../../utils";
import {
} from "../utils";
import CustomFooter from "./CustomFooter";
import MobileFooter from "./MobileFooter";
import initialData from "../initialData";
import type {
AppState,
BinaryFileData,
ExcalidrawImperativeAPI,
@ -25,18 +33,14 @@ import {
Gesture,
LibraryItems,
PointerDownState as ExcalidrawPointerDownState,
} from "../../../types";
import { NonDeletedExcalidrawElement, Theme } from "../../../element/types";
import { ImportedLibraryData } from "../../../data/types";
import CustomFooter from "./CustomFooter";
import MobileFooter from "./MobileFooter";
import { KEYS } from "../../../keys";
} from "@excalidraw/excalidraw/dist/excalidraw/types";
import type {
NonDeletedExcalidrawElement,
Theme,
} from "@excalidraw/excalidraw/dist/excalidraw/element/types";
import type { ImportedLibraryData } from "@excalidraw/excalidraw/dist/excalidraw/data/types";
declare global {
interface Window {
ExcalidrawLib: typeof TExcalidraw;
}
}
import "./App.scss";
type Comment = {
x: number;
@ -57,27 +61,6 @@ type PointerDownState = {
};
};
// This is so that we use the bundled excalidraw.development.js file instead
// of the actual source code
const {
exportToCanvas,
exportToSvg,
exportToBlob,
exportToClipboard,
Excalidraw,
useHandleLibrary,
MIME_TYPES,
sceneCoordsToViewportCoords,
viewportCoordsToSceneCoords,
restoreElements,
Sidebar,
Footer,
WelcomeScreen,
MainMenu,
LiveCollaborationTrigger,
convertToExcalidrawElements,
} = window.ExcalidrawLib;
const COMMENT_ICON_DIMENSION = 32;
const COMMENT_INPUT_HEIGHT = 50;
const COMMENT_INPUT_WIDTH = 150;
@ -86,9 +69,38 @@ export interface AppProps {
appTitle: string;
useCustom: (api: ExcalidrawImperativeAPI | null, customArgs?: any[]) => void;
customArgs?: any[];
children: React.ReactNode;
excalidrawLib: typeof TExcalidraw;
}
export default function App({ appTitle, useCustom, customArgs }: AppProps) {
export default function App({
appTitle,
useCustom,
customArgs,
children,
excalidrawLib,
}: AppProps) {
const {
exportToCanvas,
exportToSvg,
exportToBlob,
exportToClipboard,
useHandleLibrary,
MIME_TYPES,
sceneCoordsToViewportCoords,
viewportCoordsToSceneCoords,
restoreElements,
Sidebar,
Footer,
WelcomeScreen,
MainMenu,
LiveCollaborationTrigger,
convertToExcalidrawElements,
TTDDialog,
TTDDialogTrigger,
ROUNDNESS,
loadSceneOrLibraryFromBlob,
} = excalidrawLib;
const appRef = useRef<any>(null);
const [viewModeEnabled, setViewModeEnabled] = useState(false);
const [zenModeEnabled, setZenModeEnabled] = useState(false);
@ -98,6 +110,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
const [exportEmbedScene, setExportEmbedScene] = useState(false);
const [theme, setTheme] = useState<Theme>("light");
const [disableImageTool, setDisableImageTool] = useState(false);
const [isCollaborating, setIsCollaborating] = useState(false);
const [commentIcons, setCommentIcons] = useState<{ [id: string]: Comment }>(
{},
@ -149,8 +162,105 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
};
};
fetchData();
}, [excalidrawAPI]);
}, [excalidrawAPI, convertToExcalidrawElements, MIME_TYPES]);
const renderExcalidraw = (children: React.ReactNode) => {
const Excalidraw: any = Children.toArray(children).find(
(child) =>
React.isValidElement(child) &&
typeof child.type !== "string" &&
//@ts-ignore
child.type.displayName === "Excalidraw",
);
if (!Excalidraw) {
return;
}
const newElement = cloneElement(
Excalidraw,
{
excalidrawAPI: (api: ExcalidrawImperativeAPI) => setExcalidrawAPI(api),
initialData: initialStatePromiseRef.current.promise,
onChange: (
elements: NonDeletedExcalidrawElement[],
state: AppState,
) => {
console.info("Elements :", elements, "State : ", state);
},
onPointerUpdate: (payload: {
pointer: { x: number; y: number };
button: "down" | "up";
pointersMap: Gesture["pointers"];
}) => setPointerData(payload),
viewModeEnabled,
zenModeEnabled,
gridModeEnabled,
theme,
name: "Custom name of drawing",
UIOptions: {
canvasActions: {
loadScene: false,
},
tools: { image: !disableImageTool },
},
renderTopRightUI,
onLinkOpen,
onPointerDown,
onScrollChange: rerenderCommentIcons,
validateEmbeddable: true,
},
<>
{excalidrawAPI && (
<Footer>
<CustomFooter
excalidrawAPI={excalidrawAPI}
excalidrawLib={excalidrawLib}
/>
</Footer>
)}
<WelcomeScreen />
<Sidebar name="custom">
<Sidebar.Tabs>
<Sidebar.Header />
<Sidebar.Tab tab="one">Tab one!</Sidebar.Tab>
<Sidebar.Tab tab="two">Tab two!</Sidebar.Tab>
<Sidebar.TabTriggers>
<Sidebar.TabTrigger tab="one">One</Sidebar.TabTrigger>
<Sidebar.TabTrigger tab="two">Two</Sidebar.TabTrigger>
</Sidebar.TabTriggers>
</Sidebar.Tabs>
</Sidebar>
<Sidebar.Trigger
name="custom"
tab="one"
style={{
position: "absolute",
left: "50%",
transform: "translateX(-50%)",
bottom: "20px",
zIndex: 9999999999999999,
}}
>
Toggle Custom Sidebar
</Sidebar.Trigger>
{renderMenu()}
{excalidrawAPI && (
<TTDDialogTrigger icon={<span>😀</span>}>
Text to diagram
</TTDDialogTrigger>
)}
<TTDDialog
onTextSubmit={async (_) => {
console.info("submit");
// sleep for 2s
await new Promise((resolve) => setTimeout(resolve, 2000));
throw new Error("error, go away now");
// return "dummy";
}}
/>
</>,
);
return newElement;
};
const renderTopRightUI = (isMobile: boolean) => {
return (
<>
@ -334,8 +444,8 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
pointerDownState: PointerDownState,
) => {
return withBatchedUpdates((event) => {
window.removeEventListener(EVENT.POINTER_MOVE, pointerDownState.onMove);
window.removeEventListener(EVENT.POINTER_UP, pointerDownState.onUp);
window.removeEventListener("pointermove", pointerDownState.onMove);
window.removeEventListener("pointerup", pointerDownState.onUp);
excalidrawAPI?.setActiveTool({ type: "selection" });
const distance = distance2d(
pointerDownState.x,
@ -399,8 +509,8 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
onPointerMoveFromPointerDownHandler(pointerDownState);
const onPointerUp =
onPointerUpFromPointerDownHandler(pointerDownState);
window.addEventListener(EVENT.POINTER_MOVE, onPointerMove);
window.addEventListener(EVENT.POINTER_UP, onPointerUp);
window.addEventListener("pointermove", onPointerMove);
window.addEventListener("pointerup", onPointerUp);
pointerDownState.onMove = onPointerMove;
pointerDownState.onUp = onPointerUp;
@ -492,7 +602,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
}}
onBlur={saveComment}
onKeyDown={(event) => {
if (!event.shiftKey && event.key === KEYS.ENTER) {
if (!event.shiftKey && event.key === "Enter") {
event.preventDefault();
saveComment();
}
@ -525,7 +635,12 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
</MainMenu.ItemCustom>
<MainMenu.DefaultItems.Help />
{excalidrawAPI && <MobileFooter excalidrawAPI={excalidrawAPI} />}
{excalidrawAPI && (
<MobileFooter
excalidrawLib={excalidrawLib}
excalidrawAPI={excalidrawAPI}
/>
)}
</MainMenu>
);
};
@ -606,6 +721,16 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
/>
Switch to Dark Theme
</label>
<label>
<input
type="checkbox"
checked={disableImageTool === true}
onChange={() => {
setDisableImageTool(!disableImageTool);
}}
/>
Disable Image Tool
</label>
<label>
<input
type="checkbox"
@ -664,66 +789,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
</div>
</div>
<div className="excalidraw-wrapper">
<Excalidraw
ref={(api: ExcalidrawImperativeAPI) => setExcalidrawAPI(api)}
initialData={initialStatePromiseRef.current.promise}
onChange={(elements, state) => {
console.info("Elements :", elements, "State : ", state);
}}
onPointerUpdate={(payload: {
pointer: { x: number; y: number };
button: "down" | "up";
pointersMap: Gesture["pointers"];
}) => setPointerData(payload)}
viewModeEnabled={viewModeEnabled}
zenModeEnabled={zenModeEnabled}
gridModeEnabled={gridModeEnabled}
theme={theme}
name="Custom name of drawing"
UIOptions={{
canvasActions: {
loadScene: false,
},
}}
renderTopRightUI={renderTopRightUI}
onLinkOpen={onLinkOpen}
onPointerDown={onPointerDown}
onScrollChange={rerenderCommentIcons}
// allow all urls
validateEmbeddable={true}
>
{excalidrawAPI && (
<Footer>
<CustomFooter excalidrawAPI={excalidrawAPI} />
</Footer>
)}
<WelcomeScreen />
<Sidebar name="custom">
<Sidebar.Tabs>
<Sidebar.Header />
<Sidebar.Tab tab="one">Tab one!</Sidebar.Tab>
<Sidebar.Tab tab="two">Tab two!</Sidebar.Tab>
<Sidebar.TabTriggers>
<Sidebar.TabTrigger tab="one">One</Sidebar.TabTrigger>
<Sidebar.TabTrigger tab="two">Two</Sidebar.TabTrigger>
</Sidebar.TabTriggers>
</Sidebar.Tabs>
</Sidebar>
<Sidebar.Trigger
name="custom"
tab="one"
style={{
position: "absolute",
left: "50%",
transform: "translateX(-50%)",
bottom: "20px",
zIndex: 9999999999999999,
}}
>
Toggle Custom Sidebar
</Sidebar.Trigger>
{renderMenu()}
</Excalidraw>
{renderExcalidraw(children)}
{Object.keys(commentIcons || []).length > 0 && renderCommentIcons()}
{comment && renderComment()}
</div>

View File

@ -1,6 +1,5 @@
import { ExcalidrawImperativeAPI } from "../../../types";
import { MIME_TYPES } from "../entry";
import { Button } from "../../../components/Button";
import type * as TExcalidraw from "@excalidraw/excalidraw";
import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/dist/excalidraw/types";
const COMMENT_SVG = (
<svg
@ -18,24 +17,28 @@ const COMMENT_SVG = (
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
</svg>
);
const CustomFooter = ({
excalidrawAPI,
excalidrawLib,
}: {
excalidrawAPI: ExcalidrawImperativeAPI;
excalidrawLib: typeof TExcalidraw;
}) => {
const { Button, MIME_TYPES } = excalidrawLib;
return (
<>
<Button
onSelect={() => alert("General Kenobi!")}
className="you are a bold one"
style={{ marginLeft: "1rem" }}
style={{ marginLeft: "1rem", width: "auto" }}
title="Hello there!"
>
{COMMENT_SVG}
Hit me
</Button>
<button
<Button
className="custom-element"
onClick={() => {
onSelect={() => {
excalidrawAPI?.setActiveTool({
type: "custom",
customType: "comment",
@ -58,15 +61,10 @@ const CustomFooter = ({
)}`;
excalidrawAPI?.setCursor(`url(${url}), auto`);
}}
title="Comments!"
>
{COMMENT_SVG}
</button>
<button
className="custom-footer"
onClick={() => alert("This is dummy footer")}
>
custom footer
</button>
</Button>
</>
);
};

View File

@ -0,0 +1,27 @@
import { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/dist/excalidraw/types";
import CustomFooter from "./CustomFooter";
import type * as TExcalidraw from "@excalidraw/excalidraw";
const MobileFooter = ({
excalidrawAPI,
excalidrawLib,
}: {
excalidrawAPI: ExcalidrawImperativeAPI;
excalidrawLib: typeof TExcalidraw;
}) => {
const { useDevice, Footer } = excalidrawLib;
const device = useDevice();
if (device.editor.isMobile) {
return (
<Footer>
<CustomFooter
excalidrawAPI={excalidrawAPI}
excalidrawLib={excalidrawLib}
/>
</Footer>
);
}
return null;
};
export default MobileFooter;

View File

@ -1,5 +1,6 @@
import React, { useState } from "react";
import { useState } from "react";
import "./ExampleSidebar.scss";
export default function Sidebar({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(false);

View File

@ -1,5 +1,5 @@
import { ExcalidrawElementSkeleton } from "../../../data/transform";
import { FileId } from "../../../element/types";
import type { ExcalidrawElementSkeleton } from "@excalidraw/excalidraw/data/transform";
import type { FileId } from "@excalidraw/excalidraw/element/types";
const elements: ExcalidrawElementSkeleton[] = [
{
@ -7,6 +7,7 @@ const elements: ExcalidrawElementSkeleton[] = [
x: 10,
y: 10,
strokeWidth: 2,
id: "1",
},
{
type: "diamond",
@ -19,6 +20,7 @@ const elements: ExcalidrawElementSkeleton[] = [
strokeColor: "#099268",
fontSize: 30,
},
id: "2",
},
{
type: "arrow",
@ -36,6 +38,11 @@ const elements: ExcalidrawElementSkeleton[] = [
height: 230,
fileId: "rocket" as FileId,
},
{
type: "frame",
children: ["1", "2"],
name: "My frame",
},
];
export default {
elements,

View File

@ -0,0 +1,13 @@
{
"name": "examples",
"version": "1.0.0",
"private": true,
"dependencies": {
"react": "18.2.0",
"react-dom": "18.2.0",
"@excalidraw/excalidraw": "*"
},
"devDependencies": {
"typescript": "^5"
}
}

View File

@ -0,0 +1,3 @@
{
"extends": "../../tsconfig"
}

View File

@ -0,0 +1,146 @@
import { unstable_batchedUpdates } from "react-dom";
import { fileOpen as _fileOpen } from "browser-fs-access";
import type { MIME_TYPES } from "@excalidraw/excalidraw";
import { AbortError } from "../../packages/excalidraw/errors";
type FILE_EXTENSION = Exclude<keyof typeof MIME_TYPES, "binary">;
const INPUT_CHANGE_INTERVAL_MS = 500;
export type ResolvablePromise<T> = Promise<T> & {
resolve: [T] extends [undefined] ? (value?: T) => void : (value: T) => void;
reject: (error: Error) => void;
};
export const resolvablePromise = <T>() => {
let resolve!: any;
let reject!: any;
const promise = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
(promise as any).resolve = resolve;
(promise as any).reject = reject;
return promise as ResolvablePromise<T>;
};
export const distance2d = (x1: number, y1: number, x2: number, y2: number) => {
const xd = x2 - x1;
const yd = y2 - y1;
return Math.hypot(xd, yd);
};
export const fileOpen = <M extends boolean | undefined = false>(opts: {
extensions?: FILE_EXTENSION[];
description: string;
multiple?: M;
}): Promise<M extends false | undefined ? File : File[]> => {
// an unsafe TS hack, alas not much we can do AFAIK
type RetType = M extends false | undefined ? File : File[];
const mimeTypes = opts.extensions?.reduce((mimeTypes, type) => {
mimeTypes.push(MIME_TYPES[type]);
return mimeTypes;
}, [] as string[]);
const extensions = opts.extensions?.reduce((acc, ext) => {
if (ext === "jpg") {
return acc.concat(".jpg", ".jpeg");
}
return acc.concat(`.${ext}`);
}, [] as string[]);
return _fileOpen({
description: opts.description,
extensions,
mimeTypes,
multiple: opts.multiple ?? false,
legacySetup: (resolve, reject, input) => {
const scheduleRejection = debounce(reject, INPUT_CHANGE_INTERVAL_MS);
const focusHandler = () => {
checkForFile();
document.addEventListener("keyup", scheduleRejection);
document.addEventListener("pointerup", scheduleRejection);
scheduleRejection();
};
const checkForFile = () => {
// this hack might not work when expecting multiple files
if (input.files?.length) {
const ret = opts.multiple ? [...input.files] : input.files[0];
resolve(ret as RetType);
}
};
requestAnimationFrame(() => {
window.addEventListener("focus", focusHandler);
});
const interval = window.setInterval(() => {
checkForFile();
}, INPUT_CHANGE_INTERVAL_MS);
return (rejectPromise) => {
clearInterval(interval);
scheduleRejection.cancel();
window.removeEventListener("focus", focusHandler);
document.removeEventListener("keyup", scheduleRejection);
document.removeEventListener("pointerup", scheduleRejection);
if (rejectPromise) {
// so that something is shown in console if we need to debug this
console.warn("Opening the file was canceled (legacy-fs).");
rejectPromise(new AbortError());
}
};
},
}) as Promise<RetType>;
};
export const debounce = <T extends any[]>(
fn: (...args: T) => void,
timeout: number,
) => {
let handle = 0;
let lastArgs: T | null = null;
const ret = (...args: T) => {
lastArgs = args;
clearTimeout(handle);
handle = window.setTimeout(() => {
lastArgs = null;
fn(...args);
}, timeout);
};
ret.flush = () => {
clearTimeout(handle);
if (lastArgs) {
const _lastArgs = lastArgs;
lastArgs = null;
fn(..._lastArgs);
}
};
ret.cancel = () => {
lastArgs = null;
clearTimeout(handle);
};
return ret;
};
export const withBatchedUpdates = <
TFunction extends ((event: any) => void) | (() => void),
>(
func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never,
) =>
((event) => {
unstable_batchedUpdates(func as TFunction, event);
}) as TFunction;
/**
* barches React state updates and throttles the calls to a single call per
* animation frame
*/
export const withBatchedUpdatesThrottled = <
TFunction extends ((event: any) => void) | (() => void),
>(
func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never,
) => {
// @ts-ignore
return throttleRAF<Parameters<TFunction>>(((event) => {
unstable_batchedUpdates(func, event);
}) as TFunction);
};

View File

@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3005) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

View File

@ -0,0 +1,12 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
distDir: "build",
typescript: {
// The ts config doesn't work with `jsx: preserve" and if updated to `react-jsx` it gets ovewritten by next js throwing ts errors hence I am ignoring build errors until this is fixed.
ignoreBuildErrors: true,
},
// This is needed as in pages router the code for importing types throws error as its outside next js app
transpilePackages: ["../"],
};
module.exports = nextConfig;

View File

@ -0,0 +1,25 @@
{
"name": "with-nextjs",
"version": "0.1.0",
"private": true,
"scripts": {
"build:workspace": "yarn workspace @excalidraw/excalidraw run build:esm",
"dev": "yarn build:workspace && next dev -p 3005",
"build": "yarn build:workspace && next build",
"start": "next start -p 3006",
"lint": "next lint"
},
"dependencies": {
"@excalidraw/excalidraw": "*",
"next": "14.1",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"path2d-polyfill": "2.0.1",
"typescript": "^5"
}
}

View File

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 197 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,11 @@
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

View File

@ -0,0 +1,23 @@
import dynamic from "next/dynamic";
import "../common.scss";
// Since client components get prerenderd on server as well hence importing the excalidraw stuff dynamically
// with ssr false
const ExcalidrawWithClientOnly = dynamic(
async () => (await import("../excalidrawWrapper")).default,
{
ssr: false,
},
);
export default function Page() {
return (
<>
<a href="/excalidraw-in-pages">Switch to Pages router</a>
<h1 className="page-title">App Router</h1>
{/* @ts-expect-error - https://github.com/vercel/next.js/issues/42292 */}
<ExcalidrawWithClientOnly />
</>
);
}

View File

@ -0,0 +1,15 @@
* {
box-sizing: border-box;
font-family: sans-serif;
}
a {
color: #1c7ed6;
font-size: 20px;
text-decoration: none;
font-weight: 550;
}
.page-title {
text-align: center;
}

View File

@ -0,0 +1,22 @@
"use client";
import * as excalidrawLib from "@excalidraw/excalidraw";
import { Excalidraw } from "@excalidraw/excalidraw";
import App from "../../components/App";
import "@excalidraw/excalidraw/index.css";
const ExcalidrawWrapper: React.FC = () => {
return (
<>
<App
appTitle={"Excalidraw with Nextjs Example"}
useCustom={(api: any, args?: any[]) => {}}
excalidrawLib={excalidrawLib}
>
<Excalidraw />
</App>
</>
);
};
export default ExcalidrawWrapper;

View File

@ -0,0 +1,22 @@
import dynamic from "next/dynamic";
import "../common.scss";
// Since client components get prerenderd on server as well hence importing the excalidraw stuff dynamically
// with ssr false
const Excalidraw = dynamic(
async () => (await import("../excalidrawWrapper")).default,
{
ssr: false,
},
);
export default function Page() {
return (
<>
<a href="/">Switch to App router</a>
<h1 className="page-title">Pages Router</h1>
{/* @ts-expect-error - https://github.com/vercel/next.js/issues/42292 */}
<Excalidraw />
</>
);
}

View File

@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
},
"forceConsistentCasingInFileNames": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "build/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@ -0,0 +1,3 @@
{
"outputDirectory": "build"
}

View File

@ -0,0 +1,252 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@excalidraw/excalidraw@workspace:^":
version "0.17.2"
resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.17.2.tgz#9a636a1e6bb3c88c5883347d3a7e75e9cce8ab96"
integrity sha512-7pqUWD8+mPjDhF4XxG3gw4rvE2JGaLW3Vss5UZfTbITPxAtFaGEc1K081bncitnaYhUwN9ENJE0i87QB3poDwQ==
"@next/env@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/env/-/env-14.0.4.tgz#d5cda0c4a862d70ae760e58c0cd96a8899a2e49a"
integrity sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==
"@next/swc-darwin-arm64@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.4.tgz#27b1854c2cd04eb1d5e75081a1a792ad91526618"
integrity sha512-mF05E/5uPthWzyYDyptcwHptucf/jj09i2SXBPwNzbgBNc+XnwzrL0U6BmPjQeOL+FiB+iG1gwBeq7mlDjSRPg==
"@next/swc-darwin-x64@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.4.tgz#9940c449e757d0ee50bb9e792d2600cc08a3eb3b"
integrity sha512-IZQ3C7Bx0k2rYtrZZxKKiusMTM9WWcK5ajyhOZkYYTCc8xytmwSzR1skU7qLgVT/EY9xtXDG0WhY6fyujnI3rw==
"@next/swc-linux-arm64-gnu@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.4.tgz#0eafd27c8587f68ace7b4fa80695711a8434de21"
integrity sha512-VwwZKrBQo/MGb1VOrxJ6LrKvbpo7UbROuyMRvQKTFKhNaXjUmKTu7wxVkIuCARAfiI8JpaWAnKR+D6tzpCcM4w==
"@next/swc-linux-arm64-musl@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.4.tgz#2b0072adb213f36dada5394ea67d6e82069ae7dd"
integrity sha512-8QftwPEW37XxXoAwsn+nXlodKWHfpMaSvt81W43Wh8dv0gkheD+30ezWMcFGHLI71KiWmHK5PSQbTQGUiidvLQ==
"@next/swc-linux-x64-gnu@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.4.tgz#68c67d20ebc8e3f6ced6ff23a4ba2a679dbcec32"
integrity sha512-/s/Pme3VKfZAfISlYVq2hzFS8AcAIOTnoKupc/j4WlvF6GQ0VouS2Q2KEgPuO1eMBwakWPB1aYFIA4VNVh667A==
"@next/swc-linux-x64-musl@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.4.tgz#67cd81b42fb2caf313f7992fcf6d978af55a1247"
integrity sha512-m8z/6Fyal4L9Bnlxde5g2Mfa1Z7dasMQyhEhskDATpqr+Y0mjOBZcXQ7G5U+vgL22cI4T7MfvgtrM2jdopqWaw==
"@next/swc-win32-arm64-msvc@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.4.tgz#be06585906b195d755ceda28f33c633e1443f1a3"
integrity sha512-7Wv4PRiWIAWbm5XrGz3D8HUkCVDMMz9igffZG4NB1p4u1KoItwx9qjATHz88kwCEal/HXmbShucaslXCQXUM5w==
"@next/swc-win32-ia32-msvc@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.4.tgz#e76cabefa9f2d891599c3d85928475bd8d3f6600"
integrity sha512-zLeNEAPULsl0phfGb4kdzF/cAVIfaC7hY+kt0/d+y9mzcZHsMS3hAS829WbJ31DkSlVKQeHEjZHIdhN+Pg7Gyg==
"@next/swc-win32-x64-msvc@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.4.tgz#e74892f1a9ccf41d3bf5979ad6d3d77c07b9cba1"
integrity sha512-yEh2+R8qDlDCjxVpzOTEpBLQTEFAcP2A8fUFLaWNap9GitYKkKv1//y2S6XY6zsR4rCOPRpU7plYDR+az2n30A==
"@swc/helpers@0.5.2":
version "0.5.2"
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d"
integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==
dependencies:
tslib "^2.4.0"
"@types/node@^20":
version "20.11.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.0.tgz#8e0b99e70c0c1ade1a86c4a282f7b7ef87c9552f"
integrity sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==
dependencies:
undici-types "~5.26.4"
"@types/prop-types@*":
version "15.7.11"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563"
integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==
"@types/react-dom@^18":
version "18.2.18"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.18.tgz#16946e6cd43971256d874bc3d0a72074bb8571dd"
integrity sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18":
version "18.2.47"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.47.tgz#85074b27ab563df01fbc3f68dc64bf7050b0af40"
integrity sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.8"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff"
integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==
busboy@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
dependencies:
streamsearch "^1.1.0"
caniuse-lite@^1.0.30001406:
version "1.0.30001576"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz#893be772cf8ee6056d6c1e2d07df365b9ec0a5c4"
integrity sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==
client-only@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
csstype@^3.0.2:
version "3.1.3"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
glob-to-regexp@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
graceful-fs@^4.1.2, graceful-fs@^4.2.11:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
nanoid@^3.3.6:
version "3.3.7"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
next@14.0.4:
version "14.0.4"
resolved "https://registry.yarnpkg.com/next/-/next-14.0.4.tgz#bf00b6f835b20d10a5057838fa2dfced1d0d84dc"
integrity sha512-qbwypnM7327SadwFtxXnQdGiKpkuhaRLE2uq62/nRul9cj9KhQ5LhHmlziTNqUidZotw/Q1I9OjirBROdUJNgA==
dependencies:
"@next/env" "14.0.4"
"@swc/helpers" "0.5.2"
busboy "1.6.0"
caniuse-lite "^1.0.30001406"
graceful-fs "^4.2.11"
postcss "8.4.31"
styled-jsx "5.1.1"
watchpack "2.4.0"
optionalDependencies:
"@next/swc-darwin-arm64" "14.0.4"
"@next/swc-darwin-x64" "14.0.4"
"@next/swc-linux-arm64-gnu" "14.0.4"
"@next/swc-linux-arm64-musl" "14.0.4"
"@next/swc-linux-x64-gnu" "14.0.4"
"@next/swc-linux-x64-musl" "14.0.4"
"@next/swc-win32-arm64-msvc" "14.0.4"
"@next/swc-win32-ia32-msvc" "14.0.4"
"@next/swc-win32-x64-msvc" "14.0.4"
path2d-polyfill@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz#24c554a738f42700d6961992bf5f1049672f2391"
integrity sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
postcss@8.4.31:
version "8.4.31"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"
react-dom@^18:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react@^18:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
dependencies:
loose-envify "^1.1.0"
scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
dependencies:
loose-envify "^1.1.0"
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
streamsearch@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
styled-jsx@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f"
integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==
dependencies:
client-only "0.0.1"
tslib@^2.4.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
typescript@^5:
version "5.3.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
undici-types@~5.26.4:
version "5.26.5"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
watchpack@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
dependencies:
glob-to-regexp "^0.4.1"
graceful-fs "^4.1.2"

View File

@ -12,18 +12,21 @@
<script>
window.name = "codesandbox";
</script>
<link rel="stylesheet" href="/dist/browser/dev/index.css" />
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div>
<script src="https://unpkg.com/react@18.2.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18.2.0/umd/react-dom.development.js"></script>
<!-- This is so that we use the bundled excalidraw.development.js file instead
of the actual source code -->
<script src="./excalidraw.development.js"></script>
<script type="module">
import * as ExcalidrawLib from "@excalidraw/excalidraw";
<script src="./bundle.js"></script>
console.log(ExcalidrawLib);
window.ExcalidrawLib = ExcalidrawLib;
</script>
<script type="module" src="index.tsx"></script>
</body>
</html>

View File

@ -0,0 +1,28 @@
import App from "../components/App";
import React, { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import type * as TExcalidraw from "@excalidraw/excalidraw";
import "@excalidraw/excalidraw/index.css";
declare global {
interface Window {
ExcalidrawLib: typeof TExcalidraw;
}
}
const rootElement = document.getElementById("root")!;
const root = createRoot(rootElement);
const { Excalidraw } = window.ExcalidrawLib;
root.render(
<StrictMode>
<App
appTitle={"Excalidraw Example"}
useCustom={(api: any, args?: any[]) => {}}
excalidrawLib={window.ExcalidrawLib}
>
<Excalidraw />
</App>
</StrictMode>,
);

View File

@ -0,0 +1,19 @@
{
"name": "with-script-in-browser",
"version": "1.0.0",
"private": true,
"dependencies": {
"react": "18.2.0",
"react-dom": "18.2.0",
"@excalidraw/excalidraw": "*"
},
"devDependencies": {
"vite": "5.0.12",
"typescript": "^5"
},
"scripts": {
"start": "yarn workspace @excalidraw/excalidraw run build:esm && vite",
"build": "yarn workspace @excalidraw/excalidraw run build:esm && vite build",
"build:preview": "yarn build && vite preview --port 5002"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -0,0 +1,4 @@
{
"outputDirectory": "dist",
"installCommand": "yarn install"
}

View File

@ -0,0 +1,11 @@
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
server: {
port: 3001,
// open the browser
open: true,
},
publicDir: "public",
});

View File

@ -0,0 +1,313 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@esbuild/aix-ppc64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz#2acd20be6d4f0458bc8c784103495ff24f13b1d3"
integrity sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==
"@esbuild/android-arm64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz#b45d000017385c9051a4f03e17078abb935be220"
integrity sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==
"@esbuild/android-arm@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.11.tgz#f46f55414e1c3614ac682b29977792131238164c"
integrity sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==
"@esbuild/android-x64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.11.tgz#bfc01e91740b82011ef503c48f548950824922b2"
integrity sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==
"@esbuild/darwin-arm64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz#533fb7f5a08c37121d82c66198263dcc1bed29bf"
integrity sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==
"@esbuild/darwin-x64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz#62f3819eff7e4ddc656b7c6815a31cf9a1e7d98e"
integrity sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==
"@esbuild/freebsd-arm64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz#d478b4195aa3ca44160272dab85ef8baf4175b4a"
integrity sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==
"@esbuild/freebsd-x64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz#7bdcc1917409178257ca6a1a27fe06e797ec18a2"
integrity sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==
"@esbuild/linux-arm64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz#58ad4ff11685fcc735d7ff4ca759ab18fcfe4545"
integrity sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==
"@esbuild/linux-arm@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz#ce82246d873b5534d34de1e5c1b33026f35e60e3"
integrity sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==
"@esbuild/linux-ia32@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz#cbae1f313209affc74b80f4390c4c35c6ab83fa4"
integrity sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==
"@esbuild/linux-loong64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz#5f32aead1c3ec8f4cccdb7ed08b166224d4e9121"
integrity sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==
"@esbuild/linux-mips64el@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz#38eecf1cbb8c36a616261de858b3c10d03419af9"
integrity sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==
"@esbuild/linux-ppc64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz#9c5725a94e6ec15b93195e5a6afb821628afd912"
integrity sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==
"@esbuild/linux-riscv64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz#2dc4486d474a2a62bbe5870522a9a600e2acb916"
integrity sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==
"@esbuild/linux-s390x@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz#4ad8567df48f7dd4c71ec5b1753b6f37561a65a8"
integrity sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==
"@esbuild/linux-x64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz#b7390c4d5184f203ebe7ddaedf073df82a658766"
integrity sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==
"@esbuild/netbsd-x64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz#d633c09492a1721377f3bccedb2d821b911e813d"
integrity sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==
"@esbuild/openbsd-x64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz#17388c76e2f01125bf831a68c03a7ffccb65d1a2"
integrity sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==
"@esbuild/sunos-x64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz#e320636f00bb9f4fdf3a80e548cb743370d41767"
integrity sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==
"@esbuild/win32-arm64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz#c778b45a496e90b6fc373e2a2bb072f1441fe0ee"
integrity sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==
"@esbuild/win32-ia32@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz#481a65fee2e5cce74ec44823e6b09ecedcc5194c"
integrity sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==
"@esbuild/win32-x64@0.19.11":
version "0.19.11"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz#a5d300008960bb39677c46bf16f53ec70d8dee04"
integrity sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==
"@rollup/rollup-android-arm-eabi@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.5.tgz#b752b6c88a14ccfcbdf3f48c577ccc3a7f0e66b9"
integrity sha512-idWaG8xeSRCfRq9KpRysDHJ/rEHBEXcHuJ82XY0yYFIWnLMjZv9vF/7DOq8djQ2n3Lk6+3qfSH8AqlmHlmi1MA==
"@rollup/rollup-android-arm64@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.5.tgz#33757c3a448b9ef77b6f6292d8b0ec45c87e9c1a"
integrity sha512-f14d7uhAMtsCGjAYwZGv6TwuS3IFaM4ZnGMUn3aCBgkcHAYErhV1Ad97WzBvS2o0aaDv4mVz+syiN0ElMyfBPg==
"@rollup/rollup-darwin-arm64@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.5.tgz#5234ba62665a3f443143bc8bcea9df2cc58f55fb"
integrity sha512-ndoXeLx455FffL68OIUrVr89Xu1WLzAG4n65R8roDlCoYiQcGGg6MALvs2Ap9zs7AHg8mpHtMpwC8jBBjZrT/w==
"@rollup/rollup-darwin-x64@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.5.tgz#981256c054d3247b83313724938d606798a919d1"
integrity sha512-UmElV1OY2m/1KEEqTlIjieKfVwRg0Zwg4PLgNf0s3glAHXBN99KLpw5A5lrSYCa1Kp63czTpVll2MAqbZYIHoA==
"@rollup/rollup-linux-arm-gnueabihf@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.5.tgz#120678a5a2b3a283a548dbb4d337f9187a793560"
integrity sha512-Q0LcU61v92tQB6ae+udZvOyZ0wfpGojtAKrrpAaIqmJ7+psq4cMIhT/9lfV6UQIpeItnq/2QDROhNLo00lOD1g==
"@rollup/rollup-linux-arm64-gnu@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.5.tgz#c99d857e2372ece544b6f60b85058ad259f64114"
integrity sha512-dkRscpM+RrR2Ee3eOQmRWFjmV/payHEOrjyq1VZegRUa5OrZJ2MAxBNs05bZuY0YCtpqETDy1Ix4i/hRqX98cA==
"@rollup/rollup-linux-arm64-musl@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.5.tgz#3064060f568a5718c2a06858cd6e6d24f2ff8632"
integrity sha512-QaKFVOzzST2xzY4MAmiDmURagWLFh+zZtttuEnuNn19AiZ0T3fhPyjPPGwLNdiDT82ZE91hnfJsUiDwF9DClIQ==
"@rollup/rollup-linux-riscv64-gnu@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.5.tgz#987d30b5d2b992fff07d055015991a57ff55fbad"
integrity sha512-HeGqmRJuyVg6/X6MpE2ur7GbymBPS8Np0S/vQFHDmocfORT+Zt76qu+69NUoxXzGqVP1pzaY6QIi0FJWLC3OPA==
"@rollup/rollup-linux-x64-gnu@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.5.tgz#85946ee4d068bd12197aeeec2c6f679c94978a49"
integrity sha512-Dq1bqBdLaZ1Gb/l2e5/+o3B18+8TI9ANlA1SkejZqDgdU/jK/ThYaMPMJpVMMXy2uRHvGKbkz9vheVGdq3cJfA==
"@rollup/rollup-linux-x64-musl@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.5.tgz#fe0b20f9749a60eb1df43d20effa96c756ddcbd4"
integrity sha512-ezyFUOwldYpj7AbkwyW9AJ203peub81CaAIVvckdkyH8EvhEIoKzaMFJj0G4qYJ5sw3BpqhFrsCc30t54HV8vg==
"@rollup/rollup-win32-arm64-msvc@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.5.tgz#422661ef0e16699a234465d15b2c1089ef963b2a"
integrity sha512-aHSsMnUw+0UETB0Hlv7B/ZHOGY5bQdwMKJSzGfDfvyhnpmVxLMGnQPGNE9wgqkLUs3+gbG1Qx02S2LLfJ5GaRQ==
"@rollup/rollup-win32-ia32-msvc@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.5.tgz#7b73a145891c202fbcc08759248983667a035d85"
integrity sha512-AiqiLkb9KSf7Lj/o1U3SEP9Zn+5NuVKgFdRIZkvd4N0+bYrTOovVd0+LmYCPQGbocT4kvFyK+LXCDiXPBF3fyA==
"@rollup/rollup-win32-x64-msvc@4.9.5":
version "4.9.5"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.5.tgz#10491ccf4f63c814d4149e0316541476ea603602"
integrity sha512-1q+mykKE3Vot1kaFJIDoUFv5TuW+QQVaf2FmTT9krg86pQrGStOSJJ0Zil7CFagyxDuouTepzt5Y5TVzyajOdQ==
"@types/estree@1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
esbuild@^0.19.3:
version "0.19.11"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.11.tgz#4a02dca031e768b5556606e1b468fe72e3325d96"
integrity sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==
optionalDependencies:
"@esbuild/aix-ppc64" "0.19.11"
"@esbuild/android-arm" "0.19.11"
"@esbuild/android-arm64" "0.19.11"
"@esbuild/android-x64" "0.19.11"
"@esbuild/darwin-arm64" "0.19.11"
"@esbuild/darwin-x64" "0.19.11"
"@esbuild/freebsd-arm64" "0.19.11"
"@esbuild/freebsd-x64" "0.19.11"
"@esbuild/linux-arm" "0.19.11"
"@esbuild/linux-arm64" "0.19.11"
"@esbuild/linux-ia32" "0.19.11"
"@esbuild/linux-loong64" "0.19.11"
"@esbuild/linux-mips64el" "0.19.11"
"@esbuild/linux-ppc64" "0.19.11"
"@esbuild/linux-riscv64" "0.19.11"
"@esbuild/linux-s390x" "0.19.11"
"@esbuild/linux-x64" "0.19.11"
"@esbuild/netbsd-x64" "0.19.11"
"@esbuild/openbsd-x64" "0.19.11"
"@esbuild/sunos-x64" "0.19.11"
"@esbuild/win32-arm64" "0.19.11"
"@esbuild/win32-ia32" "0.19.11"
"@esbuild/win32-x64" "0.19.11"
fsevents@~2.3.2, fsevents@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
nanoid@^3.3.7:
version "3.3.7"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
postcss@^8.4.32:
version "8.4.33"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742"
integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==
dependencies:
nanoid "^3.3.7"
picocolors "^1.0.0"
source-map-js "^1.0.2"
react-dom@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
dependencies:
loose-envify "^1.1.0"
rollup@^4.2.0:
version "4.9.5"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.5.tgz#62999462c90f4c8b5d7c38fc7161e63b29101b05"
integrity sha512-E4vQW0H/mbNMw2yLSqJyjtkHY9dslf/p0zuT1xehNRqUTBOFMqEjguDvqhXr7N7r/4ttb2jr4T41d3dncmIgbQ==
dependencies:
"@types/estree" "1.0.5"
optionalDependencies:
"@rollup/rollup-android-arm-eabi" "4.9.5"
"@rollup/rollup-android-arm64" "4.9.5"
"@rollup/rollup-darwin-arm64" "4.9.5"
"@rollup/rollup-darwin-x64" "4.9.5"
"@rollup/rollup-linux-arm-gnueabihf" "4.9.5"
"@rollup/rollup-linux-arm64-gnu" "4.9.5"
"@rollup/rollup-linux-arm64-musl" "4.9.5"
"@rollup/rollup-linux-riscv64-gnu" "4.9.5"
"@rollup/rollup-linux-x64-gnu" "4.9.5"
"@rollup/rollup-linux-x64-musl" "4.9.5"
"@rollup/rollup-win32-arm64-msvc" "4.9.5"
"@rollup/rollup-win32-ia32-msvc" "4.9.5"
"@rollup/rollup-win32-x64-msvc" "4.9.5"
fsevents "~2.3.2"
scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
dependencies:
loose-envify "^1.1.0"
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
vite@5.0.6:
version "5.0.6"
resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.6.tgz#f9e13503a4c5ccd67312c67803dec921f3bdea7c"
integrity sha512-MD3joyAEBtV7QZPl2JVVUai6zHms3YOmLR+BpMzLlX2Yzjfcc4gTgNi09d/Rua3F4EtC8zdwPU8eQYyib4vVMQ==
dependencies:
esbuild "^0.19.3"
postcss "^8.4.32"
rollup "^4.2.0"
optionalDependencies:
fsevents "~2.3.3"

1122
excalidraw-app/App.tsx Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
import { useEffect, useState } from "react";
import { debounce, getVersion, nFormatter } from "../src/utils";
import { debounce, getVersion, nFormatter } from "../packages/excalidraw/utils";
import {
getElementsStorageSize,
getTotalStorageSize,
} from "./data/localStorage";
import { DEFAULT_VERSION } from "../src/constants";
import { t } from "../src/i18n";
import { copyTextToSystemClipboard } from "../src/clipboard";
import { NonDeletedExcalidrawElement } from "../src/element/types";
import { UIAppState } from "../src/types";
import { DEFAULT_VERSION } from "../packages/excalidraw/constants";
import { t } from "../packages/excalidraw/i18n";
import { copyTextToSystemClipboard } from "../packages/excalidraw/clipboard";
import { NonDeletedExcalidrawElement } from "../packages/excalidraw/element/types";
import { UIAppState } from "../packages/excalidraw/types";
type StorageSizes = { scene: number; total: number };

View File

@ -15,11 +15,17 @@ export const FILE_CACHE_MAX_AGE_SEC = 31536000;
export const WS_EVENTS = {
SERVER_VOLATILE: "server-volatile-broadcast",
SERVER: "server-broadcast",
};
USER_FOLLOW_CHANGE: "user-follow",
USER_FOLLOW_ROOM_CHANGE: "user-follow-room-change",
} as const;
export enum WS_SCENE_EVENT_TYPES {
export enum WS_SUBTYPES {
INVALID_RESPONSE = "INVALID_RESPONSE",
INIT = "SCENE_INIT",
UPDATE = "SCENE_UPDATE",
MOUSE_LOCATION = "MOUSE_LOCATION",
IDLE_STATUS = "IDLE_STATUS",
USER_VISIBLE_SCENE_BOUNDS = "USER_VISIBLE_SCENE_BOUNDS",
}
export const FIREBASE_STORAGE_PREFIXES = {
@ -33,10 +39,14 @@ export const STORAGE_KEYS = {
LOCAL_STORAGE_ELEMENTS: "excalidraw",
LOCAL_STORAGE_APP_STATE: "excalidraw-state",
LOCAL_STORAGE_COLLAB: "excalidraw-collab",
LOCAL_STORAGE_LIBRARY: "excalidraw-library",
LOCAL_STORAGE_THEME: "excalidraw-theme",
VERSION_DATA_STATE: "version-dataState",
VERSION_FILES: "version-files",
IDB_LIBRARY: "excalidraw-library",
// do not use apart from migrations
__LEGACY_LOCAL_STORAGE_LIBRARY: "excalidraw-library",
} as const;
export const COOKIES = {

View File

@ -1,36 +1,42 @@
import throttle from "lodash.throttle";
import { PureComponent } from "react";
import { ExcalidrawImperativeAPI } from "../../src/types";
import { ErrorDialog } from "../../src/components/ErrorDialog";
import { APP_NAME, ENV, EVENT } from "../../src/constants";
import { ImportedDataState } from "../../src/data/types";
import {
ExcalidrawImperativeAPI,
SocketId,
} from "../../packages/excalidraw/types";
import { ErrorDialog } from "../../packages/excalidraw/components/ErrorDialog";
import { APP_NAME, ENV, EVENT } from "../../packages/excalidraw/constants";
import { ImportedDataState } from "../../packages/excalidraw/data/types";
import {
ExcalidrawElement,
InitializedExcalidrawImageElement,
} from "../../src/element/types";
OrderedExcalidrawElement,
} from "../../packages/excalidraw/element/types";
import {
getSceneVersion,
restoreElements,
} from "../../src/packages/excalidraw/index";
import { Collaborator, Gesture } from "../../src/types";
zoomToFitBounds,
} from "../../packages/excalidraw/index";
import { Collaborator, Gesture } from "../../packages/excalidraw/types";
import {
assertNever,
preventUnload,
resolvablePromise,
withBatchedUpdates,
} from "../../src/utils";
throttleRAF,
} from "../../packages/excalidraw/utils";
import {
CURSOR_SYNC_TIMEOUT,
FILE_UPLOAD_MAX_BYTES,
FIREBASE_STORAGE_PREFIXES,
INITIAL_SCENE_UPDATE_TIMEOUT,
LOAD_IMAGES_TIMEOUT,
WS_SCENE_EVENT_TYPES,
WS_SUBTYPES,
SYNC_FULL_SCENE_INTERVAL_MS,
WS_EVENTS,
} from "../app_constants";
import {
generateCollaborationLinkData,
getCollaborationLink,
getCollabServer,
getSyncableElements,
SocketUpdateDataSource,
SyncableExcalidrawElement,
@ -47,42 +53,52 @@ import {
saveUsernameToLocalStorage,
} from "../data/localStorage";
import Portal from "./Portal";
import RoomDialog from "./RoomDialog";
import { t } from "../../src/i18n";
import { UserIdleState } from "../../src/types";
import { IDLE_THRESHOLD, ACTIVE_THRESHOLD } from "../../src/constants";
import { t } from "../../packages/excalidraw/i18n";
import { UserIdleState } from "../../packages/excalidraw/types";
import {
IDLE_THRESHOLD,
ACTIVE_THRESHOLD,
} from "../../packages/excalidraw/constants";
import {
encodeFilesForUpload,
FileManager,
updateStaleImageStatuses,
} from "../data/FileManager";
import { AbortError } from "../../src/errors";
import { AbortError } from "../../packages/excalidraw/errors";
import {
isImageElement,
isInitializedImageElement,
} from "../../src/element/typeChecks";
import { newElementWith } from "../../src/element/mutateElement";
import {
ReconciledElements,
reconcileElements as _reconcileElements,
} from "./reconciliation";
import { decryptData } from "../../src/data/encryption";
} from "../../packages/excalidraw/element/typeChecks";
import { newElementWith } from "../../packages/excalidraw/element/mutateElement";
import { decryptData } from "../../packages/excalidraw/data/encryption";
import { resetBrowserStateVersions } from "../data/tabSync";
import { LocalData } from "../data/LocalData";
import { atom, useAtom } from "jotai";
import { atom } from "jotai";
import { appJotaiStore } from "../app-jotai";
import { Mutable, ValueOf } from "../../packages/excalidraw/utility-types";
import { getVisibleSceneBounds } from "../../packages/excalidraw/element/bounds";
import { withBatchedUpdates } from "../../packages/excalidraw/reactUtils";
import { collabErrorIndicatorAtom } from "./CollabError";
import {
ReconciledExcalidrawElement,
RemoteExcalidrawElement,
reconcileElements,
} from "../../packages/excalidraw/data/reconcile";
export const collabAPIAtom = atom<CollabAPI | null>(null);
export const collabDialogShownAtom = atom(false);
export const isCollaboratingAtom = atom(false);
export const isOfflineAtom = atom(false);
interface CollabState {
errorMessage: string;
errorMessage: string | null;
/** errors related to saving */
dialogNotifiedErrors: Record<string, boolean>;
username: string;
activeRoomLink: string;
activeRoomLink: string | null;
}
export const activeRoomLinkAtom = atom<string | null>(null);
type CollabInstance = InstanceType<typeof Collab>;
export interface CollabAPI {
@ -93,32 +109,34 @@ export interface CollabAPI {
stopCollaboration: CollabInstance["stopCollaboration"];
syncElements: CollabInstance["syncElements"];
fetchImageFilesFromFirebase: CollabInstance["fetchImageFilesFromFirebase"];
setUsername: (username: string) => void;
setUsername: CollabInstance["setUsername"];
getUsername: CollabInstance["getUsername"];
getActiveRoomLink: CollabInstance["getActiveRoomLink"];
setCollabError: CollabInstance["setErrorDialog"];
}
interface PublicProps {
interface CollabProps {
excalidrawAPI: ExcalidrawImperativeAPI;
}
type Props = PublicProps & { modalIsShown: boolean };
class Collab extends PureComponent<Props, CollabState> {
class Collab extends PureComponent<CollabProps, CollabState> {
portal: Portal;
fileManager: FileManager;
excalidrawAPI: Props["excalidrawAPI"];
excalidrawAPI: CollabProps["excalidrawAPI"];
activeIntervalId: number | null;
idleTimeoutId: number | null;
private socketInitializationTimer?: number;
private lastBroadcastedOrReceivedSceneVersion: number = -1;
private collaborators = new Map<string, Collaborator>();
private collaborators = new Map<SocketId, Collaborator>();
constructor(props: Props) {
constructor(props: CollabProps) {
super(props);
this.state = {
errorMessage: "",
errorMessage: null,
dialogNotifiedErrors: {},
username: importUsernameFromLocalStorage() || "",
activeRoomLink: "",
activeRoomLink: null,
};
this.portal = new Portal(this);
this.fileManager = new FileManager({
@ -151,12 +169,28 @@ class Collab extends PureComponent<Props, CollabState> {
this.idleTimeoutId = null;
}
private onUmmount: (() => void) | null = null;
componentDidMount() {
window.addEventListener(EVENT.BEFORE_UNLOAD, this.beforeUnload);
window.addEventListener("online", this.onOfflineStatusToggle);
window.addEventListener("offline", this.onOfflineStatusToggle);
window.addEventListener(EVENT.UNLOAD, this.onUnload);
const unsubOnUserFollow = this.excalidrawAPI.onUserFollow((payload) => {
this.portal.socket && this.portal.broadcastUserFollowed(payload);
});
const throttledRelayUserViewportBounds = throttleRAF(
this.relayVisibleSceneBounds,
);
const unsubOnScrollChange = this.excalidrawAPI.onScrollChange(() =>
throttledRelayUserViewportBounds(),
);
this.onUmmount = () => {
unsubOnUserFollow();
unsubOnScrollChange();
};
this.onOfflineStatusToggle();
const collabAPI: CollabAPI = {
@ -167,6 +201,9 @@ class Collab extends PureComponent<Props, CollabState> {
fetchImageFilesFromFirebase: this.fetchImageFilesFromFirebase,
stopCollaboration: this.stopCollaboration,
setUsername: this.setUsername,
getUsername: this.getUsername,
getActiveRoomLink: this.getActiveRoomLink,
setCollabError: this.setErrorDialog,
};
appJotaiStore.set(collabAPIAtom, collabAPI);
@ -204,6 +241,7 @@ class Collab extends PureComponent<Props, CollabState> {
window.clearTimeout(this.idleTimeoutId);
this.idleTimeoutId = null;
}
this.onUmmount?.();
}
isCollaborating = () => appJotaiStore.get(isCollaboratingAtom)!;
@ -238,24 +276,39 @@ class Collab extends PureComponent<Props, CollabState> {
syncableElements: readonly SyncableExcalidrawElement[],
) => {
try {
const savedData = await saveToFirebase(
const storedElements = await saveToFirebase(
this.portal,
syncableElements,
this.excalidrawAPI.getAppState(),
);
if (this.isCollaborating() && savedData && savedData.reconciledElements) {
this.handleRemoteSceneUpdate(
this.reconcileElements(savedData.reconciledElements),
);
this.resetErrorIndicator();
if (this.isCollaborating() && storedElements) {
this.handleRemoteSceneUpdate(this._reconcileElements(storedElements));
}
} catch (error: any) {
this.setState({
// firestore doesn't return a specific error code when size exceeded
errorMessage: /is longer than.*?bytes/.test(error.message)
? t("errors.collabSaveFailed_sizeExceeded")
: t("errors.collabSaveFailed"),
});
const errorMessage = /is longer than.*?bytes/.test(error.message)
? t("errors.collabSaveFailed_sizeExceeded")
: t("errors.collabSaveFailed");
if (
!this.state.dialogNotifiedErrors[errorMessage] ||
!this.isCollaborating()
) {
this.setErrorDialog(errorMessage);
this.setState({
dialogNotifiedErrors: {
...this.state.dialogNotifiedErrors,
[errorMessage]: true,
},
});
}
if (this.isCollaborating()) {
this.setErrorIndicator(errorMessage);
}
console.error(error);
}
};
@ -264,6 +317,7 @@ class Collab extends PureComponent<Props, CollabState> {
this.queueBroadcastAllElements.cancel();
this.queueSaveToFirebase.cancel();
this.loadImageFiles.cancel();
this.resetErrorIndicator(true);
this.saveCollabRoomToFirebase(
getSyncableElements(
@ -313,9 +367,7 @@ class Collab extends PureComponent<Props, CollabState> {
this.fileManager.reset();
if (!opts?.isUnload) {
this.setIsCollaborating(false);
this.setState({
activeRoomLink: "",
});
this.setActiveRoomLink(null);
this.collaborators = new Map();
this.excalidrawAPI.updateScene({
collaborators: this.collaborators,
@ -356,7 +408,7 @@ class Collab extends PureComponent<Props, CollabState> {
iv: Uint8Array,
encryptedData: ArrayBuffer,
decryptionKey: string,
) => {
): Promise<ValueOf<SocketUpdateDataSource>> => {
try {
const decrypted = await decryptData(iv, encryptedData, decryptionKey);
@ -368,7 +420,7 @@ class Collab extends PureComponent<Props, CollabState> {
window.alert(t("alerts.decryptFailed"));
console.error(error);
return {
type: "INVALID_RESPONSE",
type: WS_SUBTYPES.INVALID_RESPONSE,
};
}
};
@ -377,11 +429,11 @@ class Collab extends PureComponent<Props, CollabState> {
startCollaboration = async (
existingRoomLinkData: null | { roomId: string; roomKey: string },
): Promise<ImportedDataState | null> => {
) => {
if (!this.state.username) {
import("@excalidraw/random-username").then(({ getRandomUsername }) => {
const username = getRandomUsername();
this.onUsernameChange(username);
this.setUsername(username);
});
}
@ -403,7 +455,11 @@ class Collab extends PureComponent<Props, CollabState> {
);
}
const scenePromise = resolvablePromise<ImportedDataState | null>();
// TODO: `ImportedDataState` type here seems abused
const scenePromise = resolvablePromise<
| (ImportedDataState & { elements: readonly OrderedExcalidrawElement[] })
| null
>();
this.setIsCollaborating(true);
LocalData.pauseSave("collaboration");
@ -423,13 +479,9 @@ class Collab extends PureComponent<Props, CollabState> {
this.fallbackInitializationHandler = fallbackInitializationHandler;
try {
const socketServerData = await getCollabServer();
this.portal.socket = this.portal.open(
socketIOClient(socketServerData.url, {
transports: socketServerData.polling
? ["websocket", "polling"]
: ["websocket"],
socketIOClient(import.meta.env.VITE_APP_WS_SERVER_URL, {
transports: ["websocket", "polling"],
}),
roomId,
roomKey,
@ -438,7 +490,7 @@ class Collab extends PureComponent<Props, CollabState> {
this.portal.socket.once("connect_error", fallbackInitializationHandler);
} catch (error: any) {
console.error(error);
this.setState({ errorMessage: error.message });
this.setErrorDialog(error.message);
return null;
}
@ -484,13 +536,14 @@ class Collab extends PureComponent<Props, CollabState> {
);
switch (decryptedData.type) {
case "INVALID_RESPONSE":
case WS_SUBTYPES.INVALID_RESPONSE:
return;
case WS_SCENE_EVENT_TYPES.INIT: {
case WS_SUBTYPES.INIT: {
if (!this.portal.socketInitialized) {
this.initializeRoom({ fetchScene: false });
const remoteElements = decryptedData.payload.elements;
const reconciledElements = this.reconcileElements(remoteElements);
const reconciledElements =
this._reconcileElements(remoteElements);
this.handleRemoteSceneUpdate(reconciledElements, {
init: true,
});
@ -502,41 +555,75 @@ class Collab extends PureComponent<Props, CollabState> {
}
break;
}
case WS_SCENE_EVENT_TYPES.UPDATE:
case WS_SUBTYPES.UPDATE:
this.handleRemoteSceneUpdate(
this.reconcileElements(decryptedData.payload.elements),
this._reconcileElements(decryptedData.payload.elements),
);
break;
case "MOUSE_LOCATION": {
case WS_SUBTYPES.MOUSE_LOCATION: {
const { pointer, button, username, selectedElementIds } =
decryptedData.payload;
const socketId: SocketUpdateDataSource["MOUSE_LOCATION"]["payload"]["socketId"] =
decryptedData.payload.socketId ||
// @ts-ignore legacy, see #2094 (#2097)
decryptedData.payload.socketID;
const collaborators = new Map(this.collaborators);
const user = collaborators.get(socketId) || {}!;
user.pointer = pointer;
user.button = button;
user.selectedElementIds = selectedElementIds;
user.username = username;
collaborators.set(socketId, user);
this.updateCollaborator(socketId, {
pointer,
button,
selectedElementIds,
username,
});
break;
}
case WS_SUBTYPES.USER_VISIBLE_SCENE_BOUNDS: {
const { sceneBounds, socketId } = decryptedData.payload;
const appState = this.excalidrawAPI.getAppState();
// we're not following the user
// (shouldn't happen, but could be late message or bug upstream)
if (appState.userToFollow?.socketId !== socketId) {
console.warn(
`receiving remote client's (from ${socketId}) viewport bounds even though we're not subscribed to it!`,
);
return;
}
// cross-follow case, ignore updates in this case
if (
appState.userToFollow &&
appState.followedBy.has(appState.userToFollow.socketId)
) {
return;
}
this.excalidrawAPI.updateScene({
collaborators,
appState: zoomToFitBounds({
appState,
bounds: sceneBounds,
fitToViewport: true,
viewportZoomFactor: 1,
}).appState,
});
break;
}
case WS_SUBTYPES.IDLE_STATUS: {
const { userState, socketId, username } = decryptedData.payload;
this.updateCollaborator(socketId, {
userState,
username,
});
break;
}
case "IDLE_STATUS": {
const { userState, socketId, username } = decryptedData.payload;
const collaborators = new Map(this.collaborators);
const user = collaborators.get(socketId) || {}!;
user.userState = userState;
user.username = username;
this.excalidrawAPI.updateScene({
collaborators,
});
break;
default: {
assertNever(decryptedData, null);
}
}
},
@ -553,11 +640,20 @@ class Collab extends PureComponent<Props, CollabState> {
scenePromise.resolve(sceneData);
});
this.portal.socket.on(
WS_EVENTS.USER_FOLLOW_ROOM_CHANGE,
(followedBy: SocketId[]) => {
this.excalidrawAPI.updateScene({
appState: { followedBy: new Set(followedBy) },
});
this.relayVisibleSceneBounds({ force: true });
},
);
this.initializeIdleDetector();
this.setState({
activeRoomLink: window.location.href,
});
this.setActiveRoomLink(window.location.href);
return scenePromise;
};
@ -609,17 +705,15 @@ class Collab extends PureComponent<Props, CollabState> {
return null;
};
private reconcileElements = (
private _reconcileElements = (
remoteElements: readonly ExcalidrawElement[],
): ReconciledElements => {
): ReconciledExcalidrawElement[] => {
const localElements = this.getSceneElementsIncludingDeleted();
const appState = this.excalidrawAPI.getAppState();
remoteElements = restoreElements(remoteElements, null);
const reconciledElements = _reconcileElements(
const restoredRemoteElements = restoreElements(remoteElements, null);
const reconciledElements = reconcileElements(
localElements,
remoteElements,
restoredRemoteElements as RemoteExcalidrawElement[],
appState,
);
@ -650,7 +744,7 @@ class Collab extends PureComponent<Props, CollabState> {
}, LOAD_IMAGES_TIMEOUT);
private handleRemoteSceneUpdate = (
elements: ReconciledElements,
elements: ReconciledExcalidrawElement[],
{ init = false }: { init?: boolean } = {},
) => {
this.excalidrawAPI.updateScene({
@ -721,20 +815,39 @@ class Collab extends PureComponent<Props, CollabState> {
document.addEventListener(EVENT.VISIBILITY_CHANGE, this.onVisibilityChange);
};
setCollaborators(sockets: string[]) {
setCollaborators(sockets: SocketId[]) {
const collaborators: InstanceType<typeof Collab>["collaborators"] =
new Map();
for (const socketId of sockets) {
if (this.collaborators.has(socketId)) {
collaborators.set(socketId, this.collaborators.get(socketId)!);
} else {
collaborators.set(socketId, {});
}
collaborators.set(
socketId,
Object.assign({}, this.collaborators.get(socketId), {
isCurrentUser: socketId === this.portal.socket?.id,
}),
);
}
this.collaborators = collaborators;
this.excalidrawAPI.updateScene({ collaborators });
}
updateCollaborator = (socketId: SocketId, updates: Partial<Collaborator>) => {
const collaborators = new Map(this.collaborators);
const user: Mutable<Collaborator> = Object.assign(
{},
collaborators.get(socketId),
updates,
{
isCurrentUser: socketId === this.portal.socket?.id,
},
);
collaborators.set(socketId, user);
this.collaborators = collaborators;
this.excalidrawAPI.updateScene({
collaborators,
});
};
public setLastBroadcastedOrReceivedSceneVersion = (version: number) => {
this.lastBroadcastedOrReceivedSceneVersion = version;
};
@ -760,29 +873,42 @@ class Collab extends PureComponent<Props, CollabState> {
CURSOR_SYNC_TIMEOUT,
);
relayVisibleSceneBounds = (props?: { force: boolean }) => {
const appState = this.excalidrawAPI.getAppState();
if (this.portal.socket && (appState.followedBy.size > 0 || props?.force)) {
this.portal.broadcastVisibleSceneBounds(
{
sceneBounds: getVisibleSceneBounds(appState),
},
`follow@${this.portal.socket.id}`,
);
}
};
onIdleStateChange = (userState: UserIdleState) => {
this.portal.broadcastIdleChange(userState);
};
broadcastElements = (elements: readonly ExcalidrawElement[]) => {
broadcastElements = (elements: readonly OrderedExcalidrawElement[]) => {
if (
getSceneVersion(elements) >
this.getLastBroadcastedOrReceivedSceneVersion()
) {
this.portal.broadcastScene(WS_SCENE_EVENT_TYPES.UPDATE, elements, false);
this.portal.broadcastScene(WS_SUBTYPES.UPDATE, elements, false);
this.lastBroadcastedOrReceivedSceneVersion = getSceneVersion(elements);
this.queueBroadcastAllElements();
}
};
syncElements = (elements: readonly ExcalidrawElement[]) => {
syncElements = (elements: readonly OrderedExcalidrawElement[]) => {
this.broadcastElements(elements);
this.queueSaveToFirebase();
};
queueBroadcastAllElements = throttle(() => {
this.portal.broadcastScene(
WS_SCENE_EVENT_TYPES.UPDATE,
WS_SUBTYPES.UPDATE,
this.excalidrawAPI.getSceneElementsIncludingDeleted(),
true,
);
@ -808,41 +934,49 @@ class Collab extends PureComponent<Props, CollabState> {
{ leading: false },
);
handleClose = () => {
appJotaiStore.set(collabDialogShownAtom, false);
};
setUsername = (username: string) => {
this.setState({ username });
};
onUsernameChange = (username: string) => {
this.setUsername(username);
saveUsernameToLocalStorage(username);
};
render() {
const { username, errorMessage, activeRoomLink } = this.state;
getUsername = () => this.state.username;
const { modalIsShown } = this.props;
setActiveRoomLink = (activeRoomLink: string | null) => {
this.setState({ activeRoomLink });
appJotaiStore.set(activeRoomLinkAtom, activeRoomLink);
};
getActiveRoomLink = () => this.state.activeRoomLink;
setErrorIndicator = (errorMessage: string | null) => {
appJotaiStore.set(collabErrorIndicatorAtom, {
message: errorMessage,
nonce: Date.now(),
});
};
resetErrorIndicator = (resetDialogNotifiedErrors = false) => {
appJotaiStore.set(collabErrorIndicatorAtom, { message: null, nonce: 0 });
if (resetDialogNotifiedErrors) {
this.setState({
dialogNotifiedErrors: {},
});
}
};
setErrorDialog = (errorMessage: string | null) => {
this.setState({
errorMessage,
});
};
render() {
const { errorMessage } = this.state;
return (
<>
{modalIsShown && (
<RoomDialog
handleClose={this.handleClose}
activeRoomLink={activeRoomLink}
username={username}
onUsernameChange={this.onUsernameChange}
onRoomCreate={() => this.startCollaboration(null)}
onRoomDestroy={this.stopCollaboration}
setErrorMessage={(errorMessage) => {
this.setState({ errorMessage });
}}
/>
)}
{errorMessage && (
<ErrorDialog onClose={() => this.setState({ errorMessage: "" })}>
{errorMessage != null && (
<ErrorDialog onClose={() => this.setErrorDialog(null)}>
{errorMessage}
</ErrorDialog>
)}
@ -861,11 +995,6 @@ if (import.meta.env.MODE === ENV.TEST || import.meta.env.DEV) {
window.collab = window.collab || ({} as Window["collab"]);
}
const _Collab: React.FC<PublicProps> = (props) => {
const [collabDialogShown] = useAtom(collabDialogShownAtom);
return <Collab {...props} modalIsShown={collabDialogShown} />;
};
export default _Collab;
export default Collab;
export type TCollabClass = Collab;

View File

@ -0,0 +1,35 @@
@import "../../packages/excalidraw/css/variables.module.scss";
.excalidraw {
.collab-errors-button {
width: 26px;
height: 26px;
margin-inline-end: 1rem;
color: var(--color-danger);
flex-shrink: 0;
}
.collab-errors-button-shake {
animation: strong-shake 0.15s 6;
}
@keyframes strong-shake {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(10deg);
}
50% {
transform: rotate(0eg);
}
75% {
transform: rotate(-10deg);
}
100% {
transform: rotate(0deg);
}
}
}

View File

@ -0,0 +1,54 @@
import { Tooltip } from "../../packages/excalidraw/components/Tooltip";
import { warning } from "../../packages/excalidraw/components/icons";
import clsx from "clsx";
import { useEffect, useRef, useState } from "react";
import "./CollabError.scss";
import { atom } from "jotai";
type ErrorIndicator = {
message: string | null;
/** used to rerun the useEffect responsible for animation */
nonce: number;
};
export const collabErrorIndicatorAtom = atom<ErrorIndicator>({
message: null,
nonce: 0,
});
const CollabError = ({ collabError }: { collabError: ErrorIndicator }) => {
const [isAnimating, setIsAnimating] = useState(false);
const clearAnimationRef = useRef<string | number | NodeJS.Timeout>();
useEffect(() => {
setIsAnimating(true);
clearAnimationRef.current = setTimeout(() => {
setIsAnimating(false);
}, 1000);
return () => {
clearTimeout(clearAnimationRef.current);
};
}, [collabError.message, collabError.nonce]);
if (!collabError.message) {
return null;
}
return (
<Tooltip label={collabError.message} long={true}>
<div
className={clsx("collab-errors-button", {
"collab-errors-button-shake": isAnimating,
})}
>
{warning}
</div>
</Tooltip>
);
};
CollabError.displayName = "CollabError";
export default CollabError;

View File

@ -2,27 +2,27 @@ import {
isSyncableElement,
SocketUpdateData,
SocketUpdateDataSource,
SyncableExcalidrawElement,
} from "../data";
import { TCollabClass } from "./Collab";
import { ExcalidrawElement } from "../../src/element/types";
import { OrderedExcalidrawElement } from "../../packages/excalidraw/element/types";
import { WS_EVENTS, FILE_UPLOAD_TIMEOUT, WS_SUBTYPES } from "../app_constants";
import {
WS_EVENTS,
FILE_UPLOAD_TIMEOUT,
WS_SCENE_EVENT_TYPES,
} from "../app_constants";
import { UserIdleState } from "../../src/types";
import { trackEvent } from "../../src/analytics";
OnUserFollowedPayload,
SocketId,
UserIdleState,
} from "../../packages/excalidraw/types";
import { trackEvent } from "../../packages/excalidraw/analytics";
import throttle from "lodash.throttle";
import { newElementWith } from "../../src/element/mutateElement";
import { BroadcastedExcalidrawElement } from "./reconciliation";
import { encryptData } from "../../src/data/encryption";
import { PRECEDING_ELEMENT_KEY } from "../../src/constants";
import { newElementWith } from "../../packages/excalidraw/element/mutateElement";
import { encryptData } from "../../packages/excalidraw/data/encryption";
import type { Socket } from "socket.io-client";
class Portal {
collab: TCollabClass;
socket: SocketIOClient.Socket | null = null;
socket: Socket | null = null;
socketInitialized: boolean = false; // we don't want the socket to emit any updates until it is fully initialized
roomId: string | null = null;
roomKey: string | null = null;
@ -32,7 +32,7 @@ class Portal {
this.collab = collab;
}
open(socket: SocketIOClient.Socket, id: string, key: string) {
open(socket: Socket, id: string, key: string) {
this.socket = socket;
this.roomId = id;
this.roomKey = key;
@ -46,12 +46,12 @@ class Portal {
});
this.socket.on("new-user", async (_socketId: string) => {
this.broadcastScene(
WS_SCENE_EVENT_TYPES.INIT,
WS_SUBTYPES.INIT,
this.collab.getSceneElementsIncludingDeleted(),
/* syncAll */ true,
);
});
this.socket.on("room-user-change", (clients: string[]) => {
this.socket.on("room-user-change", (clients: SocketId[]) => {
this.collab.setCollaborators(clients);
});
@ -83,6 +83,7 @@ class Portal {
async _broadcastSocketData(
data: SocketUpdateData,
volatile: boolean = false,
roomId?: string,
) {
if (this.isOpen()) {
const json = JSON.stringify(data);
@ -91,7 +92,7 @@ class Portal {
this.socket?.emit(
volatile ? WS_EVENTS.SERVER_VOLATILE : WS_EVENTS.SERVER,
this.roomId,
roomId ?? this.roomId,
encryptedBuffer,
iv,
);
@ -130,36 +131,28 @@ class Portal {
}, FILE_UPLOAD_TIMEOUT);
broadcastScene = async (
updateType: WS_SCENE_EVENT_TYPES.INIT | WS_SCENE_EVENT_TYPES.UPDATE,
allElements: readonly ExcalidrawElement[],
updateType: WS_SUBTYPES.INIT | WS_SUBTYPES.UPDATE,
elements: readonly OrderedExcalidrawElement[],
syncAll: boolean,
) => {
if (updateType === WS_SCENE_EVENT_TYPES.INIT && !syncAll) {
if (updateType === WS_SUBTYPES.INIT && !syncAll) {
throw new Error("syncAll must be true when sending SCENE.INIT");
}
// sync out only the elements we think we need to to save bandwidth.
// periodically we'll resync the whole thing to make sure no one diverges
// due to a dropped message (server goes down etc).
const syncableElements = allElements.reduce(
(acc, element: BroadcastedExcalidrawElement, idx, elements) => {
if (
(syncAll ||
!this.broadcastedElementVersions.has(element.id) ||
element.version >
this.broadcastedElementVersions.get(element.id)!) &&
isSyncableElement(element)
) {
acc.push({
...element,
// z-index info for the reconciler
[PRECEDING_ELEMENT_KEY]: idx === 0 ? "^" : elements[idx - 1]?.id,
});
}
return acc;
},
[] as BroadcastedExcalidrawElement[],
);
const syncableElements = elements.reduce((acc, element) => {
if (
(syncAll ||
!this.broadcastedElementVersions.has(element.id) ||
element.version > this.broadcastedElementVersions.get(element.id)!) &&
isSyncableElement(element)
) {
acc.push(element);
}
return acc;
}, [] as SyncableExcalidrawElement[]);
const data: SocketUpdateDataSource[typeof updateType] = {
type: updateType,
@ -183,9 +176,9 @@ class Portal {
broadcastIdleChange = (userState: UserIdleState) => {
if (this.socket?.id) {
const data: SocketUpdateDataSource["IDLE_STATUS"] = {
type: "IDLE_STATUS",
type: WS_SUBTYPES.IDLE_STATUS,
payload: {
socketId: this.socket.id,
socketId: this.socket.id as SocketId,
userState,
username: this.collab.state.username,
},
@ -203,9 +196,9 @@ class Portal {
}) => {
if (this.socket?.id) {
const data: SocketUpdateDataSource["MOUSE_LOCATION"] = {
type: "MOUSE_LOCATION",
type: WS_SUBTYPES.MOUSE_LOCATION,
payload: {
socketId: this.socket.id,
socketId: this.socket.id as SocketId,
pointer: payload.pointer,
button: payload.button || "up",
selectedElementIds:
@ -213,12 +206,43 @@ class Portal {
username: this.collab.state.username,
},
};
return this._broadcastSocketData(
data as SocketUpdateData,
true, // volatile
);
}
};
broadcastVisibleSceneBounds = (
payload: {
sceneBounds: SocketUpdateDataSource["USER_VISIBLE_SCENE_BOUNDS"]["payload"]["sceneBounds"];
},
roomId: string,
) => {
if (this.socket?.id) {
const data: SocketUpdateDataSource["USER_VISIBLE_SCENE_BOUNDS"] = {
type: WS_SUBTYPES.USER_VISIBLE_SCENE_BOUNDS,
payload: {
socketId: this.socket.id as SocketId,
username: this.collab.state.username,
sceneBounds: payload.sceneBounds,
},
};
return this._broadcastSocketData(
data as SocketUpdateData,
true, // volatile
roomId,
);
}
};
broadcastUserFollowed = (payload: OnUserFollowedPayload) => {
if (this.socket?.id) {
this.socket.emit(WS_EVENTS.USER_FOLLOW_CHANGE, payload);
}
};
}
export default Portal;

View File

@ -1,13 +1,13 @@
import { useRef, useState } from "react";
import * as Popover from "@radix-ui/react-popover";
import { copyTextToSystemClipboard } from "../../src/clipboard";
import { trackEvent } from "../../src/analytics";
import { getFrame } from "../../src/utils";
import { useI18n } from "../../src/i18n";
import { KEYS } from "../../src/keys";
import { copyTextToSystemClipboard } from "../../packages/excalidraw/clipboard";
import { trackEvent } from "../../packages/excalidraw/analytics";
import { getFrame } from "../../packages/excalidraw/utils";
import { useI18n } from "../../packages/excalidraw/i18n";
import { KEYS } from "../../packages/excalidraw/keys";
import { Dialog } from "../../src/components/Dialog";
import { Dialog } from "../../packages/excalidraw/components/Dialog";
import {
copyIcon,
playerPlayIcon,
@ -16,11 +16,11 @@ import {
shareIOS,
shareWindows,
tablerCheckIcon,
} from "../../src/components/icons";
import { TextField } from "../../src/components/TextField";
import { FilledButton } from "../../src/components/FilledButton";
} from "../../packages/excalidraw/components/icons";
import { TextField } from "../../packages/excalidraw/components/TextField";
import { FilledButton } from "../../packages/excalidraw/components/FilledButton";
import { ReactComponent as CollabImage } from "../../src/assets/lock.svg";
import { ReactComponent as CollabImage } from "../../packages/excalidraw/assets/lock.svg";
import "./RoomDialog.scss";
const getShareIcon = () => {
@ -65,19 +65,18 @@ export const RoomModal = ({
const copyRoomLink = async () => {
try {
await copyTextToSystemClipboard(activeRoomLink);
setJustCopied(true);
if (timerRef.current) {
window.clearTimeout(timerRef.current);
}
timerRef.current = window.setTimeout(() => {
setJustCopied(false);
}, 3000);
} catch (error: any) {
setErrorMessage(error.message);
} catch (e) {
setErrorMessage(t("errors.copyToSystemClipboardFailed"));
}
setJustCopied(true);
if (timerRef.current) {
window.clearTimeout(timerRef.current);
}
timerRef.current = window.setTimeout(() => {
setJustCopied(false);
}, 3000);
ref.current?.select();
};
@ -120,7 +119,7 @@ export const RoomModal = ({
size="large"
variant="icon"
label="Share"
startIcon={getShareIcon()}
icon={getShareIcon()}
className="RoomDialog__active__share"
onClick={shareRoomLink}
/>
@ -130,7 +129,7 @@ export const RoomModal = ({
<FilledButton
size="large"
label="Copy link"
startIcon={copyIcon}
icon={copyIcon}
onClick={copyRoomLink}
/>
</Popover.Trigger>
@ -166,7 +165,7 @@ export const RoomModal = ({
variant="outlined"
color="danger"
label={t("roomDialog.button_stopSession")}
startIcon={playerStopFilledIcon}
icon={playerStopFilledIcon}
onClick={() => {
trackEvent("share", "room closed");
onRoomDestroy();
@ -195,7 +194,7 @@ export const RoomModal = ({
<FilledButton
size="large"
label={t("roomDialog.button_startSession")}
startIcon={playerPlayIcon}
icon={playerPlayIcon}
onClick={() => {
trackEvent("share", "room creation", `ui (${getFrame()})`);
onRoomCreate();

View File

@ -1,154 +0,0 @@
import { PRECEDING_ELEMENT_KEY } from "../../src/constants";
import { ExcalidrawElement } from "../../src/element/types";
import { AppState } from "../../src/types";
import { arrayToMapWithIndex } from "../../src/utils";
export type ReconciledElements = readonly ExcalidrawElement[] & {
_brand: "reconciledElements";
};
export type BroadcastedExcalidrawElement = ExcalidrawElement & {
[PRECEDING_ELEMENT_KEY]?: string;
};
const shouldDiscardRemoteElement = (
localAppState: AppState,
local: ExcalidrawElement | undefined,
remote: BroadcastedExcalidrawElement,
): boolean => {
if (
local &&
// local element is being edited
(local.id === localAppState.editingElement?.id ||
local.id === localAppState.resizingElement?.id ||
local.id === localAppState.draggingElement?.id ||
// local element is newer
local.version > remote.version ||
// resolve conflicting edits deterministically by taking the one with
// the lowest versionNonce
(local.version === remote.version &&
local.versionNonce < remote.versionNonce))
) {
return true;
}
return false;
};
export const reconcileElements = (
localElements: readonly ExcalidrawElement[],
remoteElements: readonly BroadcastedExcalidrawElement[],
localAppState: AppState,
): ReconciledElements => {
const localElementsData =
arrayToMapWithIndex<ExcalidrawElement>(localElements);
const reconciledElements: ExcalidrawElement[] = localElements.slice();
const duplicates = new WeakMap<ExcalidrawElement, true>();
let cursor = 0;
let offset = 0;
let remoteElementIdx = -1;
for (const remoteElement of remoteElements) {
remoteElementIdx++;
const local = localElementsData.get(remoteElement.id);
if (shouldDiscardRemoteElement(localAppState, local?.[0], remoteElement)) {
if (remoteElement[PRECEDING_ELEMENT_KEY]) {
delete remoteElement[PRECEDING_ELEMENT_KEY];
}
continue;
}
// Mark duplicate for removal as it'll be replaced with the remote element
if (local) {
// Unless the remote and local elements are the same element in which case
// we need to keep it as we'd otherwise discard it from the resulting
// array.
if (local[0] === remoteElement) {
continue;
}
duplicates.set(local[0], true);
}
// parent may not be defined in case the remote client is running an older
// excalidraw version
const parent =
remoteElement[PRECEDING_ELEMENT_KEY] ||
remoteElements[remoteElementIdx - 1]?.id ||
null;
if (parent != null) {
delete remoteElement[PRECEDING_ELEMENT_KEY];
// ^ indicates the element is the first in elements array
if (parent === "^") {
offset++;
if (cursor === 0) {
reconciledElements.unshift(remoteElement);
localElementsData.set(remoteElement.id, [
remoteElement,
cursor - offset,
]);
} else {
reconciledElements.splice(cursor + 1, 0, remoteElement);
localElementsData.set(remoteElement.id, [
remoteElement,
cursor + 1 - offset,
]);
cursor++;
}
} else {
let idx = localElementsData.has(parent)
? localElementsData.get(parent)![1]
: null;
if (idx != null) {
idx += offset;
}
if (idx != null && idx >= cursor) {
reconciledElements.splice(idx + 1, 0, remoteElement);
offset++;
localElementsData.set(remoteElement.id, [
remoteElement,
idx + 1 - offset,
]);
cursor = idx + 1;
} else if (idx != null) {
reconciledElements.splice(cursor + 1, 0, remoteElement);
offset++;
localElementsData.set(remoteElement.id, [
remoteElement,
cursor + 1 - offset,
]);
cursor++;
} else {
reconciledElements.push(remoteElement);
localElementsData.set(remoteElement.id, [
remoteElement,
reconciledElements.length - 1 - offset,
]);
}
}
// no parent z-index information, local element exists → replace in place
} else if (local) {
reconciledElements[local[1]] = remoteElement;
localElementsData.set(remoteElement.id, [remoteElement, local[1]]);
// otherwise push to the end
} else {
reconciledElements.push(remoteElement);
localElementsData.set(remoteElement.id, [
remoteElement,
reconciledElements.length - 1 - offset,
]);
}
}
const ret: readonly ExcalidrawElement[] = reconciledElements.filter(
(element) => !duplicates.has(element),
);
return ret as ReconciledElements;
};

View File

@ -1,5 +1,5 @@
import React from "react";
import { Footer } from "../../src/packages/excalidraw/index";
import { Footer } from "../../packages/excalidraw/index";
import { EncryptedIcon } from "./EncryptedIcon";
import { ExcalidrawPlusAppLink } from "./ExcalidrawPlusAppLink";
import { isExcalidrawPlusSignedUser } from "../app_constants";

View File

@ -1,12 +1,19 @@
import React from "react";
import { PlusPromoIcon } from "../../src/components/icons";
import { MainMenu } from "../../src/packages/excalidraw/index";
import {
arrowBarToLeftIcon,
ExcalLogo,
} from "../../packages/excalidraw/components/icons";
import { Theme } from "../../packages/excalidraw/element/types";
import { MainMenu } from "../../packages/excalidraw/index";
import { isExcalidrawPlusSignedUser } from "../app_constants";
import { LanguageList } from "./LanguageList";
export const AppMainMenu: React.FC<{
setCollabDialogShown: (toggle: boolean) => any;
onCollabDialogOpen: () => any;
isCollaborating: boolean;
isCollabEnabled: boolean;
theme: Theme | "system";
setTheme: (theme: Theme | "system") => void;
}> = React.memo((props) => {
return (
<MainMenu>
@ -17,25 +24,38 @@ export const AppMainMenu: React.FC<{
{props.isCollabEnabled && (
<MainMenu.DefaultItems.LiveCollaborationTrigger
isCollaborating={props.isCollaborating}
onSelect={() => props.setCollabDialogShown(true)}
onSelect={() => props.onCollabDialogOpen()}
/>
)}
<MainMenu.DefaultItems.CommandPalette className="highlighted" />
<MainMenu.DefaultItems.Help />
<MainMenu.DefaultItems.ClearCanvas />
<MainMenu.Separator />
<MainMenu.ItemLink
icon={PlusPromoIcon}
icon={ExcalLogo}
href={`${
import.meta.env.VITE_APP_PLUS_LP
import.meta.env.VITE_APP_PLUS_APP
}/plus?utm_source=excalidraw&utm_medium=app&utm_content=hamburger`}
className="ExcalidrawPlus"
className=""
>
Excalidraw+
</MainMenu.ItemLink>
<MainMenu.DefaultItems.Socials />
<MainMenu.ItemLink
icon={arrowBarToLeftIcon}
href={`${import.meta.env.VITE_APP_PLUS_APP}${
isExcalidrawPlusSignedUser ? "" : "/sign-up"
}?utm_source=signin&utm_medium=app&utm_content=hamburger`}
className="highlighted"
>
{isExcalidrawPlusSignedUser ? "Sign in" : "Sign up"}
</MainMenu.ItemLink>
<MainMenu.Separator />
<MainMenu.DefaultItems.ToggleTheme />
<MainMenu.DefaultItems.ToggleTheme
allowSystemTheme
theme={props.theme}
onSelect={props.setTheme}
/>
<MainMenu.ItemCustom>
<LanguageList style={{ width: "100%" }} />
</MainMenu.ItemCustom>

View File

@ -1,12 +1,12 @@
import React from "react";
import { PlusPromoIcon } from "../../src/components/icons";
import { useI18n } from "../../src/i18n";
import { WelcomeScreen } from "../../src/packages/excalidraw/index";
import { arrowBarToLeftIcon } from "../../packages/excalidraw/components/icons";
import { useI18n } from "../../packages/excalidraw/i18n";
import { WelcomeScreen } from "../../packages/excalidraw/index";
import { isExcalidrawPlusSignedUser } from "../app_constants";
import { POINTER_EVENTS } from "../../src/constants";
import { POINTER_EVENTS } from "../../packages/excalidraw/constants";
export const AppWelcomeScreen: React.FC<{
setCollabDialogShown: (toggle: boolean) => any;
onCollabDialogOpen: () => any;
isCollabEnabled: boolean;
}> = React.memo((props) => {
const { t } = useI18n();
@ -52,7 +52,7 @@ export const AppWelcomeScreen: React.FC<{
<WelcomeScreen.Center.MenuItemHelp />
{props.isCollabEnabled && (
<WelcomeScreen.Center.MenuItemLiveCollaborationTrigger
onSelect={() => props.setCollabDialogShown(true)}
onSelect={() => props.onCollabDialogOpen()}
/>
)}
{!isExcalidrawPlusSignedUser && (
@ -61,9 +61,9 @@ export const AppWelcomeScreen: React.FC<{
import.meta.env.VITE_APP_PLUS_LP
}/plus?utm_source=excalidraw&utm_medium=app&utm_content=welcomeScreenGuest`}
shortcut={null}
icon={PlusPromoIcon}
icon={arrowBarToLeftIcon}
>
Try Excalidraw Plus!
Sign up
</WelcomeScreen.Center.MenuItemLink>
)}
</WelcomeScreen.Center.Menu>

View File

@ -1,6 +1,6 @@
import { shield } from "../../src/components/icons";
import { Tooltip } from "../../src/components/Tooltip";
import { useI18n } from "../../src/i18n";
import { shield } from "../../packages/excalidraw/components/icons";
import { Tooltip } from "../../packages/excalidraw/components/Tooltip";
import { useI18n } from "../../packages/excalidraw/i18n";
export const EncryptedIcon = () => {
const { t } = useI18n();

View File

@ -1,25 +1,36 @@
import React from "react";
import { Card } from "../../src/components/Card";
import { ToolButton } from "../../src/components/ToolButton";
import { serializeAsJSON } from "../../src/data/json";
import { Card } from "../../packages/excalidraw/components/Card";
import { ToolButton } from "../../packages/excalidraw/components/ToolButton";
import { serializeAsJSON } from "../../packages/excalidraw/data/json";
import { loadFirebaseStorage, saveFilesToFirebase } from "../data/firebase";
import { FileId, NonDeletedExcalidrawElement } from "../../src/element/types";
import { AppState, BinaryFileData, BinaryFiles } from "../../src/types";
import {
FileId,
NonDeletedExcalidrawElement,
} from "../../packages/excalidraw/element/types";
import {
AppState,
BinaryFileData,
BinaryFiles,
} from "../../packages/excalidraw/types";
import { nanoid } from "nanoid";
import { useI18n } from "../../src/i18n";
import { encryptData, generateEncryptionKey } from "../../src/data/encryption";
import { isInitializedImageElement } from "../../src/element/typeChecks";
import { useI18n } from "../../packages/excalidraw/i18n";
import {
encryptData,
generateEncryptionKey,
} from "../../packages/excalidraw/data/encryption";
import { isInitializedImageElement } from "../../packages/excalidraw/element/typeChecks";
import { FILE_UPLOAD_MAX_BYTES } from "../app_constants";
import { encodeFilesForUpload } from "../data/FileManager";
import { MIME_TYPES } from "../../src/constants";
import { trackEvent } from "../../src/analytics";
import { getFrame } from "../../src/utils";
import { ExcalidrawLogo } from "../../src/components/ExcalidrawLogo";
import { MIME_TYPES } from "../../packages/excalidraw/constants";
import { trackEvent } from "../../packages/excalidraw/analytics";
import { getFrame } from "../../packages/excalidraw/utils";
import { ExcalidrawLogo } from "../../packages/excalidraw/components/ExcalidrawLogo";
export const exportToExcalidrawPlus = async (
elements: readonly NonDeletedExcalidrawElement[],
appState: Partial<AppState>,
files: BinaryFiles,
name: string,
) => {
const firebase = await loadFirebaseStorage();
@ -43,7 +54,7 @@ export const exportToExcalidrawPlus = async (
.ref(`/migrations/scenes/${id}`)
.put(blob, {
customMetadata: {
data: JSON.stringify({ version: 2, name: appState.name }),
data: JSON.stringify({ version: 2, name }),
created: Date.now().toString(),
},
});
@ -79,8 +90,10 @@ export const ExportToExcalidrawPlus: React.FC<{
elements: readonly NonDeletedExcalidrawElement[];
appState: Partial<AppState>;
files: BinaryFiles;
name: string;
onError: (error: Error) => void;
}> = ({ elements, appState, files, onError }) => {
onSuccess: () => void;
}> = ({ elements, appState, files, name, onError, onSuccess }) => {
const { t } = useI18n();
return (
<Card color="primary">
@ -106,7 +119,8 @@ export const ExportToExcalidrawPlus: React.FC<{
onClick={async () => {
try {
trackEvent("export", "eplus", `ui (${getFrame()})`);
await exportToExcalidrawPlus(elements, appState, files);
await exportToExcalidrawPlus(elements, appState, files, name);
onSuccess();
} catch (error: any) {
console.error(error);
if (error.name !== "AbortError") {

View File

@ -1,7 +1,7 @@
import oc from "open-color";
import React from "react";
import { THEME } from "../../src/constants";
import { Theme } from "../../src/element/types";
import { THEME } from "../../packages/excalidraw/constants";
import { Theme } from "../../packages/excalidraw/element/types";
// https://github.com/tholman/github-corners
export const GitHubCorner = React.memo(

View File

@ -1,8 +1,8 @@
import { useSetAtom } from "jotai";
import React from "react";
import { appLangCodeAtom } from "..";
import { useI18n } from "../../src/i18n";
import { languages } from "../../src/i18n";
import { appLangCodeAtom } from "../App";
import { useI18n } from "../../packages/excalidraw/i18n";
import { languages } from "../../packages/excalidraw/i18n";
export const LanguageList = ({ style }: { style?: React.CSSProperties }) => {
const { t, langCode } = useI18n();

View File

@ -1,7 +1,7 @@
import React from "react";
import * as Sentry from "@sentry/browser";
import { t } from "../i18n";
import Trans from "./Trans";
import { t } from "../../packages/excalidraw/i18n";
import Trans from "../../packages/excalidraw/components/Trans";
interface TopErrorBoundaryState {
hasError: boolean;
@ -67,6 +67,8 @@ export class TopErrorBoundary extends React.Component<
window.open(
`https://github.com/excalidraw/excalidraw/issues/new?body=${body}`,
"_blank",
"noopener noreferrer",
);
}

View File

@ -1,19 +1,19 @@
import { compressData } from "../../src/data/encode";
import { newElementWith } from "../../src/element/mutateElement";
import { isInitializedImageElement } from "../../src/element/typeChecks";
import { compressData } from "../../packages/excalidraw/data/encode";
import { newElementWith } from "../../packages/excalidraw/element/mutateElement";
import { isInitializedImageElement } from "../../packages/excalidraw/element/typeChecks";
import {
ExcalidrawElement,
ExcalidrawImageElement,
FileId,
InitializedExcalidrawImageElement,
} from "../../src/element/types";
import { t } from "../../src/i18n";
} from "../../packages/excalidraw/element/types";
import { t } from "../../packages/excalidraw/i18n";
import {
BinaryFileData,
BinaryFileMetadata,
ExcalidrawImperativeAPI,
BinaryFiles,
} from "../../src/types";
} from "../../packages/excalidraw/types";
export class FileManager {
/** files being fetched */

View File

@ -6,16 +6,34 @@
*
* - DataState refers to full state of the app: appState, elements, images,
* though some state is saved separately (collab username, library) for one
* reason or another. We also save different data to different sotrage
* reason or another. We also save different data to different storage
* (localStorage, indexedDB).
*/
import { createStore, entries, del, getMany, set, setMany } from "idb-keyval";
import { clearAppStateForLocalStorage } from "../../src/appState";
import { clearElementsForLocalStorage } from "../../src/element";
import { ExcalidrawElement, FileId } from "../../src/element/types";
import { AppState, BinaryFileData, BinaryFiles } from "../../src/types";
import { debounce } from "../../src/utils";
import {
createStore,
entries,
del,
getMany,
set,
setMany,
get,
} from "idb-keyval";
import { clearAppStateForLocalStorage } from "../../packages/excalidraw/appState";
import { LibraryPersistedData } from "../../packages/excalidraw/data/library";
import { ImportedDataState } from "../../packages/excalidraw/data/types";
import { clearElementsForLocalStorage } from "../../packages/excalidraw/element";
import {
ExcalidrawElement,
FileId,
} from "../../packages/excalidraw/element/types";
import {
AppState,
BinaryFileData,
BinaryFiles,
} from "../../packages/excalidraw/types";
import { MaybePromise } from "../../packages/excalidraw/utility-types";
import { debounce } from "../../packages/excalidraw/utils";
import { SAVE_TO_LOCAL_STORAGE_TIMEOUT, STORAGE_KEYS } from "../app_constants";
import { FileManager } from "./FileManager";
import { Locker } from "./Locker";
@ -176,3 +194,52 @@ export class LocalData {
},
});
}
export class LibraryIndexedDBAdapter {
/** IndexedDB database and store name */
private static idb_name = STORAGE_KEYS.IDB_LIBRARY;
/** library data store key */
private static key = "libraryData";
private static store = createStore(
`${LibraryIndexedDBAdapter.idb_name}-db`,
`${LibraryIndexedDBAdapter.idb_name}-store`,
);
static async load() {
const IDBData = await get<LibraryPersistedData>(
LibraryIndexedDBAdapter.key,
LibraryIndexedDBAdapter.store,
);
return IDBData || null;
}
static save(data: LibraryPersistedData): MaybePromise<void> {
return set(
LibraryIndexedDBAdapter.key,
data,
LibraryIndexedDBAdapter.store,
);
}
}
/** LS Adapter used only for migrating LS library data
* to indexedDB */
export class LibraryLocalStorageMigrationAdapter {
static load() {
const LSData = localStorage.getItem(
STORAGE_KEYS.__LEGACY_LOCAL_STORAGE_LIBRARY,
);
if (LSData != null) {
const libraryItems: ImportedDataState["libraryItems"] =
JSON.parse(LSData);
if (libraryItems) {
return { libraryItems };
}
}
return null;
}
static clear() {
localStorage.removeItem(STORAGE_KEYS.__LEGACY_LOCAL_STORAGE_LIBRARY);
}
}

View File

@ -1,20 +1,31 @@
import { ExcalidrawElement, FileId } from "../../src/element/types";
import { getSceneVersion } from "../../src/element";
import {
ExcalidrawElement,
FileId,
OrderedExcalidrawElement,
} from "../../packages/excalidraw/element/types";
import { getSceneVersion } from "../../packages/excalidraw/element";
import Portal from "../collab/Portal";
import { restoreElements } from "../../src/data/restore";
import { restoreElements } from "../../packages/excalidraw/data/restore";
import {
AppState,
BinaryFileData,
BinaryFileMetadata,
DataURL,
} from "../../src/types";
} from "../../packages/excalidraw/types";
import { FILE_CACHE_MAX_AGE_SEC } from "../app_constants";
import { decompressData } from "../../src/data/encode";
import { encryptData, decryptData } from "../../src/data/encryption";
import { MIME_TYPES } from "../../src/constants";
import { reconcileElements } from "../collab/reconciliation";
import { decompressData } from "../../packages/excalidraw/data/encode";
import {
encryptData,
decryptData,
} from "../../packages/excalidraw/data/encryption";
import { MIME_TYPES } from "../../packages/excalidraw/constants";
import { getSyncableElements, SyncableExcalidrawElement } from ".";
import { ResolutionType } from "../../src/utility-types";
import { ResolutionType } from "../../packages/excalidraw/utility-types";
import type { Socket } from "socket.io-client";
import {
RemoteExcalidrawElement,
reconcileElements,
} from "../../packages/excalidraw/data/reconcile";
// private
// -----------------------------------------------------------------------------
@ -132,12 +143,12 @@ const decryptElements = async (
};
class FirebaseSceneVersionCache {
private static cache = new WeakMap<SocketIOClient.Socket, number>();
static get = (socket: SocketIOClient.Socket) => {
private static cache = new WeakMap<Socket, number>();
static get = (socket: Socket) => {
return FirebaseSceneVersionCache.cache.get(socket);
};
static set = (
socket: SocketIOClient.Socket,
socket: Socket,
elements: readonly SyncableExcalidrawElement[],
) => {
FirebaseSceneVersionCache.cache.set(socket, getSceneVersion(elements));
@ -223,7 +234,7 @@ export const saveToFirebase = async (
!socket ||
isSavedToFirebase(portal, elements)
) {
return false;
return null;
}
const firebase = await loadFirestore();
@ -231,56 +242,59 @@ export const saveToFirebase = async (
const docRef = firestore.collection("scenes").doc(roomId);
const savedData = await firestore.runTransaction(async (transaction) => {
const storedScene = await firestore.runTransaction(async (transaction) => {
const snapshot = await transaction.get(docRef);
if (!snapshot.exists) {
const sceneDocument = await createFirebaseSceneDocument(
const storedScene = await createFirebaseSceneDocument(
firebase,
elements,
roomKey,
);
transaction.set(docRef, sceneDocument);
transaction.set(docRef, storedScene);
return {
elements,
reconciledElements: null,
};
return storedScene;
}
const prevDocData = snapshot.data() as FirebaseStoredScene;
const prevElements = getSyncableElements(
await decryptElements(prevDocData, roomKey),
const prevStoredScene = snapshot.data() as FirebaseStoredScene;
const prevStoredElements = getSyncableElements(
restoreElements(await decryptElements(prevStoredScene, roomKey), null),
);
const reconciledElements = getSyncableElements(
reconcileElements(elements, prevElements, appState),
reconcileElements(
elements,
prevStoredElements as OrderedExcalidrawElement[] as RemoteExcalidrawElement[],
appState,
),
);
const sceneDocument = await createFirebaseSceneDocument(
const storedScene = await createFirebaseSceneDocument(
firebase,
reconciledElements,
roomKey,
);
transaction.update(docRef, sceneDocument);
return {
elements,
reconciledElements,
};
transaction.update(docRef, storedScene);
// Return the stored elements as the in memory `reconciledElements` could have mutated in the meantime
return storedScene;
});
FirebaseSceneVersionCache.set(socket, savedData.elements);
const storedElements = getSyncableElements(
restoreElements(await decryptElements(storedScene, roomKey), null),
);
return { reconciledElements: savedData.reconciledElements };
FirebaseSceneVersionCache.set(socket, storedElements);
return storedElements;
};
export const loadFromFirebase = async (
roomId: string,
roomKey: string,
socket: SocketIOClient.Socket | null,
): Promise<readonly ExcalidrawElement[] | null> => {
socket: Socket | null,
): Promise<readonly SyncableExcalidrawElement[] | null> => {
const firebase = await loadFirestore();
const db = firebase.firestore();
@ -291,14 +305,14 @@ export const loadFromFirebase = async (
}
const storedScene = doc.data() as FirebaseStoredScene;
const elements = getSyncableElements(
await decryptElements(storedScene, roomKey),
restoreElements(await decryptElements(storedScene, roomKey), null),
);
if (socket) {
FirebaseSceneVersionCache.set(socket, elements);
}
return restoreElements(elements, null);
return elements;
};
export const loadFilesFromFirebase = async (

Some files were not shown because too many files have changed in this diff Show More