@inshapardaz/likhari-react 0.1.6 → 0.1.7-dev.73
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 +25 -1
- package/dist/EditorRoot.d.ts.map +1 -1
- package/dist/EditorRoot.js +24 -5
- package/dist/PortalTargetContext.d.ts +16 -0
- package/dist/PortalTargetContext.d.ts.map +1 -0
- package/dist/PortalTargetContext.js +18 -0
- package/dist/components/LinkDialog.d.ts.map +1 -1
- package/dist/components/LinkDialog.js +7 -3
- package/dist/components/Toolbar.d.ts +4 -1
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +246 -33
- package/dist/i18n/index.d.ts +4 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/strings.d.ts +158 -0
- package/dist/i18n/strings.d.ts.map +1 -0
- package/dist/i18n/strings.js +425 -0
- package/dist/i18n/useStrings.d.ts +10 -0
- package/dist/i18n/useStrings.d.ts.map +1 -0
- package/dist/i18n/useStrings.js +14 -0
- package/dist/image/ImageComponent.d.ts +23 -0
- package/dist/image/ImageComponent.d.ts.map +1 -0
- package/dist/image/ImageComponent.js +171 -0
- package/dist/image/ImageCropDialog.d.ts +22 -0
- package/dist/image/ImageCropDialog.d.ts.map +1 -0
- package/dist/image/ImageCropDialog.js +120 -0
- package/dist/image/ImageCropper.d.ts +15 -0
- package/dist/image/ImageCropper.d.ts.map +1 -0
- package/dist/image/ImageCropper.js +120 -0
- package/dist/image/ImageDialog.d.ts +37 -0
- package/dist/image/ImageDialog.d.ts.map +1 -0
- package/dist/image/ImageDialog.js +176 -0
- package/dist/image/ImageNode.d.ts +64 -0
- package/dist/image/ImageNode.d.ts.map +1 -0
- package/dist/image/ImageNode.js +133 -0
- package/dist/image/ImageOptionsContext.d.ts +24 -0
- package/dist/image/ImageOptionsContext.d.ts.map +1 -0
- package/dist/image/ImageOptionsContext.js +10 -0
- package/dist/image/cropMath.d.ts +35 -0
- package/dist/image/cropMath.d.ts.map +1 -0
- package/dist/image/cropMath.js +92 -0
- package/dist/image/imageEdit.d.ts +49 -0
- package/dist/image/imageEdit.d.ts.map +1 -0
- package/dist/image/imageEdit.js +132 -0
- package/dist/image/imageUrl.d.ts +14 -0
- package/dist/image/imageUrl.d.ts.map +1 -0
- package/dist/image/imageUrl.js +27 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +2 -0
- package/dist/theme/EditorThemeProvider.d.ts +17 -2
- package/dist/theme/EditorThemeProvider.d.ts.map +1 -1
- package/dist/theme/EditorThemeProvider.js +27 -3
- package/dist/theme/accentColor.d.ts +43 -0
- package/dist/theme/accentColor.d.ts.map +1 -0
- package/dist/theme/accentColor.js +84 -0
- package/dist/theme/editor.css +125 -0
- package/dist/theme/editorTheme.d.ts.map +1 -1
- package/dist/theme/editorTheme.js +1 -0
- package/package.json +9 -3
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI localization strings for the editor's own chrome (toolbar, dialogs,
|
|
3
|
+
* menus, placeholders) — see docs/lexical-editor-spec.md §3.2. This is
|
|
4
|
+
* separate from content direction/fonts (handled in EditorRoot) and from
|
|
5
|
+
* Markdown/HTML/plain-text format translation, which is out of scope here.
|
|
6
|
+
*/
|
|
7
|
+
const en = {
|
|
8
|
+
editor: {
|
|
9
|
+
placeholder: 'Start writing…',
|
|
10
|
+
contentLabel: 'Editor content',
|
|
11
|
+
confirmDiscard: 'You have unsaved changes. Discard them?',
|
|
12
|
+
},
|
|
13
|
+
common: {
|
|
14
|
+
cancel: 'Cancel',
|
|
15
|
+
save: 'Save',
|
|
16
|
+
insert: 'Insert',
|
|
17
|
+
},
|
|
18
|
+
toolbar: {
|
|
19
|
+
ariaLabel: 'Formatting',
|
|
20
|
+
save: 'Save',
|
|
21
|
+
undo: 'Undo',
|
|
22
|
+
redo: 'Redo',
|
|
23
|
+
formattingLabel: 'Formatting',
|
|
24
|
+
bold: 'Bold',
|
|
25
|
+
italic: 'Italic',
|
|
26
|
+
underline: 'Underline',
|
|
27
|
+
fontFamily: 'Font family',
|
|
28
|
+
fontFamilyPlaceholder: 'Font',
|
|
29
|
+
fontSize: 'Font size',
|
|
30
|
+
fontSizePlaceholder: 'Size',
|
|
31
|
+
noMatch: 'No match',
|
|
32
|
+
alignment: 'Alignment',
|
|
33
|
+
linkOptions: 'Link options',
|
|
34
|
+
insertLink: 'Insert link (Ctrl+K)',
|
|
35
|
+
insertImage: 'Insert image',
|
|
36
|
+
poetryBlocks: 'Poetry blocks',
|
|
37
|
+
comingSoon: (label) => `${label} (coming soon)`,
|
|
38
|
+
autocorrect: 'Auto-correct',
|
|
39
|
+
textCleanup: 'Text cleanup',
|
|
40
|
+
spellChecker: 'Spell-checker',
|
|
41
|
+
moreFormatting: 'More formatting',
|
|
42
|
+
strikethrough: 'Strikethrough',
|
|
43
|
+
superscript: 'Superscript',
|
|
44
|
+
subscript: 'Subscript',
|
|
45
|
+
uppercase: 'UPPERCASE',
|
|
46
|
+
lowercase: 'lowercase',
|
|
47
|
+
capitalize: 'Capitalize',
|
|
48
|
+
clearFormatting: 'Clear formatting',
|
|
49
|
+
outdent: 'Outdent',
|
|
50
|
+
indent: 'Indent',
|
|
51
|
+
formattingOptions: {
|
|
52
|
+
paragraph: 'Paragraph',
|
|
53
|
+
heading: (level) => `Heading ${level}`,
|
|
54
|
+
numberedList: 'Numbered list',
|
|
55
|
+
bulletList: 'Bullet list',
|
|
56
|
+
taskList: 'Task list',
|
|
57
|
+
quote: 'Quote',
|
|
58
|
+
},
|
|
59
|
+
alignOptions: {
|
|
60
|
+
start: 'Align start',
|
|
61
|
+
center: 'Align center',
|
|
62
|
+
end: 'Align end',
|
|
63
|
+
justify: 'Justify',
|
|
64
|
+
left: 'Align left',
|
|
65
|
+
right: 'Align right',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
link: {
|
|
69
|
+
menuLabel: 'Link',
|
|
70
|
+
noUrl: '(no URL)',
|
|
71
|
+
editLink: 'Edit link',
|
|
72
|
+
removeLink: 'Remove link',
|
|
73
|
+
},
|
|
74
|
+
linkDialog: {
|
|
75
|
+
titleInsert: 'Insert link',
|
|
76
|
+
titleEdit: 'Edit link',
|
|
77
|
+
urlLabel: 'URL',
|
|
78
|
+
urlPlaceholder: 'https://example.com',
|
|
79
|
+
textLabel: 'Text',
|
|
80
|
+
textPlaceholder: 'Link text (defaults to the URL)',
|
|
81
|
+
invalidUrl: 'Enter a valid http(s), mailto, tel or relative URL',
|
|
82
|
+
apply: 'Apply',
|
|
83
|
+
},
|
|
84
|
+
imageDialog: {
|
|
85
|
+
titleInsert: 'Insert image',
|
|
86
|
+
titleEdit: 'Edit image',
|
|
87
|
+
currentImage: 'Current image',
|
|
88
|
+
fromUrl: 'From URL',
|
|
89
|
+
upload: 'Upload',
|
|
90
|
+
embeddedInDocument: 'Embedded in the document',
|
|
91
|
+
linkedFrom: (src) => `Linked from ${src}`,
|
|
92
|
+
convertButton: 'Convert to embedded image',
|
|
93
|
+
convertHint: 'Downloads a copy into the document, so it can be cropped, rotated and resized.',
|
|
94
|
+
imageUrlLabel: 'Image URL',
|
|
95
|
+
imageUrlPlaceholder: 'https://example.com/photo.jpg',
|
|
96
|
+
embedCopyLabel: 'Embed a copy in the document',
|
|
97
|
+
embedCopyDescription: 'Downloads the image so it can be edited and no longer depends on the URL.',
|
|
98
|
+
convertedFromUrl: 'Converted from the URL: a copy will be embedded in the document.',
|
|
99
|
+
fileLabel: 'Image file',
|
|
100
|
+
filePlaceholder: 'Choose an image',
|
|
101
|
+
fileDescription: (maxSizeMB, storedInDocument) => `Up to ${maxSizeMB} MB${storedInDocument ? '; stored inside the document' : ''}`,
|
|
102
|
+
altTextLabel: 'Alt text',
|
|
103
|
+
altTextDescription: 'Describes the image for screen readers',
|
|
104
|
+
captionLabel: 'Caption',
|
|
105
|
+
captionDescription: 'Shown under the image. Leave empty for none.',
|
|
106
|
+
errors: {
|
|
107
|
+
enterUrl: 'Enter an http(s) or relative image URL',
|
|
108
|
+
chooseFile: 'Choose an image file',
|
|
109
|
+
noImage: 'No image',
|
|
110
|
+
uploadUnusable: 'The upload handler returned an unusable image URL',
|
|
111
|
+
couldNotSave: 'Could not save the image',
|
|
112
|
+
couldNotConvert: 'Could not convert the image',
|
|
113
|
+
couldNotReadFile: 'Could not read the file',
|
|
114
|
+
largerThan: (maxSizeMB) => `Image is larger than ${maxSizeMB} MB`,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
imageCropDialog: {
|
|
118
|
+
title: 'Crop & resize',
|
|
119
|
+
sizeLabel: 'Size',
|
|
120
|
+
widthLabel: 'Width (px)',
|
|
121
|
+
heightLabel: 'Height (px)',
|
|
122
|
+
autoPlaceholder: 'Auto',
|
|
123
|
+
keepProportions: 'Keep proportions',
|
|
124
|
+
originalSize: 'Original size',
|
|
125
|
+
dragHint: (natural) => `You can also drag the corner handle on a selected image. ${natural ? `Original: ${natural.width} × ${natural.height} px.` : ''}`,
|
|
126
|
+
errors: {
|
|
127
|
+
uploadUnusable: 'The upload handler returned an unusable image URL',
|
|
128
|
+
couldNotSave: 'Could not save the image',
|
|
129
|
+
largerThan: (maxSizeMB) => `Image is larger than ${maxSizeMB} MB`,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
imageMenu: {
|
|
133
|
+
editImage: 'Edit image…',
|
|
134
|
+
convertToEmbedded: 'Convert to embedded image',
|
|
135
|
+
cropResize: 'Crop & resize…',
|
|
136
|
+
addCaption: 'Add caption…',
|
|
137
|
+
editCaption: 'Edit caption…',
|
|
138
|
+
removeCaption: 'Remove caption',
|
|
139
|
+
deleteImage: 'Delete image',
|
|
140
|
+
resizeImage: 'Resize image',
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
const ur = {
|
|
144
|
+
editor: {
|
|
145
|
+
placeholder: 'لکھنا شروع کریں…',
|
|
146
|
+
contentLabel: 'ایڈیٹر کا مواد',
|
|
147
|
+
confirmDiscard: 'آپ کی غیر محفوظ شدہ تبدیلیاں ہیں۔ کیا انہیں رد کر دیا جائے؟',
|
|
148
|
+
},
|
|
149
|
+
common: {
|
|
150
|
+
cancel: 'منسوخ کریں',
|
|
151
|
+
save: 'محفوظ کریں',
|
|
152
|
+
insert: 'شامل کریں',
|
|
153
|
+
},
|
|
154
|
+
toolbar: {
|
|
155
|
+
ariaLabel: 'فارمیٹنگ',
|
|
156
|
+
save: 'محفوظ کریں',
|
|
157
|
+
undo: 'کالعدم کریں',
|
|
158
|
+
redo: 'دوبارہ کریں',
|
|
159
|
+
formattingLabel: 'فارمیٹنگ',
|
|
160
|
+
bold: 'موٹا',
|
|
161
|
+
italic: 'ترچھا',
|
|
162
|
+
underline: 'زیرِ خط',
|
|
163
|
+
fontFamily: 'فونٹ کا خاندان',
|
|
164
|
+
fontFamilyPlaceholder: 'فونٹ',
|
|
165
|
+
fontSize: 'فونٹ کا سائز',
|
|
166
|
+
fontSizePlaceholder: 'سائز',
|
|
167
|
+
noMatch: 'کوئی مماثلت نہیں',
|
|
168
|
+
alignment: 'سیدھ',
|
|
169
|
+
linkOptions: 'لنک کے اختیارات',
|
|
170
|
+
insertLink: 'لنک شامل کریں (Ctrl+K)',
|
|
171
|
+
insertImage: 'تصویر شامل کریں',
|
|
172
|
+
poetryBlocks: 'شاعری کے بلاکس',
|
|
173
|
+
comingSoon: (label) => `${label} (جلد آ رہا ہے)`,
|
|
174
|
+
autocorrect: 'خودکار تصحیح',
|
|
175
|
+
textCleanup: 'متن کی صفائی',
|
|
176
|
+
spellChecker: 'ہجے چیک کرنے والا',
|
|
177
|
+
moreFormatting: 'مزید فارمیٹنگ',
|
|
178
|
+
strikethrough: 'خط زدہ',
|
|
179
|
+
superscript: 'بالا نویس',
|
|
180
|
+
subscript: 'زیریں نویس',
|
|
181
|
+
uppercase: 'بڑے حروف',
|
|
182
|
+
lowercase: 'چھوٹے حروف',
|
|
183
|
+
capitalize: 'پہلا حرف بڑا',
|
|
184
|
+
clearFormatting: 'فارمیٹنگ ختم کریں',
|
|
185
|
+
outdent: 'حاشیہ کم کریں',
|
|
186
|
+
indent: 'حاشیہ بڑھائیں',
|
|
187
|
+
formattingOptions: {
|
|
188
|
+
paragraph: 'پیراگراف',
|
|
189
|
+
heading: (level) => `عنوان ${level}`,
|
|
190
|
+
numberedList: 'نمبردار فہرست',
|
|
191
|
+
bulletList: 'بلٹ فہرست',
|
|
192
|
+
taskList: 'ٹاسک فہرست',
|
|
193
|
+
quote: 'اقتباس',
|
|
194
|
+
},
|
|
195
|
+
alignOptions: {
|
|
196
|
+
start: 'ابتدائی سیدھ',
|
|
197
|
+
center: 'درمیانی سیدھ',
|
|
198
|
+
end: 'اختتامی سیدھ',
|
|
199
|
+
justify: 'دو طرفہ سیدھ',
|
|
200
|
+
left: 'بائیں سیدھ',
|
|
201
|
+
right: 'دائیں سیدھ',
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
link: {
|
|
205
|
+
menuLabel: 'لنک',
|
|
206
|
+
noUrl: '(کوئی یو آر ایل نہیں)',
|
|
207
|
+
editLink: 'لنک میں ترمیم کریں',
|
|
208
|
+
removeLink: 'لنک ہٹائیں',
|
|
209
|
+
},
|
|
210
|
+
linkDialog: {
|
|
211
|
+
titleInsert: 'لنک شامل کریں',
|
|
212
|
+
titleEdit: 'لنک میں ترمیم کریں',
|
|
213
|
+
urlLabel: 'یو آر ایل',
|
|
214
|
+
urlPlaceholder: 'https://example.com',
|
|
215
|
+
textLabel: 'عبارت',
|
|
216
|
+
textPlaceholder: 'لنک کی عبارت (نہ دینے پر یو آر ایل ہی استعمال ہوگا)',
|
|
217
|
+
invalidUrl: 'براہِ کرم ایک درست http(s)، mailto، tel یا رشتہ دار یو آر ایل درج کریں',
|
|
218
|
+
apply: 'لاگو کریں',
|
|
219
|
+
},
|
|
220
|
+
imageDialog: {
|
|
221
|
+
titleInsert: 'تصویر شامل کریں',
|
|
222
|
+
titleEdit: 'تصویر میں ترمیم کریں',
|
|
223
|
+
currentImage: 'موجودہ تصویر',
|
|
224
|
+
fromUrl: 'یو آر ایل سے',
|
|
225
|
+
upload: 'اپ لوڈ',
|
|
226
|
+
embeddedInDocument: 'دستاویز میں شامل',
|
|
227
|
+
linkedFrom: (src) => `${src} سے منسلک`,
|
|
228
|
+
convertButton: 'شامل شدہ تصویر میں تبدیل کریں',
|
|
229
|
+
convertHint: 'دستاویز میں ایک نقل ڈاؤن لوڈ کرتا ہے، تاکہ اسے کاٹا، گھمایا اور سائز تبدیل کیا جا سکے۔',
|
|
230
|
+
imageUrlLabel: 'تصویر کا یو آر ایل',
|
|
231
|
+
imageUrlPlaceholder: 'https://example.com/photo.jpg',
|
|
232
|
+
embedCopyLabel: 'دستاویز میں ایک نقل شامل کریں',
|
|
233
|
+
embedCopyDescription: 'تصویر ڈاؤن لوڈ کرتا ہے تاکہ اس میں ترمیم کی جا سکے اور یہ یو آر ایل پر منحصر نہ رہے۔',
|
|
234
|
+
convertedFromUrl: 'یو آر ایل سے تبدیل شدہ: ایک نقل دستاویز میں شامل کی جائے گی۔',
|
|
235
|
+
fileLabel: 'تصویر کی فائل',
|
|
236
|
+
filePlaceholder: 'ایک تصویر منتخب کریں',
|
|
237
|
+
fileDescription: (maxSizeMB, storedInDocument) => `${maxSizeMB} ایم بی تک${storedInDocument ? '؛ دستاویز کے اندر محفوظ ہوتی ہے' : ''}`,
|
|
238
|
+
altTextLabel: 'متبادل متن',
|
|
239
|
+
altTextDescription: 'سکرین ریڈرز کے لیے تصویر کی تفصیل بیان کرتا ہے',
|
|
240
|
+
captionLabel: 'کیپشن',
|
|
241
|
+
captionDescription: 'تصویر کے نیچے دکھایا جاتا ہے۔ نہ چاہیں تو خالی چھوڑ دیں۔',
|
|
242
|
+
errors: {
|
|
243
|
+
enterUrl: 'ایک http(s) یا رشتہ دار تصویر یو آر ایل درج کریں',
|
|
244
|
+
chooseFile: 'ایک تصویر فائل منتخب کریں',
|
|
245
|
+
noImage: 'کوئی تصویر نہیں',
|
|
246
|
+
uploadUnusable: 'اپ لوڈ ہینڈلر نے ناقابلِ استعمال یو آر ایل واپس کیا',
|
|
247
|
+
couldNotSave: 'تصویر محفوظ نہیں ہو سکی',
|
|
248
|
+
couldNotConvert: 'تصویر تبدیل نہیں ہو سکی',
|
|
249
|
+
couldNotReadFile: 'فائل پڑھی نہیں جا سکی',
|
|
250
|
+
largerThan: (maxSizeMB) => `تصویر ${maxSizeMB} ایم بی سے بڑی ہے`,
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
imageCropDialog: {
|
|
254
|
+
title: 'کاٹیں اور سائز تبدیل کریں',
|
|
255
|
+
sizeLabel: 'سائز',
|
|
256
|
+
widthLabel: 'چوڑائی (px)',
|
|
257
|
+
heightLabel: 'اونچائی (px)',
|
|
258
|
+
autoPlaceholder: 'خودکار',
|
|
259
|
+
keepProportions: 'تناسب برقرار رکھیں',
|
|
260
|
+
originalSize: 'اصل سائز',
|
|
261
|
+
dragHint: (natural) => `منتخب شدہ تصویر پر کارنر ہینڈل کھینچ کر بھی سائز تبدیل کیا جا سکتا ہے۔ ${natural ? `اصل: ${natural.width} × ${natural.height} پکسل۔` : ''}`,
|
|
262
|
+
errors: {
|
|
263
|
+
uploadUnusable: 'اپ لوڈ ہینڈلر نے ناقابلِ استعمال یو آر ایل واپس کیا',
|
|
264
|
+
couldNotSave: 'تصویر محفوظ نہیں ہو سکی',
|
|
265
|
+
largerThan: (maxSizeMB) => `تصویر ${maxSizeMB} ایم بی سے بڑی ہے`,
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
imageMenu: {
|
|
269
|
+
editImage: 'تصویر میں ترمیم کریں…',
|
|
270
|
+
convertToEmbedded: 'شامل شدہ تصویر میں تبدیل کریں',
|
|
271
|
+
cropResize: 'کاٹیں اور سائز تبدیل کریں…',
|
|
272
|
+
addCaption: 'کیپشن شامل کریں…',
|
|
273
|
+
editCaption: 'کیپشن میں ترمیم کریں…',
|
|
274
|
+
removeCaption: 'کیپشن ہٹائیں',
|
|
275
|
+
deleteImage: 'تصویر حذف کریں',
|
|
276
|
+
resizeImage: 'تصویر کا سائز تبدیل کریں',
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
const paShahmukhi = {
|
|
280
|
+
editor: {
|
|
281
|
+
placeholder: 'لکھنا شروع کرو…',
|
|
282
|
+
contentLabel: 'ایڈیٹر دی سامگری',
|
|
283
|
+
confirmDiscard: 'تہاڈیاں کجھ تبدیلیاں سنبھالیاں نئیں گئیاں۔ کی ایہناں نوں رد کر دیئے؟',
|
|
284
|
+
},
|
|
285
|
+
common: {
|
|
286
|
+
cancel: 'رد کرو',
|
|
287
|
+
save: 'سنبھالو',
|
|
288
|
+
insert: 'پاؤ',
|
|
289
|
+
},
|
|
290
|
+
toolbar: {
|
|
291
|
+
ariaLabel: 'فارمیٹنگ',
|
|
292
|
+
save: 'سنبھالو',
|
|
293
|
+
undo: 'پہلاں جیہا کرو',
|
|
294
|
+
redo: 'مُڑ کرو',
|
|
295
|
+
formattingLabel: 'فارمیٹنگ',
|
|
296
|
+
bold: 'گہرا',
|
|
297
|
+
italic: 'ترچھا',
|
|
298
|
+
underline: 'تھلے لکیر',
|
|
299
|
+
fontFamily: 'فونٹ خاندان',
|
|
300
|
+
fontFamilyPlaceholder: 'فونٹ',
|
|
301
|
+
fontSize: 'فونٹ دا سائز',
|
|
302
|
+
fontSizePlaceholder: 'سائز',
|
|
303
|
+
noMatch: 'کوئی نئیں ملیا',
|
|
304
|
+
alignment: 'سیدھ',
|
|
305
|
+
linkOptions: 'لنک دے اختیار',
|
|
306
|
+
insertLink: 'لنک پاؤ (Ctrl+K)',
|
|
307
|
+
insertImage: 'تصویر پاؤ',
|
|
308
|
+
poetryBlocks: 'شاعری بلاک',
|
|
309
|
+
comingSoon: (label) => `${label} (چھیتی آ رہا اے)`,
|
|
310
|
+
autocorrect: 'خودکار درستی',
|
|
311
|
+
textCleanup: 'متن دی صفائی',
|
|
312
|
+
spellChecker: 'ہجے چیکر',
|
|
313
|
+
moreFormatting: 'ہور فارمیٹنگ',
|
|
314
|
+
strikethrough: 'کٹی لکیر',
|
|
315
|
+
superscript: 'اُتلا لکھت',
|
|
316
|
+
subscript: 'تلا لکھت',
|
|
317
|
+
uppercase: 'وڈے حرف',
|
|
318
|
+
lowercase: 'نکے حرف',
|
|
319
|
+
capitalize: 'پہلا حرف وڈا',
|
|
320
|
+
clearFormatting: 'فارمیٹنگ ہٹاؤ',
|
|
321
|
+
outdent: 'حاشیہ گھٹاؤ',
|
|
322
|
+
indent: 'حاشیہ ودھاؤ',
|
|
323
|
+
formattingOptions: {
|
|
324
|
+
paragraph: 'پیراگراف',
|
|
325
|
+
heading: (level) => `سرلیکھ ${level}`,
|
|
326
|
+
numberedList: 'نمبردار لسٹ',
|
|
327
|
+
bulletList: 'بلٹ لسٹ',
|
|
328
|
+
taskList: 'ٹاسک لسٹ',
|
|
329
|
+
quote: 'حوالہ',
|
|
330
|
+
},
|
|
331
|
+
alignOptions: {
|
|
332
|
+
start: 'شروع دی سیدھ',
|
|
333
|
+
center: 'وچکار دی سیدھ',
|
|
334
|
+
end: 'آخری سیدھ',
|
|
335
|
+
justify: 'دوویں پاسے سیدھ',
|
|
336
|
+
left: 'بائیں سیدھ',
|
|
337
|
+
right: 'سجے سیدھ',
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
link: {
|
|
341
|
+
menuLabel: 'لنک',
|
|
342
|
+
noUrl: '(کوئی یو آر ایل نئیں)',
|
|
343
|
+
editLink: 'لنک وچ تبدیلی کرو',
|
|
344
|
+
removeLink: 'لنک ہٹاؤ',
|
|
345
|
+
},
|
|
346
|
+
linkDialog: {
|
|
347
|
+
titleInsert: 'لنک پاؤ',
|
|
348
|
+
titleEdit: 'لنک وچ تبدیلی کرو',
|
|
349
|
+
urlLabel: 'یو آر ایل',
|
|
350
|
+
urlPlaceholder: 'https://example.com',
|
|
351
|
+
textLabel: 'لکھت',
|
|
352
|
+
textPlaceholder: 'لنک دی لکھت (نہ دین تے یو آر ایل ای ورتیا جاوے گا)',
|
|
353
|
+
invalidUrl: 'کِرپا کر کے صحیح http(s)، mailto، tel یا نسبتی یو آر ایل پاؤ',
|
|
354
|
+
apply: 'لاگو کرو',
|
|
355
|
+
},
|
|
356
|
+
imageDialog: {
|
|
357
|
+
titleInsert: 'تصویر پاؤ',
|
|
358
|
+
titleEdit: 'تصویر وچ تبدیلی کرو',
|
|
359
|
+
currentImage: 'موجودہ تصویر',
|
|
360
|
+
fromUrl: 'یو آر ایل توں',
|
|
361
|
+
upload: 'اپ لوڈ',
|
|
362
|
+
embeddedInDocument: 'دستاویز وچ شامل',
|
|
363
|
+
linkedFrom: (src) => `${src} توں لنک کیتا گیا`,
|
|
364
|
+
convertButton: 'شامل تصویر وچ بدلو',
|
|
365
|
+
convertHint: 'دستاویز وچ اک کاپی ڈاؤن لوڈ کردا اے، تاں جو ایہنوں کٹیا، گھمایا تے سائز بدلیا جا سکے۔',
|
|
366
|
+
imageUrlLabel: 'تصویر دا یو آر ایل',
|
|
367
|
+
imageUrlPlaceholder: 'https://example.com/photo.jpg',
|
|
368
|
+
embedCopyLabel: 'دستاویز وچ اک کاپی شامل کرو',
|
|
369
|
+
embedCopyDescription: 'تصویر ڈاؤن لوڈ کردا اے تاں جو ایہنوں تبدیل کیتا جا سکے تے ایہہ یو آر ایل تے منحصر نہ رہے۔',
|
|
370
|
+
convertedFromUrl: 'یو آر ایل توں بدلیا گیا: اک کاپی دستاویز وچ شامل کیتی جاوے گی۔',
|
|
371
|
+
fileLabel: 'تصویر دی فائل',
|
|
372
|
+
filePlaceholder: 'اک تصویر چُنو',
|
|
373
|
+
fileDescription: (maxSizeMB, storedInDocument) => `${maxSizeMB} ایم بی تیک${storedInDocument ? '؛ دستاویز دے اندر سنبھالی جاندی اے' : ''}`,
|
|
374
|
+
altTextLabel: 'بدل متن',
|
|
375
|
+
altTextDescription: 'سکرین ریڈرز لئی تصویر دی وضاحت کردا اے',
|
|
376
|
+
captionLabel: 'کیپشن',
|
|
377
|
+
captionDescription: 'تصویر دے تھلے دکھایا جاندا اے۔ نہ چاہیدا تے خالی چھڈ دیو۔',
|
|
378
|
+
errors: {
|
|
379
|
+
enterUrl: 'اک http(s) یا نسبتی تصویر یو آر ایل پاؤ',
|
|
380
|
+
chooseFile: 'اک تصویر فائل چُنو',
|
|
381
|
+
noImage: 'کوئی تصویر نئیں',
|
|
382
|
+
uploadUnusable: 'اپ لوڈ ہینڈلر نے ناکارآمد یو آر ایل موڑیا',
|
|
383
|
+
couldNotSave: 'تصویر سنبھالی نئیں جا سکی',
|
|
384
|
+
couldNotConvert: 'تصویر بدلی نئیں جا سکی',
|
|
385
|
+
couldNotReadFile: 'فائل پڑھی نئیں جا سکی',
|
|
386
|
+
largerThan: (maxSizeMB) => `تصویر ${maxSizeMB} ایم بی توں وڈی اے`,
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
imageCropDialog: {
|
|
390
|
+
title: 'کٹو تے سائز بدلو',
|
|
391
|
+
sizeLabel: 'سائز',
|
|
392
|
+
widthLabel: 'چوڑائی (px)',
|
|
393
|
+
heightLabel: 'اُچائی (px)',
|
|
394
|
+
autoPlaceholder: 'خودکار',
|
|
395
|
+
keepProportions: 'تناسب رکھو',
|
|
396
|
+
originalSize: 'اصلی سائز',
|
|
397
|
+
dragHint: (natural) => `چُنی ہوئی تصویر تے کارنر ہینڈل گھسیٹ کے وی سائز بدلیا جا سکدا اے۔ ${natural ? `اصلی: ${natural.width} × ${natural.height} پکسل۔` : ''}`,
|
|
398
|
+
errors: {
|
|
399
|
+
uploadUnusable: 'اپ لوڈ ہینڈلر نے ناکارآمد یو آر ایل موڑیا',
|
|
400
|
+
couldNotSave: 'تصویر سنبھالی نئیں جا سکی',
|
|
401
|
+
largerThan: (maxSizeMB) => `تصویر ${maxSizeMB} ایم بی توں وڈی اے`,
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
imageMenu: {
|
|
405
|
+
editImage: 'تصویر وچ تبدیلی کرو…',
|
|
406
|
+
convertToEmbedded: 'شامل تصویر وچ بدلو',
|
|
407
|
+
cropResize: 'کٹو تے سائز بدلو…',
|
|
408
|
+
addCaption: 'کیپشن شامل کرو…',
|
|
409
|
+
editCaption: 'کیپشن وچ تبدیلی کرو…',
|
|
410
|
+
removeCaption: 'کیپشن ہٹاؤ',
|
|
411
|
+
deleteImage: 'تصویر مٹاؤ',
|
|
412
|
+
resizeImage: 'تصویر دا سائز بدلو',
|
|
413
|
+
},
|
|
414
|
+
};
|
|
415
|
+
export const STRINGS = {
|
|
416
|
+
en,
|
|
417
|
+
ur,
|
|
418
|
+
'pa-shahmukhi': paShahmukhi,
|
|
419
|
+
};
|
|
420
|
+
/** Returns the strings dictionary for `locale`, defensively falling back to
|
|
421
|
+
* `en` for any locale not present in `STRINGS` (e.g. a future locale value
|
|
422
|
+
* passed by a caller on an older type definition). */
|
|
423
|
+
export function getStrings(locale) {
|
|
424
|
+
return STRINGS[locale] ?? STRINGS.en;
|
|
425
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Locale, type Strings } from './strings.js';
|
|
2
|
+
/** Returns the translated strings dictionary for `locale`. */
|
|
3
|
+
export declare function useStrings(locale: Locale): Strings;
|
|
4
|
+
/** Provided once at `EditorRoot`'s top level so components that aren't
|
|
5
|
+
* direct children (dialogs, context menus) can reach the current locale's
|
|
6
|
+
* strings without threading a `locale` prop through every intermediate
|
|
7
|
+
* component. */
|
|
8
|
+
export declare const UiStringsContext: import("react").Context<Strings>;
|
|
9
|
+
export declare function useUiStrings(): Strings;
|
|
10
|
+
//# sourceMappingURL=useStrings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStrings.d.ts","sourceRoot":"","sources":["../../src/i18n/useStrings.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAElE,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;gBAGgB;AAChB,eAAO,MAAM,gBAAgB,kCAA2C,CAAC;AAEzE,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createContext, useContext, useMemo } from 'react';
|
|
2
|
+
import { getStrings } from './strings.js';
|
|
3
|
+
/** Returns the translated strings dictionary for `locale`. */
|
|
4
|
+
export function useStrings(locale) {
|
|
5
|
+
return useMemo(() => getStrings(locale), [locale]);
|
|
6
|
+
}
|
|
7
|
+
/** Provided once at `EditorRoot`'s top level so components that aren't
|
|
8
|
+
* direct children (dialogs, context menus) can reach the current locale's
|
|
9
|
+
* strings without threading a `locale` prop through every intermediate
|
|
10
|
+
* component. */
|
|
11
|
+
export const UiStringsContext = createContext(getStrings('en'));
|
|
12
|
+
export function useUiStrings() {
|
|
13
|
+
return useContext(UiStringsContext);
|
|
14
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type NodeKey } from 'lexical';
|
|
2
|
+
import type { ImageLinkType } from './ImageNode.js';
|
|
3
|
+
interface ImageComponentProps {
|
|
4
|
+
nodeKey: NodeKey;
|
|
5
|
+
src: string;
|
|
6
|
+
altText: string;
|
|
7
|
+
caption: string | null;
|
|
8
|
+
linkType: ImageLinkType;
|
|
9
|
+
/** Display width in px; null = natural size (height always follows the aspect ratio). */
|
|
10
|
+
width: number | null;
|
|
11
|
+
height: number | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* An image in the document. Click selects it (Delete/Backspace removes it),
|
|
15
|
+
* drag the corner handle to resize an embedded image, double-click or
|
|
16
|
+
* right-click for the edit dialog and menu (edit image, convert a linked image
|
|
17
|
+
* to embedded, add/edit/remove caption, delete). The caption
|
|
18
|
+
* is shown as plain text under the image — it is edited in the dialog, not in
|
|
19
|
+
* place.
|
|
20
|
+
*/
|
|
21
|
+
export declare function ImageComponent({ nodeKey, src, altText, caption, linkType, width, height }: ImageComponentProps): import("react").JSX.Element;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=ImageComponent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageComponent.d.ts","sourceRoot":"","sources":["../../src/image/ImageComponent.tsx"],"names":[],"mappings":"AAKA,OAAO,EASL,KAAK,OAAO,EACb,MAAM,SAAS,CAAC;AAOjB,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,aAAa,CAAC;AAU5D,UAAU,mBAAmB;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,aAAa,CAAC;IACxB,yFAAyF;IACzF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,mBAAmB,+BA4P9G"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Menu } from '@mantine/core';
|
|
4
|
+
import { IconCrop, IconPhotoDown, IconPhotoEdit, IconTextCaption, IconTrash, IconX } from '@tabler/icons-react';
|
|
5
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
6
|
+
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
|
|
7
|
+
import { $getNodeByKey, $getSelection, $isNodeSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, } from 'lexical';
|
|
8
|
+
import { ImageCropDialog } from './ImageCropDialog.js';
|
|
9
|
+
import { ImageDialog } from './ImageDialog.js';
|
|
10
|
+
import { useImageOptions } from './ImageOptionsContext.js';
|
|
11
|
+
import { useUiStrings } from '../i18n/useStrings.js';
|
|
12
|
+
import { usePortalTarget } from '../PortalTargetContext.js';
|
|
13
|
+
import { dataUrlBytes, fetchImageAsDataUrl } from './imageEdit.js';
|
|
14
|
+
// A type-only import of ImageNode (ImageNode itself imports this file), so the
|
|
15
|
+
// node is recognised by its type string rather than `instanceof`.
|
|
16
|
+
function isImageNode(node) {
|
|
17
|
+
return node?.getType() === 'image';
|
|
18
|
+
}
|
|
19
|
+
const MIN_WIDTH = 32;
|
|
20
|
+
/**
|
|
21
|
+
* An image in the document. Click selects it (Delete/Backspace removes it),
|
|
22
|
+
* drag the corner handle to resize an embedded image, double-click or
|
|
23
|
+
* right-click for the edit dialog and menu (edit image, convert a linked image
|
|
24
|
+
* to embedded, add/edit/remove caption, delete). The caption
|
|
25
|
+
* is shown as plain text under the image — it is edited in the dialog, not in
|
|
26
|
+
* place.
|
|
27
|
+
*/
|
|
28
|
+
export function ImageComponent({ nodeKey, src, altText, caption, linkType, width, height }) {
|
|
29
|
+
const [editor] = useLexicalComposerContext();
|
|
30
|
+
const options = useImageOptions();
|
|
31
|
+
const strings = useUiStrings();
|
|
32
|
+
const portalTarget = usePortalTarget();
|
|
33
|
+
const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey);
|
|
34
|
+
const imageRef = useRef(null);
|
|
35
|
+
const figureRef = useRef(null);
|
|
36
|
+
const [menu, setMenu] = useState(null);
|
|
37
|
+
const [dialog, setDialog] = useState(null);
|
|
38
|
+
const [cropDialogOpen, setCropDialogOpen] = useState(false);
|
|
39
|
+
const [liveWidth, setLiveWidth] = useState(null);
|
|
40
|
+
// Selecting must go through CLICK_COMMAND (returning true) rather than a
|
|
41
|
+
// React onClick: otherwise Lexical's own click handling turns the DOM
|
|
42
|
+
// selection into a range selection right after, undoing the node selection.
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
return editor.registerCommand(CLICK_COMMAND, (event) => {
|
|
45
|
+
if (event.target !== imageRef.current)
|
|
46
|
+
return false;
|
|
47
|
+
clearSelection();
|
|
48
|
+
setSelected(true);
|
|
49
|
+
return true;
|
|
50
|
+
}, COMMAND_PRIORITY_LOW);
|
|
51
|
+
}, [editor, clearSelection, setSelected]);
|
|
52
|
+
const removeImage = useCallback(() => {
|
|
53
|
+
editor.update(() => {
|
|
54
|
+
$getNodeByKey(nodeKey)?.remove();
|
|
55
|
+
});
|
|
56
|
+
}, [editor, nodeKey]);
|
|
57
|
+
const onDelete = useCallback((event) => {
|
|
58
|
+
if (!isSelected || dialog || cropDialogOpen || menu)
|
|
59
|
+
return false;
|
|
60
|
+
if (!$isNodeSelection($getSelection()))
|
|
61
|
+
return false;
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
$getNodeByKey(nodeKey)?.remove();
|
|
64
|
+
return true;
|
|
65
|
+
}, [isSelected, dialog, cropDialogOpen, menu, nodeKey]);
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
const unregisterDelete = editor.registerCommand(KEY_DELETE_COMMAND, onDelete, COMMAND_PRIORITY_LOW);
|
|
68
|
+
const unregisterBackspace = editor.registerCommand(KEY_BACKSPACE_COMMAND, onDelete, COMMAND_PRIORITY_LOW);
|
|
69
|
+
return () => {
|
|
70
|
+
unregisterDelete();
|
|
71
|
+
unregisterBackspace();
|
|
72
|
+
};
|
|
73
|
+
}, [editor, onDelete]);
|
|
74
|
+
const updateNode = (change) => {
|
|
75
|
+
editor.update(() => {
|
|
76
|
+
const node = $getNodeByKey(nodeKey);
|
|
77
|
+
if (isImageNode(node))
|
|
78
|
+
change(node);
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
// Converting from the context menu (as opposed to the "Crop & size" tab's
|
|
82
|
+
// checkbox) needs no review: just download and swap the source in place.
|
|
83
|
+
// Only on failure do we fall back to the full dialog, which shows the error
|
|
84
|
+
// and lets the person retry or pick a different image.
|
|
85
|
+
const convertToEmbedded = useCallback(async () => {
|
|
86
|
+
try {
|
|
87
|
+
const dataUrl = await fetchImageAsDataUrl(src, options.fetchImage);
|
|
88
|
+
if (dataUrlBytes(dataUrl) > options.maxSizeMB * 1024 * 1024) {
|
|
89
|
+
throw new Error(strings.imageDialog.errors.largerThan(options.maxSizeMB));
|
|
90
|
+
}
|
|
91
|
+
updateNode((node) => node.setSource(dataUrl, 'embedded'));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
setDialog({ intent: 'convert' });
|
|
95
|
+
}
|
|
96
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
97
|
+
}, [src, options.fetchImage, options.maxSizeMB]);
|
|
98
|
+
const applyEdit = (value) => {
|
|
99
|
+
updateNode((node) => {
|
|
100
|
+
node.setSource(value.src, value.linkType);
|
|
101
|
+
node.setAltText(value.altText);
|
|
102
|
+
node.setCaption(value.caption);
|
|
103
|
+
// A changed source has new pixels the current display size may no
|
|
104
|
+
// longer fit — reset to auto. Editing alt text/caption only keeps it.
|
|
105
|
+
if (value.sourceChanged)
|
|
106
|
+
node.setDimensions(null, null);
|
|
107
|
+
});
|
|
108
|
+
setDialog(null);
|
|
109
|
+
editor.focus();
|
|
110
|
+
};
|
|
111
|
+
const applyCrop = (value) => {
|
|
112
|
+
updateNode((node) => {
|
|
113
|
+
node.setSource(value.src, 'embedded');
|
|
114
|
+
node.setDimensions(value.width, value.height);
|
|
115
|
+
});
|
|
116
|
+
setCropDialogOpen(false);
|
|
117
|
+
editor.focus();
|
|
118
|
+
};
|
|
119
|
+
// --- drag-to-resize: bottom-right handle, aspect ratio kept ---------------
|
|
120
|
+
const resizeStart = useRef(null);
|
|
121
|
+
const onResizeDown = (event) => {
|
|
122
|
+
const img = imageRef.current;
|
|
123
|
+
if (!img)
|
|
124
|
+
return;
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
event.stopPropagation();
|
|
127
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
128
|
+
const box = img.getBoundingClientRect();
|
|
129
|
+
resizeStart.current = {
|
|
130
|
+
x: event.clientX,
|
|
131
|
+
width: box.width,
|
|
132
|
+
ratio: img.naturalHeight && img.naturalWidth ? img.naturalHeight / img.naturalWidth : box.height / box.width,
|
|
133
|
+
max: figureRef.current?.clientWidth ?? box.width,
|
|
134
|
+
};
|
|
135
|
+
setLiveWidth(box.width);
|
|
136
|
+
};
|
|
137
|
+
const onResizeMove = (event) => {
|
|
138
|
+
const start = resizeStart.current;
|
|
139
|
+
if (!start)
|
|
140
|
+
return;
|
|
141
|
+
setLiveWidth(Math.round(Math.min(Math.max(start.width + (event.clientX - start.x), MIN_WIDTH), start.max)));
|
|
142
|
+
};
|
|
143
|
+
const onResizeUp = () => {
|
|
144
|
+
const start = resizeStart.current;
|
|
145
|
+
resizeStart.current = null;
|
|
146
|
+
if (start && liveWidth !== null) {
|
|
147
|
+
const w = Math.round(liveWidth);
|
|
148
|
+
updateNode((node) => node.setDimensions(w, Math.round(w * start.ratio)));
|
|
149
|
+
}
|
|
150
|
+
setLiveWidth(null);
|
|
151
|
+
};
|
|
152
|
+
const shownWidth = liveWidth ?? width ?? undefined;
|
|
153
|
+
return (_jsxs("figure", { ref: figureRef, className: "likhari-image-figure", "data-selected": isSelected ? 'true' : 'false', contentEditable: false, onDoubleClick: (e) => {
|
|
154
|
+
if (e.target === imageRef.current)
|
|
155
|
+
setDialog({});
|
|
156
|
+
}, onContextMenu: (e) => {
|
|
157
|
+
e.preventDefault();
|
|
158
|
+
clearSelection();
|
|
159
|
+
setSelected(true);
|
|
160
|
+
setMenu({ x: e.clientX, y: e.clientY });
|
|
161
|
+
}, children: [_jsxs("span", { className: "likhari-image-wrap", children: [_jsx("img", { ref: imageRef, className: "likhari-image", src: src, alt: altText, width: shownWidth, draggable: false }), isSelected && linkType === 'embedded' && (_jsx("span", { className: "likhari-image-resize-handle", role: "separator", "aria-label": strings.imageMenu.resizeImage, onPointerDown: onResizeDown, onPointerMove: onResizeMove, onPointerUp: onResizeUp, onPointerCancel: onResizeUp }))] }), caption && _jsx("figcaption", { className: "likhari-image-caption", children: caption }), _jsxs(Menu, { opened: menu !== null, onChange: (opened) => {
|
|
162
|
+
if (!opened)
|
|
163
|
+
setMenu(null);
|
|
164
|
+
}, position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 200, children: [_jsx(Menu.Target, { children: _jsx("span", { "aria-hidden": "true", style: { position: 'fixed', left: menu?.x ?? -9999, top: menu?.y ?? -9999, width: 1, height: 1, pointerEvents: 'none' } }) }), _jsxs(Menu.Dropdown, { children: [_jsx(Menu.Item, { leftSection: _jsx(IconPhotoEdit, { size: 16, stroke: 1.75 }), onClick: () => setDialog({}), children: strings.imageMenu.editImage }), linkType === 'linked' && options.allowEmbedded && (_jsx(Menu.Item, { leftSection: _jsx(IconPhotoDown, { size: 16, stroke: 1.75 }), onClick: () => void convertToEmbedded(), children: strings.imageMenu.convertToEmbedded })), linkType === 'embedded' && (_jsx(Menu.Item, { leftSection: _jsx(IconCrop, { size: 16, stroke: 1.75 }), onClick: () => setCropDialogOpen(true), children: strings.imageMenu.cropResize })), options.allowCaption && (_jsx(Menu.Item, { leftSection: _jsx(IconTextCaption, { size: 16, stroke: 1.75 }), onClick: () => setDialog({ intent: 'caption' }), children: caption ? strings.imageMenu.editCaption : strings.imageMenu.addCaption })), options.allowCaption && caption && (_jsx(Menu.Item, { leftSection: _jsx(IconX, { size: 16, stroke: 1.75 }), onClick: () => updateNode((node) => node.setCaption(null)), children: strings.imageMenu.removeCaption })), _jsx(Menu.Divider, {}), _jsx(Menu.Item, { color: "red", leftSection: _jsx(IconTrash, { size: 16, stroke: 1.75 }), onClick: removeImage, children: strings.imageMenu.deleteImage })] })] }), _jsx(ImageDialog, { mode: "edit", opened: dialog !== null, initial: { src, altText, caption, linkType }, intent: dialog?.intent, onSubmit: applyEdit, onClose: () => {
|
|
165
|
+
setDialog(null);
|
|
166
|
+
editor.focus();
|
|
167
|
+
} }), linkType === 'embedded' && (_jsx(ImageCropDialog, { opened: cropDialogOpen, initial: { src, width, height }, onSubmit: applyCrop, onClose: () => {
|
|
168
|
+
setCropDialogOpen(false);
|
|
169
|
+
editor.focus();
|
|
170
|
+
} }))] }));
|
|
171
|
+
}
|