@inshapardaz/likhari-react 0.1.7-dev.81 → 0.1.7-dev.86

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 +57 -0
  2. package/dist/EditorRoot.d.ts.map +1 -1
  3. package/dist/EditorRoot.js +174 -11
  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/Toolbar.d.ts +4 -1
  14. package/dist/components/Toolbar.d.ts.map +1 -1
  15. package/dist/components/Toolbar.js +8 -6
  16. package/dist/i18n/strings.d.ts +38 -5
  17. package/dist/i18n/strings.d.ts.map +1 -1
  18. package/dist/i18n/strings.js +96 -9
  19. package/dist/index.d.ts +2 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/nodes.d.ts.map +1 -1
  22. package/dist/nodes.js +0 -2
  23. package/dist/persistence/draftStorage.d.ts +55 -0
  24. package/dist/persistence/draftStorage.d.ts.map +1 -0
  25. package/dist/persistence/draftStorage.js +198 -0
  26. package/dist/persistence/draftUi.d.ts +9 -0
  27. package/dist/persistence/draftUi.d.ts.map +1 -0
  28. package/dist/persistence/draftUi.js +23 -0
  29. package/dist/theme/editor.css +74 -39
  30. package/dist/theme/editorTheme.d.ts.map +1 -1
  31. package/dist/theme/editorTheme.js +0 -1
  32. package/package.json +1 -1
  33. package/dist/blocks/PageBreakNode.d.ts +0 -30
  34. package/dist/blocks/PageBreakNode.d.ts.map +0 -1
  35. package/dist/blocks/PageBreakNode.js +0 -110
  36. package/dist/plugins/PageBreakPlugin.d.ts +0 -3
  37. package/dist/plugins/PageBreakPlugin.d.ts.map +0 -1
  38. package/dist/plugins/PageBreakPlugin.js +0 -19
@@ -10,15 +10,15 @@ import { $isListNode, INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, IN
10
10
  import { $findMatchingParent, $insertNodeToNearestRoot } from '@lexical/utils';
11
11
  import { ImageDialog } from '../image/ImageDialog.js';
12
12
  import { $createImageNode } from '../image/ImageNode.js';
13
- import { INSERT_PAGE_BREAK_COMMAND } from '../blocks/PageBreakNode.js';
14
13
  import { $createLinkNode, $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
15
14
  import { LinkDialog } from './LinkDialog.js';
15
+ import { DraftsDialog } from './DraftsDialog.js';
16
16
  import { normalizeLinkUrl } from '../utils/linkUrl.js';
17
17
  import { CANVAS_FONT_DEFAULTS, DEFAULT_FONT_OPTIONS, FONT_SIZES_PX } from '../fonts/index.js';
18
18
  import { setStyleProperty } from '../utils/style.js';
19
19
  import { useStrings } from '../i18n/useStrings.js';
20
20
  import { usePortalTarget } from '../PortalTargetContext.js';
21
- import { IconAbc, IconAlignCenter, IconAlignJustified, IconAlignLeft, IconAlignRight, IconArrowBackUp, IconArrowForwardUp, IconBold, IconClearFormatting, IconDeviceFloppy, IconDots, IconExternalLink, IconFeather, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconIndentDecrease, IconIndentIncrease, IconItalic, IconLetterCase, IconLetterCaseLower, IconLetterCaseUpper, IconLink, IconLinkOff, IconList, IconListCheck, IconListNumbers, IconPageBreak, IconPencil, IconPhoto, IconPilcrow, IconQuote, IconSparkles, IconStrikethrough, IconSubscript, IconSuperscript, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
21
+ import { IconAbc, IconAlignCenter, IconAlignJustified, IconAlignLeft, IconAlignRight, IconArrowBackUp, IconArrowForwardUp, IconBold, IconClearFormatting, IconDeviceFloppy, IconDots, IconHistory, IconExternalLink, IconFeather, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconIndentDecrease, IconIndentIncrease, IconItalic, IconLetterCase, IconLetterCaseLower, IconLetterCaseUpper, IconLink, IconLinkOff, IconList, IconListCheck, IconListNumbers, IconPencil, IconPhoto, IconPilcrow, IconQuote, IconSparkles, IconStrikethrough, IconSubscript, IconSuperscript, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
22
22
  /** Sentinel for "no inline style": Lexical returns the default it is given when
23
23
  * the selection has none, so this tells "unstyled" (show the canvas default)
24
24
  * apart from "styled with a value the dropdown doesn't list" (show nothing). */
@@ -120,11 +120,12 @@ function LinkMenuItems({ url, onEdit, onRemove, strings }) {
120
120
  // Not a URL the editor would accept (e.g. loaded from a document): show it, don't make it clickable.
121
121
  _jsx(Menu.Item, { disabled: true, title: url, className: "likhari-link-menu-url", children: url || strings.link.noUrl })), _jsx(Menu.Item, { leftSection: _jsx(IconPencil, { size: ICON_SIZE, stroke: ICON_STROKE }), onMouseDown: (e) => e.preventDefault(), onClick: onEdit, children: strings.link.editLink }), _jsx(Menu.Item, { color: "red", leftSection: _jsx(IconLinkOff, { size: ICON_SIZE, stroke: ICON_STROKE }), onMouseDown: (e) => e.preventDefault(), onClick: onRemove, children: strings.link.removeLink })] }));
