@inshapardaz/likhari-react 0.1.8 → 0.1.9-dev.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EditorRoot.d.ts +60 -0
- package/dist/EditorRoot.d.ts.map +1 -1
- package/dist/EditorRoot.js +183 -10
- package/dist/components/DraftRestore.d.ts +24 -0
- package/dist/components/DraftRestore.d.ts.map +1 -0
- package/dist/components/DraftRestore.js +61 -0
- package/dist/components/DraftsDialog.d.ts +25 -0
- package/dist/components/DraftsDialog.d.ts.map +1 -0
- package/dist/components/DraftsDialog.js +66 -0
- package/dist/components/LeaveDialog.d.ts +22 -0
- package/dist/components/LeaveDialog.d.ts.map +1 -0
- package/dist/components/LeaveDialog.js +15 -0
- package/dist/components/TableDialog.d.ts +17 -0
- package/dist/components/TableDialog.d.ts.map +1 -0
- package/dist/components/TableDialog.js +33 -0
- package/dist/components/Toolbar.d.ts +4 -1
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +110 -6
- package/dist/i18n/strings.d.ts +65 -2
- package/dist/i18n/strings.d.ts.map +1 -1
- package/dist/i18n/strings.js +168 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +4 -0
- package/dist/persistence/draftStorage.d.ts +55 -0
- package/dist/persistence/draftStorage.d.ts.map +1 -0
- package/dist/persistence/draftStorage.js +198 -0
- package/dist/persistence/draftUi.d.ts +9 -0
- package/dist/persistence/draftUi.d.ts.map +1 -0
- package/dist/persistence/draftUi.js +23 -0
- package/dist/table/tableActions.d.ts +21 -0
- package/dist/table/tableActions.d.ts.map +1 -0
- package/dist/table/tableActions.js +71 -0
- package/dist/theme/editor.css +111 -0
- package/dist/theme/editorTheme.d.ts.map +1 -1
- package/dist/theme/editorTheme.js +5 -0
- package/package.json +2 -1
package/dist/i18n/strings.js
CHANGED
|
@@ -8,7 +8,6 @@ const en = {
|
|
|
8
8
|
editor: {
|
|
9
9
|
placeholder: 'Start writing…',
|
|
10
10
|
contentLabel: 'Editor content',
|
|
11
|
-
confirmDiscard: 'You have unsaved changes. Discard them?',
|
|
12
11
|
},
|
|
13
12
|
common: {
|
|
14
13
|
cancel: 'Cancel',
|
|
@@ -18,6 +17,7 @@ const en = {
|
|
|
18
17
|
toolbar: {
|
|
19
18
|
ariaLabel: 'Formatting',
|
|
20
19
|
save: 'Save',
|
|
20
|
+
drafts: 'Drafts',
|
|
21
21
|
undo: 'Undo',
|
|
22
22
|
redo: 'Redo',
|
|
23
23
|
formattingLabel: 'Formatting',
|
|
@@ -31,8 +31,11 @@ const en = {
|
|
|
31
31
|
noMatch: 'No match',
|
|
32
32
|
alignment: 'Alignment',
|
|
33
33
|
linkOptions: 'Link options',
|
|
34
|
+
tableOptions: 'Table options',
|
|
34
35
|
insertLink: 'Insert link (Ctrl+K)',
|
|
35
36
|
insertImage: 'Insert image',
|
|
37
|
+
insertTable: 'Insert table',
|
|
38
|
+
insertHorizontalRule: 'Insert horizontal rule',
|
|
36
39
|
poetryBlocks: 'Poetry blocks',
|
|
37
40
|
comingSoon: (label) => `${label} (coming soon)`,
|
|
38
41
|
autocorrect: 'Auto-correct',
|
|
@@ -65,6 +68,52 @@ const en = {
|
|
|
65
68
|
right: 'Align right',
|
|
66
69
|
},
|
|
67
70
|
},
|
|
71
|
+
leaveDialog: {
|
|
72
|
+
title: 'Unsaved changes',
|
|
73
|
+
message: 'You have unsaved changes. What would you like to do before leaving?',
|
|
74
|
+
save: 'Save',
|
|
75
|
+
saveDraft: 'Save draft',
|
|
76
|
+
discard: 'Discard',
|
|
77
|
+
saveDraftFailed: "The draft couldn't be saved (the document may be too large, or browser storage is unavailable).",
|
|
78
|
+
},
|
|
79
|
+
drafts: {
|
|
80
|
+
bannerMessage: (when) => `An unsaved draft of this document from ${when} was found.`,
|
|
81
|
+
restore: 'Restore',
|
|
82
|
+
ignore: 'Ignore',
|
|
83
|
+
remove: 'Remove draft',
|
|
84
|
+
dialogTitle: 'Saved drafts',
|
|
85
|
+
intro: 'Drafts are saved in this browser as you type, and removed when you save.',
|
|
86
|
+
empty: 'No drafts yet.',
|
|
87
|
+
noText: '(no text)',
|
|
88
|
+
thisDocument: 'Current document',
|
|
89
|
+
untitled: 'Untitled draft',
|
|
90
|
+
documentLabel: (id) => `Document “${id}”`,
|
|
91
|
+
earlierUntitled: 'Earlier version of an untitled draft',
|
|
92
|
+
earlierVersionOf: (id) => `Earlier version of “${id}”`,
|
|
93
|
+
savedAt: (when) => `Saved ${when}`,
|
|
94
|
+
size: (kb) => `${kb} KB`,
|
|
95
|
+
replacePrompt: 'Replace the current content with this draft?',
|
|
96
|
+
replace: 'Replace',
|
|
97
|
+
deletePrompt: 'Delete this draft?',
|
|
98
|
+
delete: 'Delete',
|
|
99
|
+
close: 'Close',
|
|
100
|
+
},
|
|
101
|
+
tableMenu: {
|
|
102
|
+
menuLabel: 'Table',
|
|
103
|
+
insertRowBefore: 'Insert row before',
|
|
104
|
+
insertRowAfter: 'Insert row after',
|
|
105
|
+
insertColumnBefore: 'Insert column before',
|
|
106
|
+
insertColumnAfter: 'Insert column after',
|
|
107
|
+
deleteRow: 'Delete row',
|
|
108
|
+
deleteColumn: 'Delete column',
|
|
109
|
+
deleteTable: 'Delete table',
|
|
110
|
+
insertRowsBefore: 'Insert rows before',
|
|
111
|
+
insertRowsAfter: 'Insert rows after',
|
|
112
|
+
insertColumnsBefore: 'Insert columns before',
|
|
113
|
+
insertColumnsAfter: 'Insert columns after',
|
|
114
|
+
deleteRows: 'Delete rows',
|
|
115
|
+
deleteColumns: 'Delete columns',
|
|
116
|
+
},
|
|
68
117
|
link: {
|
|
69
118
|
menuLabel: 'Link',
|
|
70
119
|
noUrl: '(no URL)',
|
|
@@ -81,6 +130,12 @@ const en = {
|
|
|
81
130
|
invalidUrl: 'Enter a valid http(s), mailto, tel or relative URL',
|
|
82
131
|
apply: 'Apply',
|
|
83
132
|
},
|
|
133
|
+
tableDialog: {
|
|
134
|
+
title: 'Insert table',
|
|
135
|
+
rows: 'Rows',
|
|
136
|
+
columns: 'Columns',
|
|
137
|
+
headerRow: 'Header row',
|
|
138
|
+
},
|
|
84
139
|
imageDialog: {
|
|
85
140
|
titleInsert: 'Insert image',
|
|
86
141
|
titleEdit: 'Edit image',
|
|
@@ -144,7 +199,6 @@ const ur = {
|
|
|
144
199
|
editor: {
|
|
145
200
|
placeholder: 'لکھنا شروع کریں…',
|
|
146
201
|
contentLabel: 'ایڈیٹر کا مواد',
|
|
147
|
-
confirmDiscard: 'آپ کی غیر محفوظ شدہ تبدیلیاں ہیں۔ کیا انہیں رد کر دیا جائے؟',
|
|
148
202
|
},
|
|
149
203
|
common: {
|
|
150
204
|
cancel: 'منسوخ کریں',
|
|
@@ -154,6 +208,7 @@ const ur = {
|
|
|
154
208
|
toolbar: {
|
|
155
209
|
ariaLabel: 'فارمیٹنگ',
|
|
156
210
|
save: 'محفوظ کریں',
|
|
211
|
+
drafts: 'مسودے',
|
|
157
212
|
undo: 'کالعدم کریں',
|
|
158
213
|
redo: 'دوبارہ کریں',
|
|
159
214
|
formattingLabel: 'فارمیٹنگ',
|
|
@@ -167,8 +222,11 @@ const ur = {
|
|
|
167
222
|
noMatch: 'کوئی مماثلت نہیں',
|
|
168
223
|
alignment: 'سیدھ',
|
|
169
224
|
linkOptions: 'لنک کے اختیارات',
|
|
225
|
+
tableOptions: 'جدول کے اختیارات',
|
|
170
226
|
insertLink: 'لنک شامل کریں (Ctrl+K)',
|
|
171
227
|
insertImage: 'تصویر شامل کریں',
|
|
228
|
+
insertTable: 'جدول شامل کریں',
|
|
229
|
+
insertHorizontalRule: 'افقی لکیر شامل کریں',
|
|
172
230
|
poetryBlocks: 'شاعری کے بلاکس',
|
|
173
231
|
comingSoon: (label) => `${label} (جلد آ رہا ہے)`,
|
|
174
232
|
autocorrect: 'خودکار تصحیح',
|
|
@@ -201,6 +259,52 @@ const ur = {
|
|
|
201
259
|
right: 'دائیں سیدھ',
|
|
202
260
|
},
|
|
203
261
|
},
|
|
262
|
+
leaveDialog: {
|
|
263
|
+
title: 'غیر محفوظ شدہ تبدیلیاں',
|
|
264
|
+
message: 'آپ کی تبدیلیاں محفوظ نہیں ہوئیں۔ جانے سے پہلے آپ کیا کرنا چاہیں گے؟',
|
|
265
|
+
save: 'محفوظ کریں',
|
|
266
|
+
saveDraft: 'مسودہ محفوظ کریں',
|
|
267
|
+
discard: 'رد کریں',
|
|
268
|
+
saveDraftFailed: 'مسودہ محفوظ نہیں ہو سکا (دستاویز بہت بڑی ہو سکتی ہے، یا براؤزر کا اسٹوریج دستیاب نہیں)۔',
|
|
269
|
+
},
|
|
270
|
+
drafts: {
|
|
271
|
+
bannerMessage: (when) => `اس دستاویز کا ایک غیر محفوظ شدہ مسودہ (${when}) ملا ہے۔`,
|
|
272
|
+
restore: 'بحال کریں',
|
|
273
|
+
ignore: 'نظر انداز کریں',
|
|
274
|
+
remove: 'مسودہ ہٹائیں',
|
|
275
|
+
dialogTitle: 'محفوظ شدہ مسودے',
|
|
276
|
+
intro: 'لکھتے وقت مسودے اس براؤزر میں خود بخود محفوظ ہوتے ہیں اور محفوظ کرنے پر ہٹا دیے جاتے ہیں۔',
|
|
277
|
+
empty: 'ابھی کوئی مسودہ نہیں۔',
|
|
278
|
+
noText: '(کوئی متن نہیں)',
|
|
279
|
+
thisDocument: 'موجودہ دستاویز',
|
|
280
|
+
untitled: 'بلا عنوان مسودہ',
|
|
281
|
+
documentLabel: (id) => `دستاویز «${id}»`,
|
|
282
|
+
earlierUntitled: 'ایک بلا عنوان مسودے کا پرانا ورژن',
|
|
283
|
+
earlierVersionOf: (id) => `«${id}» کا پرانا ورژن`,
|
|
284
|
+
savedAt: (when) => `محفوظ شدہ: ${when}`,
|
|
285
|
+
size: (kb) => `${kb} کے بی`,
|
|
286
|
+
replacePrompt: 'موجودہ مواد کو اس مسودے سے بدل دیں؟',
|
|
287
|
+
replace: 'بدل دیں',
|
|
288
|
+
deletePrompt: 'یہ مسودہ حذف کریں؟',
|
|
289
|
+
delete: 'حذف کریں',
|
|
290
|
+
close: 'بند کریں',
|
|
291
|
+
},
|
|
292
|
+
tableMenu: {
|
|
293
|
+
menuLabel: 'جدول',
|
|
294
|
+
insertRowBefore: 'پہلے قطار شامل کریں',
|
|
295
|
+
insertRowAfter: 'بعد میں قطار شامل کریں',
|
|
296
|
+
insertColumnBefore: 'پہلے کالم شامل کریں',
|
|
297
|
+
insertColumnAfter: 'بعد میں کالم شامل کریں',
|
|
298
|
+
deleteRow: 'قطار حذف کریں',
|
|
299
|
+
deleteColumn: 'کالم حذف کریں',
|
|
300
|
+
deleteTable: 'جدول حذف کریں',
|
|
301
|
+
insertRowsBefore: 'پہلے قطاریں شامل کریں',
|
|
302
|
+
insertRowsAfter: 'بعد میں قطاریں شامل کریں',
|
|
303
|
+
insertColumnsBefore: 'پہلے کالمز شامل کریں',
|
|
304
|
+
insertColumnsAfter: 'بعد میں کالمز شامل کریں',
|
|
305
|
+
deleteRows: 'قطاریں حذف کریں',
|
|
306
|
+
deleteColumns: 'کالمز حذف کریں',
|
|
307
|
+
},
|
|
204
308
|
link: {
|
|
205
309
|
menuLabel: 'لنک',
|
|
206
310
|
noUrl: '(کوئی یو آر ایل نہیں)',
|
|
@@ -217,6 +321,12 @@ const ur = {
|
|
|
217
321
|
invalidUrl: 'براہِ کرم ایک درست http(s)، mailto، tel یا رشتہ دار یو آر ایل درج کریں',
|
|
218
322
|
apply: 'لاگو کریں',
|
|
219
323
|
},
|
|
324
|
+
tableDialog: {
|
|
325
|
+
title: 'جدول شامل کریں',
|
|
326
|
+
rows: 'قطاریں',
|
|
327
|
+
columns: 'کالم',
|
|
328
|
+
headerRow: 'سرِ فہرست قطار',
|
|
329
|
+
},
|
|
220
330
|
imageDialog: {
|
|
221
331
|
titleInsert: 'تصویر شامل کریں',
|
|
222
332
|
titleEdit: 'تصویر میں ترمیم کریں',
|
|
@@ -280,7 +390,6 @@ const paShahmukhi = {
|
|
|
280
390
|
editor: {
|
|
281
391
|
placeholder: 'لکھنا شروع کرو…',
|
|
282
392
|
contentLabel: 'ایڈیٹر دی سامگری',
|
|
283
|
-
confirmDiscard: 'تہاڈیاں کجھ تبدیلیاں سنبھالیاں نئیں گئیاں۔ کی ایہناں نوں رد کر دیئے؟',
|
|
284
393
|
},
|
|
285
394
|
common: {
|
|
286
395
|
cancel: 'رد کرو',
|
|
@@ -290,6 +399,7 @@ const paShahmukhi = {
|
|
|
290
399
|
toolbar: {
|
|
291
400
|
ariaLabel: 'فارمیٹنگ',
|
|
292
401
|
save: 'سنبھالو',
|
|
402
|
+
drafts: 'سودھے',
|
|
293
403
|
undo: 'پہلاں جیہا کرو',
|
|
294
404
|
redo: 'مُڑ کرو',
|
|
295
405
|
formattingLabel: 'فارمیٹنگ',
|
|
@@ -303,8 +413,11 @@ const paShahmukhi = {
|
|
|
303
413
|
noMatch: 'کوئی نئیں ملیا',
|
|
304
414
|
alignment: 'سیدھ',
|
|
305
415
|
linkOptions: 'لنک دے اختیار',
|
|
416
|
+
tableOptions: 'ٹیبل دے اختیار',
|
|
306
417
|
insertLink: 'لنک پاؤ (Ctrl+K)',
|
|
307
418
|
insertImage: 'تصویر پاؤ',
|
|
419
|
+
insertTable: 'ٹیبل پاؤ',
|
|
420
|
+
insertHorizontalRule: 'لیٹی لکیر پاؤ',
|
|
308
421
|
poetryBlocks: 'شاعری بلاک',
|
|
309
422
|
comingSoon: (label) => `${label} (چھیتی آ رہا اے)`,
|
|
310
423
|
autocorrect: 'خودکار درستی',
|
|
@@ -337,6 +450,52 @@ const paShahmukhi = {
|
|
|
337
450
|
right: 'سجے سیدھ',
|
|
338
451
|
},
|
|
339
452
|
},
|
|
453
|
+
leaveDialog: {
|
|
454
|
+
title: 'غیر محفوظ تبدیلیاں',
|
|
455
|
+
message: 'تہاڈیاں تبدیلیاں سنبھالیاں نئیں گئیاں۔ جان توں پہلاں تسی کی کرنا چاہو گے؟',
|
|
456
|
+
save: 'سنبھالو',
|
|
457
|
+
saveDraft: 'سودھا سنبھالو',
|
|
458
|
+
discard: 'رد کرو',
|
|
459
|
+
saveDraftFailed: 'سودھا سنبھالیا نئیں جا سکیا (دستاویز بہت وڈی ہو سکدی اے، یا براؤزر دی سٹوریج نئیں اے)۔',
|
|
460
|
+
},
|
|
461
|
+
drafts: {
|
|
462
|
+
bannerMessage: (when) => `ایس دستاویز دا اک غیر محفوظ سودھا (${when}) لبھیا اے۔`,
|
|
463
|
+
restore: 'بحال کرو',
|
|
464
|
+
ignore: 'نظر انداز کرو',
|
|
465
|
+
remove: 'سودھا ہٹاؤ',
|
|
466
|
+
dialogTitle: 'سنبھالے ہوئے سودھے',
|
|
467
|
+
intro: 'لکھدیاں ہویاں سودھے ایس براؤزر وچ آپ سنبھلدے نیں تے سنبھالن تے ہٹ جاندے نیں۔',
|
|
468
|
+
empty: 'ہلے کوئی سودھا نئیں۔',
|
|
469
|
+
noText: '(کوئی متن نئیں)',
|
|
470
|
+
thisDocument: 'موجودہ دستاویز',
|
|
471
|
+
untitled: 'بنا ناں دا سودھا',
|
|
472
|
+
documentLabel: (id) => `دستاویز «${id}»`,
|
|
473
|
+
earlierUntitled: 'اک بنا ناں دے سودھے دا پرانا ورژن',
|
|
474
|
+
earlierVersionOf: (id) => `«${id}» دا پرانا ورژن`,
|
|
475
|
+
savedAt: (when) => `سنبھالیا: ${when}`,
|
|
476
|
+
size: (kb) => `${kb} کے بی`,
|
|
477
|
+
replacePrompt: 'موجودہ مواد نوں ایس سودھے نال بدل دیئے؟',
|
|
478
|
+
replace: 'بدل دیو',
|
|
479
|
+
deletePrompt: 'ایہ سودھا مٹا دیئے؟',
|
|
480
|
+
delete: 'مٹاؤ',
|
|
481
|
+
close: 'بند کرو',
|
|
482
|
+
},
|
|
483
|
+
tableMenu: {
|
|
484
|
+
menuLabel: 'ٹیبل',
|
|
485
|
+
insertRowBefore: 'پہلاں قطار پاؤ',
|
|
486
|
+
insertRowAfter: 'بعد وچ قطار پاؤ',
|
|
487
|
+
insertColumnBefore: 'پہلاں کالم پاؤ',
|
|
488
|
+
insertColumnAfter: 'بعد وچ کالم پاؤ',
|
|
489
|
+
deleteRow: 'قطار مٹاؤ',
|
|
490
|
+
deleteColumn: 'کالم مٹاؤ',
|
|
491
|
+
deleteTable: 'ٹیبل مٹاؤ',
|
|
492
|
+
insertRowsBefore: 'پہلاں قطاراں پاؤ',
|
|
493
|
+
insertRowsAfter: 'بعد وچ قطاراں پاؤ',
|
|
494
|
+
insertColumnsBefore: 'پہلاں کالماں پاؤ',
|
|
495
|
+
insertColumnsAfter: 'بعد وچ کالماں پاؤ',
|
|
496
|
+
deleteRows: 'قطاراں مٹاؤ',
|
|
497
|
+
deleteColumns: 'کالماں مٹاؤ',
|
|
498
|
+
},
|
|
340
499
|
link: {
|
|
341
500
|
menuLabel: 'لنک',
|
|
342
501
|
noUrl: '(کوئی یو آر ایل نئیں)',
|
|
@@ -353,6 +512,12 @@ const paShahmukhi = {
|
|
|
353
512
|
invalidUrl: 'کِرپا کر کے صحیح http(s)، mailto، tel یا نسبتی یو آر ایل پاؤ',
|
|
354
513
|
apply: 'لاگو کرو',
|
|
355
514
|
},
|
|
515
|
+
tableDialog: {
|
|
516
|
+
title: 'ٹیبل پاؤ',
|
|
517
|
+
rows: 'قطاراں',
|
|
518
|
+
columns: 'کالم',
|
|
519
|
+
headerRow: 'سرکڑی قطار',
|
|
520
|
+
},
|
|
356
521
|
imageDialog: {
|
|
357
522
|
titleInsert: 'تصویر پاؤ',
|
|
358
523
|
titleEdit: 'تصویر وچ تبدیلی کرو',
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { EditorRoot } from './EditorRoot.js';
|
|
2
|
-
export type { EditorRootProps, EditorRef, EditorInitialContent } from './EditorRoot.js';
|
|
2
|
+
export type { EditorRootProps, EditorRef, EditorInitialContent, NavigationGuardMode } from './EditorRoot.js';
|
|
3
|
+
export type { DraftRestoreMode } from './components/DraftRestore.js';
|
|
3
4
|
export { defaultMantineTheme } from './theme/mantineTheme.js';
|
|
4
5
|
export { ImageNode, $createImageNode, $isImageNode } from './image/ImageNode.js';
|
|
5
6
|
export type { ImagePayload, ImageLinkType, SerializedImageNode } from './image/ImageNode.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAC1G,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9E,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACrF,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AACzF,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC"}
|
package/dist/nodes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../src/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../src/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAQlD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAW5C,CAAC"}
|
package/dist/nodes.js
CHANGED
|
@@ -2,6 +2,7 @@ import { HeadingNode, QuoteNode } from '@lexical/rich-text';
|
|
|
2
2
|
import { ListItemNode, ListNode } from '@lexical/list';
|
|
3
3
|
import { LinkNode } from '@lexical/link';
|
|
4
4
|
import { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';
|
|
5
|
+
import { TableCellNode, TableNode, TableRowNode } from '@lexical/table';
|
|
5
6
|
import { ImageNode } from './image/ImageNode.js';
|
|
6
7
|
/**
|
|
7
8
|
* Node types registered on the editor at construction time. Per
|
|
@@ -19,5 +20,8 @@ export const EDITOR_NODES = [
|
|
|
19
20
|
ListItemNode,
|
|
20
21
|
LinkNode,
|
|
21
22
|
HorizontalRuleNode,
|
|
23
|
+
TableNode,
|
|
24
|
+
TableRowNode,
|
|
25
|
+
TableCellNode,
|
|
22
26
|
ImageNode,
|
|
23
27
|
];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autosave-to-localStorage drafts (lexical-editor-spec.md §6.2). Each draft is
|
|
3
|
+
* keyed by an id: the host's `documentId` when it gives one (§6.1), otherwise
|
|
4
|
+
* a generated unique id, so editors without a `documentId` never overwrite each
|
|
5
|
+
* other's drafts. Every function is a no-op (never throws) when `localStorage`
|
|
6
|
+
* is unavailable (SSR, privacy mode) or a stored value is corrupt — autosave is
|
|
7
|
+
* best-effort, never a hard dependency.
|
|
8
|
+
*/
|
|
9
|
+
export interface StoredDraft {
|
|
10
|
+
/** Lexical JSON (as produced by `EditorState.toJSON()`, stringified). */
|
|
11
|
+
json: string;
|
|
12
|
+
/** `Date.now()` at write time — lets a host distinguish a stale draft from a genuinely recent one. */
|
|
13
|
+
savedAt: number;
|
|
14
|
+
/** Bumped only if the stored shape itself changes; lets old drafts be recognised/discarded across an upgrade. */
|
|
15
|
+
version: 1;
|
|
16
|
+
/** First words of the text, for listing drafts without parsing every document. */
|
|
17
|
+
preview?: string;
|
|
18
|
+
/** Set on a draft archived from `documentId` (the id it was an earlier version of). */
|
|
19
|
+
sourceId?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface DraftEntry {
|
|
22
|
+
id: string;
|
|
23
|
+
draft: StoredDraft;
|
|
24
|
+
}
|
|
25
|
+
export declare function draftKey(id: string): string;
|
|
26
|
+
/** A new unique id for a draft whose editor has no `documentId`. */
|
|
27
|
+
export declare function createDraftId(): string;
|
|
28
|
+
/** Whether an id came from createDraftId() rather than a host's `documentId`. */
|
|
29
|
+
export declare function isGeneratedDraftId(id: string): boolean;
|
|
30
|
+
/** One-line text preview of a Lexical JSON document ('' when it has no text). */
|
|
31
|
+
export declare function extractPreview(json: string): string;
|
|
32
|
+
/** Whether a Lexical JSON document has any text or image (a blank one isn't worth a draft). */
|
|
33
|
+
export declare function hasDraftContent(json: string): boolean;
|
|
34
|
+
export declare function readDraft(id: string): StoredDraft | null;
|
|
35
|
+
/**
|
|
36
|
+
* Best-effort write; returns whether the draft was actually stored (callers that
|
|
37
|
+
* promise the user a saved draft must check). Skips (rather than throwing) when `json` exceeds
|
|
38
|
+
* `maxBytes` — localStorage has a shared ~5-10MB per-origin ceiling (§6.2), so a
|
|
39
|
+
* single large document (e.g. embedded base64 images) must not be allowed to
|
|
40
|
+
* autosave past a caller-configured limit — or when the write itself fails
|
|
41
|
+
* (quota exceeded, privacy mode).
|
|
42
|
+
*/
|
|
43
|
+
export declare function writeDraft(id: string, json: string, maxBytes: number, sourceId?: string): boolean;
|
|
44
|
+
export declare function clearDraft(id: string): void;
|
|
45
|
+
/** Every stored draft, newest first. */
|
|
46
|
+
export declare function listDrafts(): DraftEntry[];
|
|
47
|
+
/**
|
|
48
|
+
* Keeps a draft that is about to be overwritten or ignored: copies it to a new
|
|
49
|
+
* generated id (remembering `sourceId`) so it stays in the drafts list.
|
|
50
|
+
* Returns the new id, or null if nothing could be copied.
|
|
51
|
+
*/
|
|
52
|
+
export declare function archiveDraft(id: string): string | null;
|
|
53
|
+
/** Deletes the oldest drafts beyond `max`, never touching `keepIds`. */
|
|
54
|
+
export declare function pruneDrafts(max: number, keepIds?: string[]): void;
|
|
55
|
+
//# sourceMappingURL=draftStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draftStorage.d.ts","sourceRoot":"","sources":["../../src/persistence/draftStorage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,sGAAsG;IACtG,OAAO,EAAE,MAAM,CAAC;IAChB,iHAAiH;IACjH,OAAO,EAAE,CAAC,CAAC;IACX,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,oEAAoE;AACpE,wBAAgB,aAAa,IAAI,MAAM,CAOtC;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEtD;AAgDD,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,+FAA+F;AAC/F,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAaD,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAQxD;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAgBjG;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAQ3C;AAED,wCAAwC;AACxC,wBAAgB,UAAU,IAAI,UAAU,EAAE,CAezC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWtD;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,IAAI,CAQrE"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autosave-to-localStorage drafts (lexical-editor-spec.md §6.2). Each draft is
|
|
3
|
+
* keyed by an id: the host's `documentId` when it gives one (§6.1), otherwise
|
|
4
|
+
* a generated unique id, so editors without a `documentId` never overwrite each
|
|
5
|
+
* other's drafts. Every function is a no-op (never throws) when `localStorage`
|
|
6
|
+
* is unavailable (SSR, privacy mode) or a stored value is corrupt — autosave is
|
|
7
|
+
* best-effort, never a hard dependency.
|
|
8
|
+
*/
|
|
9
|
+
const KEY_PREFIX = 'likhari:draft:';
|
|
10
|
+
const PREVIEW_LENGTH = 140;
|
|
11
|
+
export function draftKey(id) {
|
|
12
|
+
return `${KEY_PREFIX}${id}`;
|
|
13
|
+
}
|
|
14
|
+
/** A new unique id for a draft whose editor has no `documentId`. */
|
|
15
|
+
export function createDraftId() {
|
|
16
|
+
try {
|
|
17
|
+
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')
|
|
18
|
+
return crypto.randomUUID();
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// fall through to the non-crypto id
|
|
22
|
+
}
|
|
23
|
+
return `draft-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
24
|
+
}
|
|
25
|
+
/** Whether an id came from createDraftId() rather than a host's `documentId`. */
|
|
26
|
+
export function isGeneratedDraftId(id) {
|
|
27
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id) || /^draft-[0-9a-z]+-[0-9a-z]+$/.test(id);
|
|
28
|
+
}
|
|
29
|
+
function getLocalStorage() {
|
|
30
|
+
try {
|
|
31
|
+
return typeof localStorage === 'undefined' ? null : localStorage;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Some browsers throw on accessing localStorage in certain privacy modes.
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function collectText(node, parts, state) {
|
|
39
|
+
if (node.type === 'text' && typeof node.text === 'string') {
|
|
40
|
+
if (node.text.trim())
|
|
41
|
+
state.hasContent = true;
|
|
42
|
+
parts.push(node.text);
|
|
43
|
+
}
|
|
44
|
+
else if (node.type === 'linebreak') {
|
|
45
|
+
parts.push(' ');
|
|
46
|
+
}
|
|
47
|
+
else if (node.type === 'image') {
|
|
48
|
+
state.hasContent = true;
|
|
49
|
+
if (node.altText)
|
|
50
|
+
parts.push(`[${node.altText}]`);
|
|
51
|
+
}
|
|
52
|
+
for (const child of node.children ?? [])
|
|
53
|
+
collectText(child, parts, state);
|
|
54
|
+
// Block boundaries read as a space in a one-line preview.
|
|
55
|
+
if (node.children && node.type !== 'root')
|
|
56
|
+
parts.push(' ');
|
|
57
|
+
}
|
|
58
|
+
function summarize(json) {
|
|
59
|
+
try {
|
|
60
|
+
const root = JSON.parse(json).root;
|
|
61
|
+
if (!root)
|
|
62
|
+
return { preview: '', hasContent: false };
|
|
63
|
+
const parts = [];
|
|
64
|
+
const state = { hasContent: false };
|
|
65
|
+
collectText(root, parts, state);
|
|
66
|
+
const text = parts.join('').replace(/\s+/g, ' ').trim();
|
|
67
|
+
const preview = text.length > PREVIEW_LENGTH ? `${text.slice(0, PREVIEW_LENGTH).trimEnd()}…` : text;
|
|
68
|
+
return { preview, hasContent: state.hasContent };
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return { preview: '', hasContent: false };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** One-line text preview of a Lexical JSON document ('' when it has no text). */
|
|
75
|
+
export function extractPreview(json) {
|
|
76
|
+
return summarize(json).preview;
|
|
77
|
+
}
|
|
78
|
+
/** Whether a Lexical JSON document has any text or image (a blank one isn't worth a draft). */
|
|
79
|
+
export function hasDraftContent(json) {
|
|
80
|
+
return summarize(json).hasContent;
|
|
81
|
+
}
|
|
82
|
+
function parseDraft(raw) {
|
|
83
|
+
if (!raw)
|
|
84
|
+
return null;
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(raw);
|
|
87
|
+
if (typeof parsed.json !== 'string' || typeof parsed.savedAt !== 'number' || parsed.version !== 1)
|
|
88
|
+
return null;
|
|
89
|
+
return parsed;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export function readDraft(id) {
|
|
96
|
+
const storage = getLocalStorage();
|
|
97
|
+
if (!storage)
|
|
98
|
+
return null;
|
|
99
|
+
try {
|
|
100
|
+
return parseDraft(storage.getItem(draftKey(id)));
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Best-effort write; returns whether the draft was actually stored (callers that
|
|
108
|
+
* promise the user a saved draft must check). Skips (rather than throwing) when `json` exceeds
|
|
109
|
+
* `maxBytes` — localStorage has a shared ~5-10MB per-origin ceiling (§6.2), so a
|
|
110
|
+
* single large document (e.g. embedded base64 images) must not be allowed to
|
|
111
|
+
* autosave past a caller-configured limit — or when the write itself fails
|
|
112
|
+
* (quota exceeded, privacy mode).
|
|
113
|
+
*/
|
|
114
|
+
export function writeDraft(id, json, maxBytes, sourceId) {
|
|
115
|
+
const storage = getLocalStorage();
|
|
116
|
+
if (!storage)
|
|
117
|
+
return false;
|
|
118
|
+
// .length (UTF-16 code units) over-estimates UTF-8 byte size for any
|
|
119
|
+
// non-Latin text, which only makes this check more conservative — fine
|
|
120
|
+
// for a soft cap that doesn't need to be exact.
|
|
121
|
+
if (json.length > maxBytes)
|
|
122
|
+
return false;
|
|
123
|
+
const draft = { json, savedAt: Date.now(), version: 1, preview: extractPreview(json) };
|
|
124
|
+
if (sourceId)
|
|
125
|
+
draft.sourceId = sourceId;
|
|
126
|
+
try {
|
|
127
|
+
storage.setItem(draftKey(id), JSON.stringify(draft));
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Quota exceeded or similar — autosave is best-effort.
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export function clearDraft(id) {
|
|
136
|
+
const storage = getLocalStorage();
|
|
137
|
+
if (!storage)
|
|
138
|
+
return;
|
|
139
|
+
try {
|
|
140
|
+
storage.removeItem(draftKey(id));
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// ignore
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** Every stored draft, newest first. */
|
|
147
|
+
export function listDrafts() {
|
|
148
|
+
const storage = getLocalStorage();
|
|
149
|
+
if (!storage)
|
|
150
|
+
return [];
|
|
151
|
+
const entries = [];
|
|
152
|
+
try {
|
|
153
|
+
for (let i = 0; i < storage.length; i++) {
|
|
154
|
+
const key = storage.key(i);
|
|
155
|
+
if (!key || !key.startsWith(KEY_PREFIX))
|
|
156
|
+
continue;
|
|
157
|
+
const draft = parseDraft(storage.getItem(key));
|
|
158
|
+
if (draft)
|
|
159
|
+
entries.push({ id: key.slice(KEY_PREFIX.length), draft });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return entries;
|
|
164
|
+
}
|
|
165
|
+
return entries.sort((a, b) => b.draft.savedAt - a.draft.savedAt);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Keeps a draft that is about to be overwritten or ignored: copies it to a new
|
|
169
|
+
* generated id (remembering `sourceId`) so it stays in the drafts list.
|
|
170
|
+
* Returns the new id, or null if nothing could be copied.
|
|
171
|
+
*/
|
|
172
|
+
export function archiveDraft(id) {
|
|
173
|
+
const storage = getLocalStorage();
|
|
174
|
+
const draft = readDraft(id);
|
|
175
|
+
if (!storage || !draft)
|
|
176
|
+
return null;
|
|
177
|
+
const archivedId = createDraftId();
|
|
178
|
+
try {
|
|
179
|
+
storage.setItem(draftKey(archivedId), JSON.stringify({ ...draft, sourceId: draft.sourceId ?? id }));
|
|
180
|
+
return archivedId;
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/** Deletes the oldest drafts beyond `max`, never touching `keepIds`. */
|
|
187
|
+
export function pruneDrafts(max, keepIds = []) {
|
|
188
|
+
if (max < 1)
|
|
189
|
+
return;
|
|
190
|
+
const removable = listDrafts().filter((entry) => !keepIds.includes(entry.id));
|
|
191
|
+
const kept = listDrafts().length - removable.length;
|
|
192
|
+
const excess = removable.length + kept - max;
|
|
193
|
+
if (excess <= 0)
|
|
194
|
+
return;
|
|
195
|
+
// removable is newest first, so the oldest are at the end.
|
|
196
|
+
for (const entry of removable.slice(-excess))
|
|
197
|
+
clearDraft(entry.id);
|
|
198
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LexicalEditor } from 'lexical';
|
|
2
|
+
import type { Locale } from '../i18n/index.js';
|
|
3
|
+
/** Replaces the editor's content with a stored draft's Lexical JSON. Returns
|
|
4
|
+
* false (leaving the editor untouched) if the draft is corrupt or from an
|
|
5
|
+
* incompatible node schema, rather than throwing. */
|
|
6
|
+
export declare function applyDraftToEditor(editor: LexicalEditor, json: string): boolean;
|
|
7
|
+
/** A draft's save time as a short localized date and time. */
|
|
8
|
+
export declare function formatDraftTime(savedAt: number, locale: Locale): string;
|
|
9
|
+
//# sourceMappingURL=draftUi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draftUi.d.ts","sourceRoot":"","sources":["../../src/persistence/draftUi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC;;qDAEqD;AACrD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAO/E;AAID,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOvE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Replaces the editor's content with a stored draft's Lexical JSON. Returns
|
|
2
|
+
* false (leaving the editor untouched) if the draft is corrupt or from an
|
|
3
|
+
* incompatible node schema, rather than throwing. */
|
|
4
|
+
export function applyDraftToEditor(editor, json) {
|
|
5
|
+
try {
|
|
6
|
+
editor.setEditorState(editor.parseEditorState(json));
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const INTL_LOCALES = { en: 'en', ur: 'ur', 'pa-shahmukhi': 'pa-Arab' };
|
|
14
|
+
/** A draft's save time as a short localized date and time. */
|
|
15
|
+
export function formatDraftTime(savedAt, locale) {
|
|
16
|
+
const date = new Date(savedAt);
|
|
17
|
+
try {
|
|
18
|
+
return new Intl.DateTimeFormat(INTL_LOCALES[locale], { dateStyle: 'medium', timeStyle: 'short' }).format(date);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return date.toLocaleString();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** How many rows and columns the selection spans (1 × 1 for a caret in a cell, 0 × 0 outside a table). */
|
|
2
|
+
export declare function $getTableSelectionSize(): {
|
|
3
|
+
rows: number;
|
|
4
|
+
columns: number;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Inserts as many rows as the selection spans, before its first row or after
|
|
8
|
+
* its last. Lexical's own insert works from the selection's focus cell and adds
|
|
9
|
+
* one row, so with several rows selected it would land mid-selection.
|
|
10
|
+
*/
|
|
11
|
+
export declare function $insertTableRows(insertAfter: boolean): void;
|
|
12
|
+
/** Like $insertTableRows, for columns. "Before" is the column index below the
|
|
13
|
+
* first selected one (the right-hand side in a right-to-left table). */
|
|
14
|
+
export declare function $insertTableColumns(insertAfter: boolean): void;
|
|
15
|
+
/** Deletes every row the selection touches (Lexical handles a multi-cell selection). */
|
|
16
|
+
export declare function $deleteTableRows(): void;
|
|
17
|
+
/** Deletes every column the selection touches. */
|
|
18
|
+
export declare function $deleteTableColumns(): void;
|
|
19
|
+
/** Removes the whole table the selection is in. */
|
|
20
|
+
export declare function $deleteTable(): void;
|
|
21
|
+
//# sourceMappingURL=tableActions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tableActions.d.ts","sourceRoot":"","sources":["../../src/table/tableActions.ts"],"names":[],"mappings":"AA2BA,0GAA0G;AAC1G,wBAAgB,sBAAsB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAS1E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAS3D;AAED;wEACwE;AACxE,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAQ9D;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED,kDAAkD;AAClD,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,mDAAmD;AACnD,wBAAgB,YAAY,IAAI,IAAI,CAInC"}
|