@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
package/dist/EditorRoot.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { SerializedEditorState } from 'lexical';
|
|
|
3
3
|
import { type FormatId } from '@inshapardaz/likhari-converters';
|
|
4
4
|
import { type EditorFeatureConfig, type FeatureConfigPresetName } from '@inshapardaz/likhari-core';
|
|
5
5
|
import { type FontOption } from './fonts/index.js';
|
|
6
|
+
import { type Locale } from './i18n/index.js';
|
|
6
7
|
export interface EditorInitialContent {
|
|
7
8
|
format: Extract<FormatId, 'lexical-json' | 'plain-text'>;
|
|
8
9
|
value: string;
|
|
@@ -14,7 +15,15 @@ export interface EditorRootProps {
|
|
|
14
15
|
featurePreset?: FeatureConfigPresetName;
|
|
15
16
|
theme?: MantineThemeOverride;
|
|
16
17
|
colorScheme?: 'light' | 'dark';
|
|
17
|
-
|
|
18
|
+
/**
|
|
19
|
+
* A CSS color (e.g. `'#2B6E6E'`) overriding the editor's default accent —
|
|
20
|
+
* both Mantine's own primary color (buttons, portaled dropdowns' active-item
|
|
21
|
+
* highlight, etc.) and the `--editor-accent` / `--editor-accent-soft` CSS
|
|
22
|
+
* variables the toolbar/canvas use directly. Omit to use the built-in
|
|
23
|
+
* default tokens (packages/core/src/theme/tokens.ts).
|
|
24
|
+
*/
|
|
25
|
+
accentColor?: string;
|
|
26
|
+
locale?: Locale;
|
|
18
27
|
placeholder?: string;
|
|
19
28
|
/**
|
|
20
29
|
* CSS height for the editor box (toolbar + canvas together) — accepts any
|
|
@@ -38,6 +47,21 @@ export interface EditorRootProps {
|
|
|
38
47
|
* the unsaved-changes state) or to hide it while keeping `onSave`.
|
|
39
48
|
*/
|
|
40
49
|
showSave?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Stores an uploaded image and returns the URL to reference it by. Without
|
|
52
|
+
* it, uploaded images are embedded in the document as base64 data URIs —
|
|
53
|
+
* simple, but they bloat the document (see `images.maxSizeMB`).
|
|
54
|
+
*/
|
|
55
|
+
onImageUpload?: (file: File) => Promise<string>;
|
|
56
|
+
/**
|
|
57
|
+
* Downloads a linked image's bytes when converting it to an embedded copy
|
|
58
|
+
* or applying a crop/rotate/flip. Without it, the browser fetches the URL
|
|
59
|
+
* directly, which fails for any image server that doesn't send CORS
|
|
60
|
+
* headers — that restriction can't be worked around from the browser
|
|
61
|
+
* alone. Provide this to route the request through your own backend (or a
|
|
62
|
+
* CORS proxy) instead.
|
|
63
|
+
*/
|
|
64
|
+
fetchImage?: (url: string) => Promise<Blob>;
|
|
41
65
|
/**
|
|
42
66
|
* Entries for the toolbar's font-family dropdown. Defaults to
|
|
43
67
|
* `DEFAULT_FONT_OPTIONS` (generic Latin faces plus the Urdu/Arabic-script
|
package/dist/EditorRoot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAU1D,OAAO,KAAK,EAAe,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,EAAwB,KAAK,mBAAmB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAKzH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAIjE,OAAO,EAAgC,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,cAAc,GAAG,YAAY,CAAC,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAClD;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrD;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IACrC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IAClD,iBAAiB,IAAI,OAAO,CAAC;IAC7B,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,KAAK,IAAI,IAAI,CAAC;CACf;AAQD,eAAO,MAAM,UAAU,uGAkKrB,CAAC"}
|
package/dist/EditorRoot.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { forwardRef, useEffect, useId, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { LexicalComposer } from '@lexical/react/LexicalComposer';
|
|
4
4
|
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
|
|
5
5
|
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
|
|
6
6
|
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
|
|
7
7
|
import { ListPlugin } from '@lexical/react/LexicalListPlugin';
|
|
8
|
+
import { CheckListPlugin } from '@lexical/react/LexicalCheckListPlugin';
|
|
8
9
|
import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
|
|
9
10
|
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
|
|
10
11
|
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
|
|
@@ -16,20 +17,33 @@ import { EditorThemeProvider } from './theme/EditorThemeProvider.js';
|
|
|
16
17
|
import { Toolbar } from './components/Toolbar.js';
|
|
17
18
|
import { injectUrduWebFontsCss } from './fonts/index.js';
|
|
18
19
|
import { LinkPastePlugin } from './plugins/LinkPastePlugin.js';
|
|
20
|
+
import { ImageOptionsContext } from './image/ImageOptionsContext.js';
|
|
21
|
+
import { PortalTargetContext } from './PortalTargetContext.js';
|
|
22
|
+
import { UiStringsContext, getStrings } from './i18n/index.js';
|
|
19
23
|
function initialEditorStateJson(initialContent) {
|
|
20
24
|
if (!initialContent)
|
|
21
25
|
return undefined;
|
|
22
26
|
const state = defaultFormatRegistry.parse(initialContent.format, initialContent.value);
|
|
23
27
|
return JSON.stringify(state);
|
|
24
28
|
}
|
|
25
|
-
export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialContent, featureConfig, featurePreset, theme, colorScheme, locale = 'en', placeholder
|
|
29
|
+
export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialContent, featureConfig, featurePreset, theme, colorScheme, accentColor, locale = 'en', placeholder, height = '480px', onChange, onSave, showSave = Boolean(onSave), onImageUpload, fetchImage, fontOptions, }, ref) {
|
|
26
30
|
const config = useMemo(() => resolveFeatureConfig(featureConfig, featurePreset), [featureConfig, featurePreset]);
|
|
31
|
+
const strings = useMemo(() => getStrings(locale), [locale]);
|
|
32
|
+
const resolvedPlaceholder = placeholder ?? strings.editor.placeholder;
|
|
27
33
|
// The urdu-web-fonts stylesheets are needed for the font dropdown and for
|
|
28
34
|
// RTL content, whose canvas font (editor.css) is one of those families.
|
|
29
35
|
useEffect(() => {
|
|
30
36
|
if (config.font.family || locale !== 'en')
|
|
31
37
|
injectUrduWebFontsCss();
|
|
32
38
|
}, [config.font.family, locale]);
|
|
39
|
+
const imageOptions = useMemo(() => ({
|
|
40
|
+
allowLinked: config.images.linked,
|
|
41
|
+
allowEmbedded: config.images.embedded,
|
|
42
|
+
allowCaption: config.images.caption,
|
|
43
|
+
maxSizeMB: config.images.maxSizeMB,
|
|
44
|
+
onImageUpload,
|
|
45
|
+
fetchImage,
|
|
46
|
+
}), [config.images.linked, config.images.embedded, config.images.caption, config.images.maxSizeMB, onImageUpload, fetchImage]);
|
|
33
47
|
const editorStateRef = useRef(null);
|
|
34
48
|
const lastSavedJsonRef = useRef(null);
|
|
35
49
|
const [isDirty, setIsDirty] = useState(false);
|
|
@@ -68,12 +82,12 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
|
|
|
68
82
|
return true;
|
|
69
83
|
if (typeof window === 'undefined')
|
|
70
84
|
return true;
|
|
71
|
-
return window.confirm(
|
|
85
|
+
return window.confirm(strings.editor.confirmDiscard);
|
|
72
86
|
},
|
|
73
87
|
focus() {
|
|
74
88
|
rootElementRef.current?.focus();
|
|
75
89
|
},
|
|
76
|
-
}), [isDirty]);
|
|
90
|
+
}), [isDirty, strings]);
|
|
77
91
|
const rootElementRef = useRef(null);
|
|
78
92
|
const handleChange = (state) => {
|
|
79
93
|
editorStateRef.current = state;
|
|
@@ -92,5 +106,10 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
|
|
|
92
106
|
onSave?.(content, format);
|
|
93
107
|
};
|
|
94
108
|
const dir = locale === 'en' ? 'ltr' : 'rtl';
|
|
95
|
-
|
|
109
|
+
// A stable per-instance id for the portal-anchor div below, so multiple
|
|
110
|
+
// EditorRoot instances on one page each get their own portal target
|
|
111
|
+
// rather than colliding on a shared one.
|
|
112
|
+
const portalTargetId = useId();
|
|
113
|
+
const portalTargetSelector = `#${CSS.escape(portalTargetId)}`;
|
|
114
|
+
return (_jsx(EditorThemeProvider, { theme: theme, colorScheme: colorScheme, accentColor: accentColor, scopeElementId: portalTargetId, children: _jsxs("div", { className: "likhari-root", dir: dir, ref: rootElementRef, "data-document-id": documentId, style: { height: typeof height === 'number' ? `${height}px` : height }, children: [_jsx("div", { id: portalTargetId, className: "likhari-portal-target" }), _jsx(PortalTargetContext.Provider, { value: portalTargetSelector, children: _jsx(UiStringsContext.Provider, { value: strings, children: _jsx(ImageOptionsContext.Provider, { value: imageOptions, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Toolbar, { config: config, onSave: handleSave, isDirty: isDirty, showSave: showSave, fontOptions: fontOptions, direction: dir, locale: locale }), _jsx("div", { className: "likhari-canvas", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "likhari-content-editable", dir: dir, "aria-label": strings.editor.contentLabel }), placeholder: _jsx("div", { className: "likhari-placeholder", children: resolvedPlaceholder }), ErrorBoundary: LexicalErrorBoundary }) }), config.history && _jsx(HistoryPlugin, {}), (config.lists.bullet || config.lists.numbered || config.lists.check) && _jsx(ListPlugin, {}), config.lists.check && _jsx(CheckListPlugin, {}), config.links && _jsx(LinkPlugin, {}), config.links && _jsx(LinkPastePlugin, {}), _jsx(OnChangePlugin, { onChange: handleChange })] }) }) }) })] }) }));
|
|
96
115
|
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS selector for the portal-anchor `<div>` `EditorRoot` renders as the
|
|
3
|
+
* first child of `.likhari-root` (see EditorRoot.tsx). Mantine's `Menu`,
|
|
4
|
+
* `Modal`, `Select`'s combobox and `Tooltip` all default to portaling their
|
|
5
|
+
* content to `document.body` — outside the DOM subtree that carries the
|
|
6
|
+
* `--editor-*` CSS custom properties (`.likhari-theme-scope`) and the `dir`
|
|
7
|
+
* attribute (`.likhari-root`), so none of that styling/direction reaches
|
|
8
|
+
* them. Passing this selector as the target fixes that by portaling into a
|
|
9
|
+
* genuine descendant of both instead.
|
|
10
|
+
*
|
|
11
|
+
* `undefined` (the default, outside any `EditorRoot`, or before it has
|
|
12
|
+
* mounted) falls back to Mantine's own default portal behavior.
|
|
13
|
+
*/
|
|
14
|
+
export declare const PortalTargetContext: import("react").Context<string | undefined>;
|
|
15
|
+
export declare function usePortalTarget(): string | undefined;
|
|
16
|
+
//# sourceMappingURL=PortalTargetContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PortalTargetContext.d.ts","sourceRoot":"","sources":["../src/PortalTargetContext.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,6CAA+C,CAAC;AAEhF,wBAAgB,eAAe,IAAI,MAAM,GAAG,SAAS,CAEpD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* CSS selector for the portal-anchor `<div>` `EditorRoot` renders as the
|
|
4
|
+
* first child of `.likhari-root` (see EditorRoot.tsx). Mantine's `Menu`,
|
|
5
|
+
* `Modal`, `Select`'s combobox and `Tooltip` all default to portaling their
|
|
6
|
+
* content to `document.body` — outside the DOM subtree that carries the
|
|
7
|
+
* `--editor-*` CSS custom properties (`.likhari-theme-scope`) and the `dir`
|
|
8
|
+
* attribute (`.likhari-root`), so none of that styling/direction reaches
|
|
9
|
+
* them. Passing this selector as the target fixes that by portaling into a
|
|
10
|
+
* genuine descendant of both instead.
|
|
11
|
+
*
|
|
12
|
+
* `undefined` (the default, outside any `EditorRoot`, or before it has
|
|
13
|
+
* mounted) falls back to Mantine's own default portal behavior.
|
|
14
|
+
*/
|
|
15
|
+
export const PortalTargetContext = createContext(undefined);
|
|
16
|
+
export function usePortalTarget() {
|
|
17
|
+
return useContext(PortalTargetContext);
|
|
18
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LinkDialog.d.ts","sourceRoot":"","sources":["../../src/components/LinkDialog.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LinkDialog.d.ts","sourceRoot":"","sources":["../../src/components/LinkDialog.tsx"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACxD,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;gDACgD;AAChD,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,eAAe,+BAyE7G"}
|
|
@@ -2,9 +2,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { Button, Group, Modal, TextInput } from '@mantine/core';
|
|
4
4
|
import { normalizeLinkUrl } from '../utils/linkUrl.js';
|
|
5
|
+
import { useUiStrings } from '../i18n/useStrings.js';
|
|
6
|
+
import { usePortalTarget } from '../PortalTargetContext.js';
|
|
5
7
|
/** Insert/edit-link dialog (UI spec §6). Mantine Modal supplies focus
|
|
6
8
|
* trapping, Escape-to-close and the overlay. */
|
|
7
9
|
export function LinkDialog({ opened, initialUrl, showTextField, onSubmit, onRemove, onClose }) {
|
|
10
|
+
const strings = useUiStrings();
|
|
11
|
+
const portalTarget = usePortalTarget();
|
|
8
12
|
const [url, setUrl] = useState(initialUrl);
|
|
9
13
|
const [text, setText] = useState('');
|
|
10
14
|
const [error, setError] = useState(null);
|
|
@@ -19,13 +23,13 @@ export function LinkDialog({ opened, initialUrl, showTextField, onSubmit, onRemo
|
|
|
19
23
|
e.preventDefault();
|
|
20
24
|
const normalized = normalizeLinkUrl(url);
|
|
21
25
|
if (!normalized) {
|
|
22
|
-
setError(
|
|
26
|
+
setError(strings.linkDialog.invalidUrl);
|
|
23
27
|
return;
|
|
24
28
|
}
|
|
25
29
|
onSubmit({ url: normalized, text: text.trim() || normalized });
|
|
26
30
|
};
|
|
27
|
-
return (_jsx(Modal, { opened: opened, onClose: onClose, title: onRemove ?
|
|
31
|
+
return (_jsx(Modal, { opened: opened, onClose: onClose, title: onRemove ? strings.linkDialog.titleEdit : strings.linkDialog.titleInsert, centered: true, size: "sm", portalProps: { target: portalTarget }, children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TextInput, { label: strings.linkDialog.urlLabel, placeholder: strings.linkDialog.urlPlaceholder, value: url, onChange: (e) => {
|
|
28
32
|
setUrl(e.currentTarget.value);
|
|
29
33
|
setError(null);
|
|
30
|
-
}, error: error, "data-autofocus": true }), showTextField && (_jsx(TextInput, { mt: "sm", label:
|
|
34
|
+
}, error: error, "data-autofocus": true }), showTextField && (_jsx(TextInput, { mt: "sm", label: strings.linkDialog.textLabel, placeholder: strings.linkDialog.textPlaceholder, value: text, onChange: (e) => setText(e.currentTarget.value) })), _jsxs(Group, { justify: "space-between", mt: "md", children: [onRemove ? (_jsx(Button, { variant: "subtle", color: "red", onClick: onRemove, children: strings.link.removeLink })) : (_jsx("span", {})), _jsxs(Group, { gap: "xs", children: [_jsx(Button, { variant: "default", onClick: onClose, children: strings.common.cancel }), _jsx(Button, { type: "submit", children: strings.linkDialog.apply })] })] })] }) }));
|
|
31
35
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ResolvedEditorFeatureConfig } from '@inshapardaz/likhari-core';
|
|
2
2
|
import { type FontOption } from '../fonts/index.js';
|
|
3
|
+
import type { Locale } from '../i18n/strings.js';
|
|
3
4
|
export interface ToolbarProps {
|
|
4
5
|
config: ResolvedEditorFeatureConfig;
|
|
5
6
|
onSave?: () => void;
|
|
@@ -9,6 +10,8 @@ export interface ToolbarProps {
|
|
|
9
10
|
fontOptions?: FontOption[];
|
|
10
11
|
/** Text direction of the canvas; picks which default font and size are pre-selected. */
|
|
11
12
|
direction?: 'ltr' | 'rtl';
|
|
13
|
+
/** UI locale — picks the translated strings for labels, tooltips and menu items. */
|
|
14
|
+
locale?: Locale;
|
|
12
15
|
}
|
|
13
|
-
export declare function Toolbar({ config, onSave, isDirty, showSave, fontOptions, direction }: ToolbarProps): import("react").JSX.Element;
|
|
16
|
+
export declare function Toolbar({ config, onSave, isDirty, showSave, fontOptions, direction, locale }: ToolbarProps): import("react").JSX.Element;
|
|
14
17
|
//# sourceMappingURL=Toolbar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAA6D,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAItG,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,iBAAiB,CAAC;AAqUvD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,2BAA2B,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,wFAAwF;IACxF,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAkC,EAAE,SAAiB,EAAE,MAAa,EAAE,EAAE,YAAY,+BA8wBhJ"}
|