122
122
  }
123
- export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en' }) {
123
+ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
124
124
  const [editor] = useLexicalComposerContext();
125
125
  const [state, setState] = useState(INITIAL_STATE);
126
126
  const strings = useStrings(locale);
127
127
  const portalTarget = usePortalTarget();
128
+ const [draftsOpen, setDraftsOpen] = useState(false);
128
129
  // Responsive "priority+" overflow: the toolbar's outer container and a
129
130
  // hidden nowrap clone (rendered with every movable group forced inline)
130
131
  // are both measured; whenever the clone's natural width exceeds the
@@ -427,7 +428,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
427
428
  const showFormattingGroup = headingLevels.length > 0 || config.lists.bullet || config.lists.numbered || config.lists.check || config.blocks.quote;
428
429
  const showInlineGroup = fmt.bold || fmt.italic || fmt.underline;
429
430
  const showAlignGroup = config.alignment.start || config.alignment.center || config.alignment.justify || config.alignment.left || config.alignment.right;
430
- const showStubInsertGroup = config.images.linked || config.images.embedded || config.blocks.pageBreak || config.poetry.enabled;
431
+ const showStubInsertGroup = config.images.linked || config.images.embedded || config.poetry.enabled;
431
432
  const showLanguageGroup = config.language.autocorrect || config.language.textCleanup || config.language.spellCheck;
432
433
  // The "script & cleanup" and "indent/outdent" groups (UI spec §3.3) render
433
434
  // as normal inline toolbar groups whenever there's room, and only move
@@ -585,6 +586,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
585
586
  // the toolbar's own layout width.
