@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.
Files changed (38) hide show
  1. package/dist/EditorRoot.d.ts +60 -0
  2. package/dist/EditorRoot.d.ts.map +1 -1
  3. package/dist/EditorRoot.js +183 -10
  4. package/dist/components/DraftRestore.d.ts +24 -0
  5. package/dist/components/DraftRestore.d.ts.map +1 -0
  6. package/dist/components/DraftRestore.js +61 -0
  7. package/dist/components/DraftsDialog.d.ts +25 -0
  8. package/dist/components/DraftsDialog.d.ts.map +1 -0
  9. package/dist/components/DraftsDialog.js +66 -0
  10. package/dist/components/LeaveDialog.d.ts +22 -0
  11. package/dist/components/LeaveDialog.d.ts.map +1 -0
  12. package/dist/components/LeaveDialog.js +15 -0
  13. package/dist/components/TableDialog.d.ts +17 -0
  14. package/dist/components/TableDialog.d.ts.map +1 -0
  15. package/dist/components/TableDialog.js +33 -0
  16. package/dist/components/Toolbar.d.ts +4 -1
  17. package/dist/components/Toolbar.d.ts.map +1 -1
  18. package/dist/components/Toolbar.js +110 -6
  19. package/dist/i18n/strings.d.ts +65 -2
  20. package/dist/i18n/strings.d.ts.map +1 -1
  21. package/dist/i18n/strings.js +168 -3
  22. package/dist/index.d.ts +2 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/nodes.d.ts.map +1 -1
  25. package/dist/nodes.js +4 -0
  26. package/dist/persistence/draftStorage.d.ts +55 -0
  27. package/dist/persistence/draftStorage.d.ts.map +1 -0
  28. package/dist/persistence/draftStorage.js +198 -0
  29. package/dist/persistence/draftUi.d.ts +9 -0
  30. package/dist/persistence/draftUi.d.ts.map +1 -0
  31. package/dist/persistence/draftUi.js +23 -0
  32. package/dist/table/tableActions.d.ts +21 -0
  33. package/dist/table/tableActions.d.ts.map +1 -0
  34. package/dist/table/tableActions.js +71 -0
  35. package/dist/theme/editor.css +111 -0
  36. package/dist/theme/editorTheme.d.ts.map +1 -1
  37. package/dist/theme/editorTheme.js +5 -0
  38. package/package.json +2 -1
@@ -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';
@@ -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;AACrF,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"}
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"}
@@ -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;AAOlD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAQ5C,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"}