586
587
  const fixedGroups = [
587
588
  showSave && (_jsx("div", { className: "likhari-toolbar-group", children: _jsx(ToolbarButton, { icon: IconDeviceFloppy, title: strings.toolbar.save, dirty: Boolean(isDirty), onClick: onSave }) }, "save")),
589
+ drafts && (_jsx("div", { className: "likhari-toolbar-group", children: _jsx(ToolbarButton, { icon: IconHistory, title: strings.toolbar.drafts, onClick: () => setDraftsOpen(true) }) }, "drafts")),
588
590
  config.history && (_jsxs("div", { className: "likhari-toolbar-group", children: [_jsx(ToolbarButton, { icon: IconArrowBackUp, title: strings.toolbar.undo, disabled: !state.canUndo, onClick: () => editor.dispatchCommand(UNDO_COMMAND, undefined) }), _jsx(ToolbarButton, { icon: IconArrowForwardUp, title: strings.toolbar.redo, disabled: !state.canRedo, onClick: () => editor.dispatchCommand(REDO_COMMAND, undefined) })] }, "history")),
589
591
  showFormattingGroup && (_jsx("div", { className: "likhari-toolbar-group", children: _jsx(ToolbarSelect, { icon: IconPilcrow, label: strings.toolbar.formattingLabel, width: 148, value: formattingValue, data: formattingOptions, comingSoon: strings.toolbar.comingSoon, renderOption: iconOptionRenderer(FORMATTING_ICONS, IconPilcrow), onChange: withRefocus((v) => applyFormatting(v)) }) }, "formatting")),
590
592
  showInlineGroup && (_jsxs("div", { className: "likhari-toolbar-group", children: [fmt.bold && (_jsx(ToolbarButton, { icon: IconBold, title: strings.toolbar.bold, active: state.activeFormats.has('bold'), onClick: () => formatText('bold') })), fmt.italic && (_jsx(ToolbarButton, { icon: IconItalic, title: strings.toolbar.italic, active: state.activeFormats.has('italic'), onClick: () => formatText('italic') })), fmt.underline && (_jsx(ToolbarButton, { icon: IconUnderline, title: strings.toolbar.underline, active: state.activeFormats.has('underline'), onClick: () => formatText('underline') }))] }, "inline")),
@@ -596,7 +598,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
596
598
  restoreSelection();
597
599
  openLinkDialog();
598
600
  }, onRemove: removeLink, strings: strings }) })] })) : (_jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.insertLink, onClick: openLinkDialog })) }, "link")),
599
- showStubInsertGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [(config.images.linked || config.images.embedded) && (_jsx(ToolbarButton, { icon: IconPhoto, title: strings.toolbar.insertImage, onClick: openImageDialog })), config.blocks.pageBreak && (_jsx(ToolbarButton, { icon: IconPageBreak, title: strings.toolbar.insertPageBreak, onClick: () => editor.dispatchCommand(INSERT_PAGE_BREAK_COMMAND, undefined) })), config.poetry.enabled && _jsx(StubButton, { icon: IconFeather, title: strings.toolbar.poetryBlocks, comingSoon: strings.toolbar.comingSoon })] }, "stubInsert")),
601
+ showStubInsertGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [(config.images.linked || config.images.embedded) && (_jsx(ToolbarButton, { icon: IconPhoto, title: strings.toolbar.insertImage, onClick: openImageDialog })), config.poetry.enabled && _jsx(StubButton, { icon: IconFeather, title: strings.toolbar.poetryBlocks, comingSoon: strings.toolbar.comingSoon })] }, "stubInsert")),
600
602
  showLanguageGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [config.language.autocorrect && _jsx(StubButton, { icon: IconWand, title: strings.toolbar.autocorrect, comingSoon: strings.toolbar.comingSoon }), config.language.textCleanup && _jsx(StubButton, { icon: IconSparkles, title: strings.toolbar.textCleanup, comingSoon: strings.toolbar.comingSoon }), config.language.spellCheck && _jsx(StubButton, { icon: IconAbc, title: strings.toolbar.spellChecker, comingSoon: strings.toolbar.comingSoon })] }, "language")),
601
603
  ];
602
604
  return (_jsxs("div", { className: "likhari-toolbar", role: "toolbar", "aria-label": strings.toolbar.ariaLabel, ref: toolbarContainerRef, children: [fixedGroups, movableGroups
@@ -618,5 +620,5 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
618
620
  display: 'flex',
619
621
  flexWrap: 'nowrap',
620
622
  gap: 8,
621
- }, children: [fixedGroups, movableGroups.map((group) => (_jsx(MovableGroupButtons, { group: group }, group.key)))] }), (config.images.linked || config.images.embedded) && (_jsx(ImageDialog, { mode: "insert", opened: imageDialogOpen, onSubmit: insertImage, onClose: closeImageDialog })), config.links && (_jsx(LinkDialog, { opened: linkDialogOpen, initialUrl: state.linkUrl, showTextField: linkNeedsText, onSubmit: applyLink, onRemove: state.isLink ? removeLink : undefined, onClose: closeLinkDialog }))] }));
623
+ }, children: [fixedGroups, movableGroups.map((group) => (_jsx(MovableGroupButtons, { group: group }, group.key)))] }), (config.images.linked || config.images.embedded) && (_jsx(ImageDialog, { mode: "insert", opened: imageDialogOpen, onSubmit: insertImage, onClose: closeImageDialog })), config.links && (_jsx(LinkDialog, { opened: linkDialogOpen, initialUrl: state.linkUrl, showTextField: linkNeedsText, onSubmit: applyLink, onRemove: state.isLink ? removeLink : undefined, onClose: closeLinkDialog })), drafts && _jsx(DraftsDialog, { opened: draftsOpen, locale: locale, onClose: () => setDraftsOpen(false), ...drafts })] }));
622
624
  }
@@ -13,10 +13,6 @@ export interface Strings {
13
13
  placeholder: string;
14
14
  /** aria-label on the contenteditable itself. */
15
15
  contentLabel: string;
16
- /** window.confirm() prompt shown by EditorRef.confirmDiscard() when there are unsaved changes. */
17
- confirmDiscard: string;
18
- /** Label shown on a page-break marker's dashed line while editing. */
19
- pageBreakLabel: string;
20
16
  };
21
17
  common: {
22
18
  cancel: string;
@@ -27,6 +23,8 @@ export interface Strings {
27
23
  /** aria-label on the toolbar's own role="toolbar" container. */
28
24
  ariaLabel: string;
29
25
  save: string;
26
+ /** Opens the list of autosaved drafts. */
27
+ drafts: string;
30
28
  undo: string;
31
29
  redo: string;
32
30
  formattingLabel: string;
@@ -42,7 +40,6 @@ export interface Strings {
42
40
  linkOptions: string;
43
41
  insertLink: string;
44
42
  insertImage: string;
45
- insertPageBreak: string;
46
43
  poetryBlocks: string;
47
44
  comingSoon: (label: string) => string;
48
45
  autocorrect: string;
@@ -75,6 +72,42 @@ export interface Strings {
75
72
  right: string;
76
73
  };
77
74
  };
75
+ /** The popup `EditorRef.confirmDiscard()` shows when the user is about to leave with unsaved changes (lexical-editor-spec.md §6.4). */
76
+ leaveDialog: {
77
+ title: string;
78
+ message: string;
79
+ save: string;
80
+ saveDraft: string;
81
+ discard: string;
82
+ stay: string;
83
+ /** Shown when a draft could not be stored (document too large, or storage unavailable). */
84
+ saveDraftFailed: string;
85
+ };
86
+ /** Autosave drafts (lexical-editor-spec.md §6.2): the restore banner and the drafts list dialog. */
87
+ drafts: {
88
+ /** Banner shown when a newer unsaved draft of this document is found; `when` is a formatted date/time. */
89
+ bannerMessage: (when: string) => string;
90
+ restore: string;
91
+ ignore: string;
92
+ remove: string;
93
+ dialogTitle: string;
94
+ intro: string;
95
+ empty: string;
96
+ /** Shown for a draft with no text (e.g. only an image). */
97
+ noText: string;
98
+ thisDocument: string;
99
+ untitled: string;
100
+ documentLabel: (id: string) => string;
101
+ earlierUntitled: string;
102
+ earlierVersionOf: (id: string) => string;
103
+ savedAt: (when: string) => string;
104
+ size: (kb: number) => string;
105
+ replacePrompt: string;
106
+ replace: string;
107
+ deletePrompt: string;
108
+ delete: string;
109
+ close: string;
110
+ };
78
111
  link: {
79
112
  menuLabel: string;
80
113
  noUrl: string;
@@ -1 +1 @@
1
- {"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"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"}
@@ -8,8 +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
- pageBreakLabel: 'Page break',
13
11
  },
14
12
  common: {
15
13
  cancel: 'Cancel',
@@ -19,6 +17,7 @@ const en = {
19
17
  toolbar: {
20
18
  ariaLabel: 'Formatting',
21
19
  save: 'Save',
20
+ drafts: 'Drafts',
22
21
  undo: 'Undo',
23
22
  redo: 'Redo',
24
23
  formattingLabel: 'Formatting',
@@ -34,7 +33,6 @@ const en = {
34
33
  linkOptions: 'Link options',
35
34
  insertLink: 'Insert link (Ctrl+K)',
36
35
  insertImage: 'Insert image',
37
- insertPageBreak: 'Insert page break',
38
36
  poetryBlocks: 'Poetry blocks',
39
37
  comingSoon: (label) => `${label} (coming soon)`,
40
38
  autocorrect: 'Auto-correct',
@@ -67,6 +65,37 @@ const en = {
67
65
  right: 'Align right',
68
66
  },
69
67
  },
68
+ leaveDialog: {
69
+ title: 'Unsaved changes',
70
+ message: 'You have unsaved changes. What would you like to do before leaving?',
71
+ save: 'Save',
72
+ saveDraft: 'Save draft',
73
+ discard: 'Discard changes',
74
+ stay: 'Stay',
75
+ saveDraftFailed: "The draft couldn't be saved (the document may be too large, or browser storage is unavailable).",
76
+ },
77
+ drafts: {
78
+ bannerMessage: (when) => `An unsaved draft of this document from ${when} was found.`,
79
+ restore: 'Restore',
80
+ ignore: 'Ignore',
81
+ remove: 'Remove draft',
82
+ dialogTitle: 'Saved drafts',
83
+ intro: 'Drafts are saved in this browser as you type, and removed when you save.',
84
+ empty: 'No drafts yet.',
85
+ noText: '(no text)',
86
+ thisDocument: 'Current document',
87
+ untitled: 'Untitled draft',
88
+ documentLabel: (id) => `Document “${id}”`,
89
+ earlierUntitled: 'Earlier version of an untitled draft',
90
+ earlierVersionOf: (id) => `Earlier version of “${id}”`,
91
+ savedAt: (when) => `Saved ${when}`,
92
+ size: (kb) => `${kb} KB`,
93
+ replacePrompt: 'Replace the current content with this draft?',
94
+ replace: 'Replace',
95
+ deletePrompt: 'Delete this draft?',
96
+ delete: 'Delete',
97
+ close: 'Close',
98
+ },
70
99
  link: {
71
100
  menuLabel: 'Link',
72
101
  noUrl: '(no URL)',
@@ -146,8 +175,6 @@ const ur = {
146
175
  editor: {
147
176
  placeholder: 'لکھنا شروع کریں…',
148
177
  contentLabel: 'ایڈیٹر کا مواد',
149
- confirmDiscard: 'آپ کی غیر محفوظ شدہ تبدیلیاں ہیں۔ کیا انہیں رد کر دیا جائے؟',
150
- pageBreakLabel: 'صفحے کی تقسیم',
151
178
  },
152
179
  common: {
153
180
  cancel: 'منسوخ کریں',
@@ -157,6 +184,7 @@ const ur = {
157
184
  toolbar: {
158
185
  ariaLabel: 'فارمیٹنگ',
159
186
  save: 'محفوظ کریں',
187
+ drafts: 'مسودے',
160
188
  undo: 'کالعدم کریں',
161
189
  redo: 'دوبارہ کریں',
162
190
  formattingLabel: 'فارمیٹنگ',
@@ -172,7 +200,6 @@ const ur = {
172
200
  linkOptions: 'لنک کے اختیارات',
173
201
  insertLink: 'لنک شامل کریں (Ctrl+K)',
174
202
  insertImage: 'تصویر شامل کریں',
175
- insertPageBreak: 'صفحے کی تقسیم شامل کریں',
176
203
  poetryBlocks: 'شاعری کے بلاکس',
177
204
  comingSoon: (label) => `${label} (جلد آ رہا ہے)`,
178
205
  autocorrect: 'خودکار تصحیح',
@@ -205,6 +232,37 @@ const ur = {
205
232
  right: 'دائیں سیدھ',
206
233
  },
207
234
  },
235
+ leaveDialog: {
236
+ title: 'غیر محفوظ شدہ تبدیلیاں',
237
+ message: 'آپ کی تبدیلیاں محفوظ نہیں ہوئیں۔ جانے سے پہلے آپ کیا کرنا چاہیں گے؟',
238
+ save: 'محفوظ کریں',
239
+ saveDraft: 'مسودہ محفوظ کریں',
240
+ discard: 'تبدیلیاں رد کریں',
241
+ stay: 'یہیں رہیں',
242
+ saveDraftFailed: 'مسودہ محفوظ نہیں ہو سکا (دستاویز بہت بڑی ہو سکتی ہے، یا براؤزر کا اسٹوریج دستیاب نہیں)۔',
243
+ },
244
+ drafts: {
245
+ bannerMessage: (when) => `اس دستاویز کا ایک غیر محفوظ شدہ مسودہ (${when}) ملا ہے۔`,
246
+ restore: 'بحال کریں',
247
+ ignore: 'نظر انداز کریں',
248
+ remove: 'مسودہ ہٹائیں',
249
+ dialogTitle: 'محفوظ شدہ مسودے',
250
+ intro: 'لکھتے وقت مسودے اس براؤزر میں خود بخود محفوظ ہوتے ہیں اور محفوظ کرنے پر ہٹا دیے جاتے ہیں۔',
251
+ empty: 'ابھی کوئی مسودہ نہیں۔',
252
+ noText: '(کوئی متن نہیں)',
253
+ thisDocument: 'موجودہ دستاویز',
254
+ untitled: 'بلا عنوان مسودہ',
255
+ documentLabel: (id) => `دستاویز «${id}»`,
256
+ earlierUntitled: 'ایک بلا عنوان مسودے کا پرانا ورژن',
257
+ earlierVersionOf: (id) => `«${id}» کا پرانا ورژن`,
258
+ savedAt: (when) => `محفوظ شدہ: ${when}`,
259
+ size: (kb) => `${kb} کے بی`,
260
+ replacePrompt: 'موجودہ مواد کو اس مسودے سے بدل دیں؟',
261
+ replace: 'بدل دیں',
262
+ deletePrompt: 'یہ مسودہ حذف کریں؟',
263
+ delete: 'حذف کریں',
264
+ close: 'بند کریں',
265
+ },
208
266
  link: {
209
267
  menuLabel: 'لنک',
210
268
  noUrl: '(کوئی یو آر ایل نہیں)',
@@ -284,8 +342,6 @@ const paShahmukhi = {
284
342
  editor: {
285
343
  placeholder: 'لکھنا شروع کرو…',
286
344
  contentLabel: 'ایڈیٹر دی سامگری',
287
- confirmDiscard: 'تہاڈیاں کجھ تبدیلیاں سنبھالیاں نئیں گئیاں۔ کی ایہناں نوں رد کر دیئے؟',
288
- pageBreakLabel: 'صفحے دی ونڈ',
289
345
  },
290
346
  common: {
291
347
  cancel: 'رد کرو',
@@ -295,6 +351,7 @@ const paShahmukhi = {
295
351
  toolbar: {
296
352
  ariaLabel: 'فارمیٹنگ',
297
353
  save: 'سنبھالو',
354
+ drafts: 'سودھے',
298
355
  undo: 'پہلاں جیہا کرو',
299
356
  redo: 'مُڑ کرو',
300
357
  formattingLabel: 'فارمیٹنگ',
@@ -310,7 +367,6 @@ const paShahmukhi = {
310
367
  linkOptions: 'لنک دے اختیار',
311
368
  insertLink: 'لنک پاؤ (Ctrl+K)',
312
369
  insertImage: 'تصویر پاؤ',
313
- insertPageBreak: 'صفحے دی ونڈ پاؤ',
314
370
  poetryBlocks: 'شاعری بلاک',
315
371
  comingSoon: (label) => `${label} (چھیتی آ رہا اے)`,
316
372
  autocorrect: 'خودکار درستی',
@@ -343,6 +399,37 @@ const paShahmukhi = {
343
399
  right: 'سجے سیدھ',
344
400
  },
345
401
  },
402
+ leaveDialog: {
403
+ title: 'غیر محفوظ تبدیلیاں',
404
+ message: 'تہاڈیاں تبدیلیاں سنبھالیاں نئیں گئیاں۔ جان توں پہلاں تسی کی کرنا چاہو گے؟',
405
+ save: 'سنبھالو',
406
+ saveDraft: 'سودھا سنبھالو',
407
+ discard: 'تبدیلیاں رد کرو',
408
+ stay: 'ایتھے ای رہو',
409
+ saveDraftFailed: 'سودھا سنبھالیا نئیں جا سکیا (دستاویز بہت وڈی ہو سکدی اے، یا براؤزر دی سٹوریج نئیں اے)۔',
410
+ },
411
+ drafts: {
412
+ bannerMessage: (when) => `ایس دستاویز دا اک غیر محفوظ سودھا (${when}) لبھیا اے۔`,
413
+ restore: 'بحال کرو',
414
+ ignore: 'نظر انداز کرو',
415
+ remove: 'سودھا ہٹاؤ',
416
+ dialogTitle: 'سنبھالے ہوئے سودھے',
417
+ intro: 'لکھدیاں ہویاں سودھے ایس براؤزر وچ آپ سنبھلدے نیں تے سنبھالن تے ہٹ جاندے نیں۔',
418
+ empty: 'ہلے کوئی سودھا نئیں۔',
419
+ noText: '(کوئی متن نئیں)',
420
+ thisDocument: 'موجودہ دستاویز',
421
+ untitled: 'بنا ناں دا سودھا',
422
+ documentLabel: (id) => `دستاویز «${id}»`,
423
+ earlierUntitled: 'اک بنا ناں دے سودھے دا پرانا ورژن',
424
+ earlierVersionOf: (id) => `«${id}» دا پرانا ورژن`,
425
+ savedAt: (when) => `سنبھالیا: ${when}`,
426
+ size: (kb) => `${kb} کے بی`,
427
+ replacePrompt: 'موجودہ مواد نوں ایس سودھے نال بدل دیئے؟',
428
+ replace: 'بدل دیو',
429
+ deletePrompt: 'ایہ سودھا مٹا دیئے؟',
430
+ delete: 'مٹاؤ',
431
+ close: 'بند کرو',
432
+ },
346
433
  link: {
347
434
  menuLabel: 'لنک',
348
435
  noUrl: '(کوئی یو آر ایل نئیں)',
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;AAQlD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAS5C,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;AAOlD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAQ5C,CAAC"}
package/dist/nodes.js CHANGED
@@ -3,7 +3,6 @@ import { ListItemNode, ListNode } from '@lexical/list';
3
3
  import { LinkNode } from '@lexical/link';
4
4
  import { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';
5
5
  import { ImageNode } from './image/ImageNode.js';
6
- import { PageBreakNode } from './blocks/PageBreakNode.js';
7
6
  /**
8
7
  * Node types registered on the editor at construction time. Per
9
8
  * editor-architecture-design.md §2, node registration cannot be conditional
@@ -21,5 +20,4 @@ export const EDITOR_NODES = [
21
20
  LinkNode,
22
21
  HorizontalRuleNode,
23
22
  ImageNode,
24
- PageBreakNode,
25
23
  ];
@@ -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