@inshapardaz/likhari-react 0.1.21-dev.196 → 0.1.21
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 +0 -3
- package/dist/EditorRoot.d.ts.map +1 -1
- package/dist/EditorRoot.js +4 -14
- package/dist/components/Toolbar.d.ts +1 -7
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +2 -2
- package/dist/find/findReplaceActions.d.ts +0 -13
- package/dist/find/findReplaceActions.d.ts.map +1 -1
- package/dist/find/findReplaceActions.js +2 -2
- package/dist/i18n/strings.d.ts +0 -24
- package/dist/i18n/strings.d.ts.map +1 -1
- package/dist/i18n/strings.js +5 -77
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/theme/editor.css +0 -185
- package/package.json +1 -1
- package/dist/autocorrect/AutoCorrectPlugin.d.ts +0 -14
- package/dist/autocorrect/AutoCorrectPlugin.d.ts.map +0 -1
- package/dist/autocorrect/AutoCorrectPlugin.js +0 -68
- package/dist/autocorrect/autoCorrectActions.d.ts +0 -8
- package/dist/autocorrect/autoCorrectActions.d.ts.map +0 -1
- package/dist/autocorrect/autoCorrectActions.js +0 -42
- package/dist/autocorrect/autoCorrectStores.d.ts +0 -52
- package/dist/autocorrect/autoCorrectStores.d.ts.map +0 -1
- package/dist/autocorrect/autoCorrectStores.js +0 -115
- package/dist/components/AutoCorrectPanel.d.ts +0 -15
- package/dist/components/AutoCorrectPanel.d.ts.map +0 -1
- package/dist/components/AutoCorrectPanel.js +0 -44
- package/dist/components/SpellcheckPanel.d.ts +0 -13
- package/dist/components/SpellcheckPanel.d.ts.map +0 -1
- package/dist/components/SpellcheckPanel.js +0 -82
- package/dist/spellcheck/SpellHighlightPlugin.d.ts +0 -8
- package/dist/spellcheck/SpellHighlightPlugin.d.ts.map +0 -1
- package/dist/spellcheck/SpellHighlightPlugin.js +0 -57
- package/dist/spellcheck/spellcheckActions.d.ts +0 -21
- package/dist/spellcheck/spellcheckActions.d.ts.map +0 -1
- package/dist/spellcheck/spellcheckActions.js +0 -38
package/dist/EditorRoot.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ 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
6
|
import { type DraftRestoreMode } from './components/DraftRestore.js';
|
|
7
|
-
import { type AutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
8
7
|
import { type Locale } from './i18n/index.js';
|
|
9
8
|
/** What happens when the user is about to leave with unsaved changes. */
|
|
10
9
|
export type NavigationGuardMode = 'confirm' | 'save-draft' | 'off';
|
|
@@ -14,8 +13,6 @@ export interface EditorInitialContent {
|
|
|
14
13
|
}
|
|
15
14
|
export interface EditorRootProps {
|
|
16
15
|
documentId?: string;
|
|
17
|
-
/** Where auto-corrections are loaded from and saved to, in priority order. Pass a stable array. */
|
|
18
|
-
autoCorrectStores?: AutoCorrectStore[];
|
|
19
16
|
initialContent?: EditorInitialContent;
|
|
20
17
|
featureConfig?: EditorFeatureConfig;
|
|
21
18
|
featurePreset?: FeatureConfigPresetName;
|
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;AAY1D,OAAO,KAAK,EAA8B,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEjF,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;AAOjE,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAY1D,OAAO,KAAK,EAA8B,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEjF,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;AAOjE,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAahF,OAAO,EAAgC,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAMnE,yEAAyE;AACzE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,YAAY,GAAG,KAAK,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,QAAQ,CAAC;IACjB,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;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,uGAAuG;IACvG,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3E,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,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,uGA2XrB,CAAC"}
|
package/dist/EditorRoot.js
CHANGED
|
@@ -27,11 +27,6 @@ import { PoetryPlugin } from './plugins/PoetryPlugin.js';
|
|
|
27
27
|
import { PoetryResizer } from './blocks/PoetryResizer.js';
|
|
28
28
|
import { DraftRestore } from './components/DraftRestore.js';
|
|
29
29
|
import { FindReplaceBar } from './components/FindReplaceBar.js';
|
|
30
|
-
import { AutoCorrectPanel } from './components/AutoCorrectPanel.js';
|
|
31
|
-
import { AutoCorrectPlugin } from './autocorrect/AutoCorrectPlugin.js';
|
|
32
|
-
import { localStorageAutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
33
|
-
import { SpellcheckPanel } from './components/SpellcheckPanel.js';
|
|
34
|
-
import { SpellHighlightPlugin } from './spellcheck/SpellHighlightPlugin.js';
|
|
35
30
|
import { LeaveDialog } from './components/LeaveDialog.js';
|
|
36
31
|
import { clearDraft, createDraftId, hasDraftContent, pruneDrafts, writeDraft, } from './persistence/draftStorage.js';
|
|
37
32
|
import { ImageOptionsContext } from './image/ImageOptionsContext.js';
|
|
@@ -40,15 +35,13 @@ import { UiStringsContext, getStrings } from './i18n/index.js';
|
|
|
40
35
|
const DEFAULT_AUTOSAVE_DELAY_MS = 750;
|
|
41
36
|
const DEFAULT_AUTOSAVE_MAX_BYTES = 2000000;
|
|
42
37
|
const DEFAULT_AUTOSAVE_MAX_DRAFTS = 20;
|
|
43
|
-
/** Used when the host passes no stores: corrections are kept in this browser. */
|
|
44
|
-
const DEFAULT_AUTOCORRECT_STORES = [localStorageAutoCorrectStore()];
|
|
45
38
|
function initialEditorStateJson(initialContent) {
|
|
46
39
|
if (!initialContent)
|
|
47
40
|
return undefined;
|
|
48
41
|
const state = defaultFormatRegistry.parse(initialContent.format, initialContent.value);
|
|
49
42
|
return JSON.stringify(state);
|
|
50
43
|
}
|
|
51
|
-
export const EditorRoot = forwardRef(function EditorRoot({ documentId,
|
|
44
|
+
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, autosave = true, restoreDraft = 'prompt', navigationGuard = 'confirm', onDraftRestored, autosaveDelayMs = DEFAULT_AUTOSAVE_DELAY_MS, autosaveMaxBytes = DEFAULT_AUTOSAVE_MAX_BYTES, autosaveMaxDrafts = DEFAULT_AUTOSAVE_MAX_DRAFTS, }, ref) {
|
|
52
45
|
const config = useMemo(() => resolveFeatureConfig(featureConfig, featurePreset), [featureConfig, featurePreset]);
|
|
53
46
|
const strings = useMemo(() => getStrings(locale), [locale]);
|
|
54
47
|
const resolvedPlaceholder = placeholder ?? strings.editor.placeholder;
|
|
@@ -75,10 +68,7 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, autoCorre
|
|
|
75
68
|
const editorStateRef = useRef(null);
|
|
76
69
|
const lastSavedJsonRef = useRef(null);
|
|
77
70
|
const [isDirty, setIsDirty] = useState(false);
|
|
78
|
-
const [
|
|
79
|
-
const [autoCorrectVersion, setAutoCorrectVersion] = useState(0);
|
|
80
|
-
const stores = autoCorrectStores ?? DEFAULT_AUTOCORRECT_STORES;
|
|
81
|
-
const togglePanel = (panel) => setOpenPanel((current) => (current === panel ? null : panel));
|
|
71
|
+
const [findOpen, setFindOpen] = useState(false);
|
|
82
72
|
const isDirtyRef = useRef(isDirty);
|
|
83
73
|
isDirtyRef.current = isDirty;
|
|
84
74
|
const autosaveTimerRef = useRef(null);
|
|
@@ -291,9 +281,9 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, autoCorre
|
|
|
291
281
|
// rather than colliding on a shared one.
|
|
292
282
|
const portalTargetId = useId();
|
|
293
283
|
const portalTargetSelector = `#${CSS.escape(portalTargetId)}`;
|
|
294
|
-
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: _jsxs(UiStringsContext.Provider, { value: strings, children: [_jsx(ImageOptionsContext.Provider, { value: imageOptions, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Toolbar, { config: config, onSave: handleSave, findOpen:
|
|
284
|
+
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: _jsxs(UiStringsContext.Provider, { value: strings, children: [_jsx(ImageOptionsContext.Provider, { value: imageOptions, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Toolbar, { config: config, onSave: handleSave, findOpen: findOpen, onToggleFind: () => setFindOpen((v) => !v), isDirty: isDirty, showSave: showSave, fontOptions: fontOptions, direction: dir, locale: locale, drafts: autosave
|
|
295
285
|
? { currentId: draftId, maxBytes: autosaveMaxBytes, adoptOnRestore: !documentId, onRestored: handleDraftRestored }
|
|
296
|
-
: undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsxs("div", { className: "likhari-canvas-frame", children: [config.findReplace &&
|
|
286
|
+
: undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsxs("div", { className: "likhari-canvas-frame", children: [config.findReplace && findOpen && _jsx(FindReplaceBar, { strings: strings, dir: dir, onClose: () => setFindOpen(false) }), _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, {}), config.blocks.pageBreak && _jsx(PageBreakPlugin, {}), config.columns && _jsx(LayoutPlugin, {}), config.footnotes && _jsx(FootnotePlugin, {}), config.poetry.enabled && _jsx(PoetryPlugin, {}), config.poetry.enabled && _jsx(PoetryResizer, {}), config.tables && _jsx(TablePlugin, { hasCellMerge: true, hasTabHandler: true }), config.blocks.horizontalRule && _jsx(HorizontalRulePlugin, {}), _jsx(EditorInstancePlugin, { instanceRef: editorInstanceRef }), _jsx(OnChangePlugin, { onChange: handleChange })] }) }), _jsx(LeaveDialog, { opened: leavePrompt !== null, canSave: Boolean(onSave), canSaveDraft: autosave || navigationGuard === 'save-draft', draftFailed: leavePrompt?.draftFailed ?? false, onSave: () => {
|
|
297
287
|
handleSave();
|
|
298
288
|
settleLeave(true);
|
|
299
289
|
}, onSaveDraft: () => {
|
|
@@ -7,12 +7,6 @@ export interface ToolbarProps {
|
|
|
7
7
|
/** Whether the find-and-replace widget is open, and how to toggle it (owned by EditorRoot). */
|
|
8
8
|
findOpen?: boolean;
|
|
9
9
|
onToggleFind?: () => void;
|
|
10
|
-
/** Whether the spellcheck panel is open, and how to toggle it (owned by EditorRoot). */
|
|
11
|
-
spellOpen?: boolean;
|
|
12
|
-
onToggleSpell?: () => void;
|
|
13
|
-
/** Whether the add-auto-correction panel is open, and how to toggle it (owned by EditorRoot). */
|
|
14
|
-
autoCorrectOpen?: boolean;
|
|
15
|
-
onToggleAutoCorrect?: () => void;
|
|
16
10
|
onSave?: () => void;
|
|
17
11
|
isDirty?: boolean;
|
|
18
12
|
showSave?: boolean;
|
|
@@ -25,5 +19,5 @@ export interface ToolbarProps {
|
|
|
25
19
|
/** Autosave drafts: when set, the toolbar offers a Drafts button that lists and restores them. */
|
|
26
20
|
drafts?: DraftsToolbarOptions;
|
|
27
21
|
}
|
|
28
|
-
export declare function Toolbar({ config, onSave, isDirty, showSave, findOpen, onToggleFind,
|
|
22
|
+
export declare function Toolbar({ config, onSave, isDirty, showSave, findOpen, onToggleFind, fontOptions, direction, locale, drafts }: ToolbarProps): import("react").JSX.Element;
|
|
29
23
|
//# sourceMappingURL=Toolbar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AAqFA,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,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;AA+gBvD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,2BAA2B,CAAC;IACpC,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,
|
|
1
|
+
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AAqFA,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,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;AA+gBvD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,2BAA2B,CAAC;IACpC,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,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;IAChB,kGAAkG;IAClG,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAED,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAgB,EAAE,YAAY,EAAE,WAAkC,EAAE,SAAiB,EAAE,MAAa,EAAE,MAAM,EAAE,EAAE,YAAY,+BAskCxL"}
|
|
@@ -182,7 +182,7 @@ function PoetryMenuItems({ strings, layout, scale, centered, onAction, }) {
|
|
|
182
182
|
};
|
|
183
183
|
return (_jsxs(_Fragment, { children: [_jsx(Menu.Label, { children: t.menuLabel }), item(IconColumns1, t.singleColumn, setLayout('single'), layout === 'single'), item(IconColumns2, t.twoColumn, setLayout('two-column'), layout === 'two-column'), item(IconArrowsShuffle, t.staggered, setLayout('staggered'), layout === 'staggered'), _jsx(Menu.Divider, {}), _jsx(Menu.Divider, {}), item(IconRowInsertTop, t.insertCoupletBefore, () => $insertCoupletRelativeToSelection('before')), item(IconRowInsertBottom, t.insertCoupletAfter, () => $insertCoupletRelativeToSelection('after')), item(IconArrowsMinimize, t.tighterSpacing, () => $adjustPoetrySpacing(-1), !canStep(POETRY_SPACINGS, scale.spacing, -1)), item(IconArrowsMaximize, t.looserSpacing, () => $adjustPoetrySpacing(1), !canStep(POETRY_SPACINGS, scale.spacing, 1)), layout === 'staggered' && (_jsxs(_Fragment, { children: [item(IconArrowsMinimize, t.narrowerCouplets, () => $adjustPoetryStagger(-1), !canStep(POETRY_STAGGERS, scale.stagger, -1)), item(IconArrowsMaximize, t.widerCouplets, () => $adjustPoetryStagger(1), !canStep(POETRY_STAGGERS, scale.stagger, 1))] })), layout === 'two-column' && (_jsxs(_Fragment, { children: [item(IconAlignCenter, centered ? t.uncenterCouplet : t.centerCouplet, () => $setCoupletCentered(!centered)), item(IconColumns2, t.narrowerGutter, () => $adjustPoetryGutter(-1), !canStep(POETRY_GUTTERS, scale.gutter, -1)), item(IconColumns2, t.widerGutter, () => $adjustPoetryGutter(1), !canStep(POETRY_GUTTERS, scale.gutter, 1))] })), item(IconTrash, t.deleteCouplet, $deletePoetryCouplet, false, 'red'), item(IconTrash, t.deletePoetry, $deletePoetryBlock, false, 'red')] }));
|
|
184
184
|
}
|
|
185
|
-
export function Toolbar({ config, onSave, isDirty, showSave, findOpen = false, onToggleFind,
|
|
185
|
+
export function Toolbar({ config, onSave, isDirty, showSave, findOpen = false, onToggleFind, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
|
|
186
186
|
const [editor] = useLexicalComposerContext();
|
|
187
187
|
const [state, setState] = useState(INITIAL_STATE);
|
|
188
188
|
const strings = useStrings(locale);
|
|
@@ -811,7 +811,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, findOpen = false, o
|
|
|
811
811
|
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.tables && _jsx(ToolbarButton, { icon: IconTable, title: strings.toolbar.insertTable, onClick: openTableDialog }), config.columns && _jsx(ToolbarButton, { icon: IconColumns, title: strings.toolbar.insertColumns, onClick: openLayoutDialog }), config.footnotes && (_jsx(ToolbarButton, { icon: IconNumber1Small, title: strings.toolbar.insertFootnote, onClick: () => editor.dispatchCommand(INSERT_FOOTNOTE_COMMAND, undefined) })), config.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.findReplace && (_jsx(ToolbarButton, { icon: IconSearch, title: strings.findReplace.toggle, active: findOpen, onClick: onToggleFind })), config.poetry.enabled && locale !== 'en' && (_jsx(ToolbarButton, { icon: IconFeather, title: strings.toolbar.insertPoetryCouplet, onClick: () => editor.dispatchCommand(INSERT_POETRY_COUPLET_COMMAND, { layout: config.poetry.defaultLayout }) }))] }, "stubInsert")),
|
|
812
812
|
config.tables && state.inTable && (_jsx("div", { className: "likhari-toolbar-group", children: _jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 240, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx("button", { type: "button", className: "likhari-toolbar-button", "data-active": "true", "aria-pressed": "true", "aria-haspopup": "menu", "aria-label": strings.toolbar.tableOptions, title: strings.toolbar.tableOptions, onMouseDown: (e) => e.preventDefault(), children: _jsx(IconTableOptions, { size: ICON_SIZE, stroke: ICON_STROKE }) }) }), _jsx(Menu.Dropdown, { children: _jsx(TableMenuItems, { strings: strings, direction: direction, rows: state.tableRows, columns: state.tableColumns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction }) })] }) }, "tableActions")),
|
|
813
813
|
config.poetry.enabled && state.inPoetry && (_jsx("div", { className: "likhari-toolbar-group", children: _jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 200, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx("button", { type: "button", className: "likhari-toolbar-button", "data-active": "true", "aria-pressed": "true", "aria-haspopup": "menu", "aria-label": strings.toolbar.poetryOptions, title: strings.toolbar.poetryOptions, onMouseDown: (e) => e.preventDefault(), children: _jsx(IconFeather, { size: ICON_SIZE, stroke: ICON_STROKE }) }) }), _jsx(Menu.Dropdown, { children: _jsx(PoetryMenuItems, { strings: strings, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction }) })] }) }, "poetryActions")),
|
|
814
|
-
showLanguageGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [config.language.autocorrect &&
|
|
814
|
+
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")),
|
|
815
815
|
];
|
|
816
816
|
return (_jsxs("div", { className: "likhari-toolbar", role: "toolbar", "aria-label": strings.toolbar.ariaLabel, ref: toolbarContainerRef, children: [fixedGroups, movableGroups
|
|
817
817
|
.filter((group) => !overflowGroupKeys.has(group.key))
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type TextNode } from 'lexical';
|
|
2
1
|
/** A match as a Lexical selection range: start and end points, each in a text node. */
|
|
3
2
|
export interface FindMatch {
|
|
4
3
|
anchorKey: string;
|
|
@@ -6,18 +5,6 @@ export interface FindMatch {
|
|
|
6
5
|
focusKey: string;
|
|
7
6
|
focusOffset: number;
|
|
8
7
|
}
|
|
9
|
-
/**
|
|
10
|
-
* Text nodes grouped by their parent, in document order. A match is searched
|
|
11
|
-
* for within one parent only, so it never spans two paragraphs or table
|
|
12
|
-
* cells, but it can span the several text nodes that formatting splits a
|
|
13
|
-
* paragraph into.
|
|
14
|
-
*/
|
|
15
|
-
export declare function $textGroups(): TextNode[][];
|
|
16
|
-
/** The text node and offset that a character index in a group falls in. */
|
|
17
|
-
export declare function $locate(group: TextNode[], index: number, end: boolean): {
|
|
18
|
-
key: string;
|
|
19
|
-
offset: number;
|
|
20
|
-
};
|
|
21
8
|
/** Every non-overlapping occurrence of `query` in the document, case-sensitive. */
|
|
22
9
|
export declare function $findMatches(query: string): FindMatch[];
|
|
23
10
|
/** Makes the match the editor's selection, so it's highlighted and scrolled to. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findReplaceActions.d.ts","sourceRoot":"","sources":["../../src/find/findReplaceActions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"findReplaceActions.d.ts","sourceRoot":"","sources":["../../src/find/findReplaceActions.ts"],"names":[],"mappings":"AAEA,uFAAuF;AACvF,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAgCD,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,CAcvD;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAKnD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAMzE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAItE"}
|
|
@@ -5,7 +5,7 @@ import { $createRangeSelection, $getRoot, $getSelection, $isRangeSelection, $set
|
|
|
5
5
|
* cells, but it can span the several text nodes that formatting splits a
|
|
6
6
|
* paragraph into.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
function $textGroups() {
|
|
9
9
|
const groups = new Map();
|
|
10
10
|
for (const node of $getRoot().getAllTextNodes()) {
|
|
11
11
|
const parentKey = node.getParentOrThrow().getKey();
|
|
@@ -18,7 +18,7 @@ export function $textGroups() {
|
|
|
18
18
|
return [...groups.values()];
|
|
19
19
|
}
|
|
20
20
|
/** The text node and offset that a character index in a group falls in. */
|
|
21
|
-
|
|
21
|
+
function $locate(group, index, end) {
|
|
22
22
|
let start = 0;
|
|
23
23
|
for (const node of group) {
|
|
24
24
|
const length = node.getTextContent().length;
|
package/dist/i18n/strings.d.ts
CHANGED
|
@@ -169,30 +169,6 @@ export interface Strings {
|
|
|
169
169
|
noMatches: string;
|
|
170
170
|
close: string;
|
|
171
171
|
};
|
|
172
|
-
spellcheck: {
|
|
173
|
-
title: string;
|
|
174
|
-
language: string;
|
|
175
|
-
check: string;
|
|
176
|
-
close: string;
|
|
177
|
-
noDictionary: string;
|
|
178
|
-
noMisspellings: string;
|
|
179
|
-
previous: string;
|
|
180
|
-
next: string;
|
|
181
|
-
noSuggestions: string;
|
|
182
|
-
};
|
|
183
|
-
autoCorrect: {
|
|
184
|
-
title: string;
|
|
185
|
-
language: string;
|
|
186
|
-
from: string;
|
|
187
|
-
fromPlaceholder: string;
|
|
188
|
-
to: string;
|
|
189
|
-
toPlaceholder: string;
|
|
190
|
-
save: string;
|
|
191
|
-
saved: string;
|
|
192
|
-
noWritableStore: string;
|
|
193
|
-
failed: string;
|
|
194
|
-
close: string;
|
|
195
|
-
};
|
|
196
172
|
link: {
|
|
197
173
|
menuLabel: string;
|
|
198
174
|
noUrl: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;+DAC+D;AAC/D,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,cAAc,CAAC;AAElD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE;QACN,mGAAmG;QACnG,WAAW,EAAE,MAAM,CAAC;QACpB,gDAAgD;QAChD,YAAY,EAAE,MAAM,CAAC;QACrB,sEAAsE;QACtE,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,MAAM,EAAE;QACN,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,OAAO,EAAE;QACP,gEAAgE;QAChE,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,0CAA0C;QAC1C,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,QAAQ,EAAE,MAAM,CAAC;QACjB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,8FAA8F;QAC9F,YAAY,EAAE,MAAM,CAAC;QACrB,0GAA0G;QAC1G,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;QACtC,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,iBAAiB,EAAE;YACjB,SAAS,EAAE,MAAM,CAAC;YAClB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;YACnC,YAAY,EAAE,MAAM,CAAC;YACrB,UAAU,EAAE,MAAM,CAAC;YACnB,QAAQ,EAAE,MAAM,CAAC;YACjB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;QACF,YAAY,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,GAAG,EAAE,MAAM,CAAC;YACZ,OAAO,EAAE,MAAM,CAAC;YAChB,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;KACH,CAAC;IACF,uIAAuI;IACvI,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,2FAA2F;QAC3F,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,oGAAoG;IACpG,MAAM,EAAE;QACN,0GAA0G;QAC1G,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;QACxC,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,2DAA2D;QAC3D,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;QACtC,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;QACzC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;QAClC,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;QAC7B,aAAa,EAAE,MAAM,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,yEAAyE;IACzE,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,2EAA2E;QAC3E,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,UAAU,EAAE;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,gBAAgB,EAAE,MAAM,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;QACtB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,WAAW,EAAE;QACX,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,eAAe,EAAE,MAAM,CAAC;QACxB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,
|
|
1
|
+
{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/strings.js
CHANGED
|
@@ -152,30 +152,6 @@ const en = {
|
|
|
152
152
|
noMatches: 'No matches',
|
|
153
153
|
close: 'Close',
|
|
154
154
|
},
|
|
155
|
-
spellcheck: {
|
|
156
|
-
title: 'Spell check',
|
|
157
|
-
language: 'Language',
|
|
158
|
-
check: 'Check',
|
|
159
|
-
close: 'Close',
|
|
160
|
-
noDictionary: 'No dictionary installed',
|
|
161
|
-
noMisspellings: 'No misspellings found',
|
|
162
|
-
previous: 'Previous',
|
|
163
|
-
next: 'Next',
|
|
164
|
-
noSuggestions: 'No suggestions',
|
|
165
|
-
},
|
|
166
|
-
autoCorrect: {
|
|
167
|
-
title: 'Auto-correct',
|
|
168
|
-
language: 'Language',
|
|
169
|
-
from: 'Typed word',
|
|
170
|
-
fromPlaceholder: 'Word as typed',
|
|
171
|
-
to: 'Corrected word',
|
|
172
|
-
toPlaceholder: 'Correct it to',
|
|
173
|
-
save: 'Save correction',
|
|
174
|
-
saved: 'Saved. It applies to the next word typed.',
|
|
175
|
-
noWritableStore: 'No store accepts new corrections',
|
|
176
|
-
failed: 'Could not save the correction',
|
|
177
|
-
close: 'Close',
|
|
178
|
-
},
|
|
179
155
|
link: {
|
|
180
156
|
menuLabel: 'Link',
|
|
181
157
|
noUrl: '(no URL)',
|
|
@@ -409,30 +385,6 @@ const ur = {
|
|
|
409
385
|
noMatches: 'کوئی میچ نہیں',
|
|
410
386
|
close: 'بند کریں',
|
|
411
387
|
},
|
|
412
|
-
spellcheck: {
|
|
413
|
-
title: 'ہجے کی جانچ',
|
|
414
|
-
language: 'زبان',
|
|
415
|
-
check: 'جانچیں',
|
|
416
|
-
close: 'بند کریں',
|
|
417
|
-
noDictionary: 'کوئی لغت نصب نہیں',
|
|
418
|
-
noMisspellings: 'کوئی غلط ہجے نہیں ملے',
|
|
419
|
-
previous: 'پچھلا',
|
|
420
|
-
next: 'اگلا',
|
|
421
|
-
noSuggestions: 'کوئی تجویز نہیں',
|
|
422
|
-
},
|
|
423
|
-
autoCorrect: {
|
|
424
|
-
title: 'خودکار تصحیح',
|
|
425
|
-
language: 'زبان',
|
|
426
|
-
from: 'لکھا ہوا لفظ',
|
|
427
|
-
fromPlaceholder: 'جو لفظ لکھا جاتا ہے',
|
|
428
|
-
to: 'درست لفظ',
|
|
429
|
-
toPlaceholder: 'اسے درست کریں',
|
|
430
|
-
save: 'تصحیح محفوظ کریں',
|
|
431
|
-
saved: 'محفوظ ہو گئی۔ اگلے لفظ پر لاگو ہوگی۔',
|
|
432
|
-
noWritableStore: 'کوئی ذخیرہ نئی تصحیح قبول نہیں کرتا',
|
|
433
|
-
failed: 'تصحیح محفوظ نہیں ہو سکی',
|
|
434
|
-
close: 'بند کریں',
|
|
435
|
-
},
|
|
436
388
|
link: {
|
|
437
389
|
menuLabel: 'لنک',
|
|
438
390
|
noUrl: '(کوئی یو آر ایل نہیں)',
|
|
@@ -655,40 +607,16 @@ const paShahmukhi = {
|
|
|
655
607
|
},
|
|
656
608
|
findReplace: {
|
|
657
609
|
toggle: 'لبھو تے بدلو',
|
|
658
|
-
find: '
|
|
659
|
-
replace: '
|
|
610
|
+
find: 'لبھo',
|
|
611
|
+
replace: 'بدلo',
|
|
660
612
|
findPlaceholder: 'جو لبھنا اے',
|
|
661
613
|
replacePlaceholder: 'بدلن والا متن',
|
|
662
614
|
previous: 'پچھلا',
|
|
663
615
|
next: 'اگلا',
|
|
664
|
-
replaceOne: '
|
|
665
|
-
replaceAll: 'سارے
|
|
616
|
+
replaceOne: 'بدلo',
|
|
617
|
+
replaceAll: 'سارے بدلo',
|
|
666
618
|
noMatches: 'کوئی ملدا نئیں',
|
|
667
|
-
close: 'بند
|
|
668
|
-
},
|
|
669
|
-
spellcheck: {
|
|
670
|
-
title: 'ہجے دی جانچ',
|
|
671
|
-
language: 'بولی',
|
|
672
|
-
check: 'جانچو',
|
|
673
|
-
close: 'بند کرو',
|
|
674
|
-
noDictionary: 'کوئی شبدکوش نئیں لگی',
|
|
675
|
-
noMisspellings: 'کوئی غلط ہجے نئیں لبھے',
|
|
676
|
-
previous: 'پچھلا',
|
|
677
|
-
next: 'اگلا',
|
|
678
|
-
noSuggestions: 'کوئی تجویز نئیں',
|
|
679
|
-
},
|
|
680
|
-
autoCorrect: {
|
|
681
|
-
title: 'خودکار درستی',
|
|
682
|
-
language: 'بولی',
|
|
683
|
-
from: 'لکھیا ہویا لفظ',
|
|
684
|
-
fromPlaceholder: 'جو لفظ لکھیا جاندا اے',
|
|
685
|
-
to: 'ٹھیک لفظ',
|
|
686
|
-
toPlaceholder: 'ایس نوں ٹھیک کرو',
|
|
687
|
-
save: 'درستی سانبھو',
|
|
688
|
-
saved: 'سانبھ لیا۔ اگلے لفظ تے لاگو ہووے گی۔',
|
|
689
|
-
noWritableStore: 'کوئی ذخیرہ نویں درستی نئیں منّدا',
|
|
690
|
-
failed: 'درستی سانبھی نئیں جا سکی',
|
|
691
|
-
close: 'بند کرو',
|
|
619
|
+
close: 'بند کرo',
|
|
692
620
|
},
|
|
693
621
|
link: {
|
|
694
622
|
menuLabel: 'لنک',
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,4 @@ export type { FontOption } from './fonts/index.js';
|
|
|
9
9
|
export { STRINGS, getStrings, useStrings, useUiStrings, UiStringsContext } from './i18n/index.js';
|
|
10
10
|
export type { Locale, Strings } from './i18n/index.js';
|
|
11
11
|
export { registerSpellDictionary, hasSpellDictionary, type HunspellFiles, type SpellLanguage } from './spellcheck/spellDictionaries.js';
|
|
12
|
-
export { localStorageAutoCorrectStore, apiAutoCorrectStore, fileAutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
13
|
-
export type { AutoCorrectStore, AutoCorrectEntry } from './autocorrect/autoCorrectStores.js';
|
|
14
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,oBAAoB,EAAE,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;AAE9C,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,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;AAE9C,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,4 +4,3 @@ export { ImageNode, $createImageNode, $isImageNode } from './image/ImageNode.js'
|
|
|
4
4
|
export { DEFAULT_FONT_OPTIONS, URDU_WEB_FONT_OPTIONS, FONT_SIZES_PX } from './fonts/index.js';
|
|
5
5
|
export { STRINGS, getStrings, useStrings, useUiStrings, UiStringsContext } from './i18n/index.js';
|
|
6
6
|
export { registerSpellDictionary, hasSpellDictionary } from './spellcheck/spellDictionaries.js';
|
|
7
|
-
export { localStorageAutoCorrectStore, apiAutoCorrectStore, fileAutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
package/dist/theme/editor.css
CHANGED
|
@@ -870,188 +870,3 @@
|
|
|
870
870
|
opacity: 0.8;
|
|
871
871
|
white-space: nowrap;
|
|
872
872
|
}
|
|
873
|
-
|
|
874
|
-
/* Spellcheck panel: same top-right floating spot as the find widget, which
|
|
875
|
-
closes when this opens. */
|
|
876
|
-
.likhari-spell-panel {
|
|
877
|
-
position: absolute;
|
|
878
|
-
z-index: 5;
|
|
879
|
-
top: 8px;
|
|
880
|
-
right: 16px;
|
|
881
|
-
width: max-content;
|
|
882
|
-
max-width: min(360px, calc(100% - 32px));
|
|
883
|
-
max-height: 60%;
|
|
884
|
-
overflow-y: auto;
|
|
885
|
-
overflow-x: hidden;
|
|
886
|
-
padding: 8px;
|
|
887
|
-
border: 1px solid var(--editor-line);
|
|
888
|
-
border-radius: 6px;
|
|
889
|
-
background: var(--editor-paper-dim);
|
|
890
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
891
|
-
font-size: 13px;
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
.likhari-spell-panel[dir='rtl'] {
|
|
895
|
-
right: auto;
|
|
896
|
-
left: 16px;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
.likhari-spell-header,
|
|
900
|
-
.likhari-spell-controls {
|
|
901
|
-
display: flex;
|
|
902
|
-
flex-wrap: wrap;
|
|
903
|
-
align-items: center;
|
|
904
|
-
justify-content: space-between;
|
|
905
|
-
gap: 6px;
|
|
906
|
-
margin-bottom: 6px;
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
.likhari-spell-controls select {
|
|
910
|
-
min-width: 0;
|
|
911
|
-
max-width: 100%;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
.likhari-spell-panel button {
|
|
915
|
-
padding: 2px 8px;
|
|
916
|
-
border: 1px solid var(--editor-line);
|
|
917
|
-
border-radius: 4px;
|
|
918
|
-
background: transparent;
|
|
919
|
-
color: inherit;
|
|
920
|
-
cursor: pointer;
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
.likhari-spell-panel button:disabled {
|
|
924
|
-
opacity: 0.5;
|
|
925
|
-
cursor: default;
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
.likhari-spell-icon {
|
|
929
|
-
display: inline-flex;
|
|
930
|
-
align-items: center;
|
|
931
|
-
justify-content: center;
|
|
932
|
-
width: 24px;
|
|
933
|
-
height: 24px;
|
|
934
|
-
padding: 0 !important;
|
|
935
|
-
border: none !important;
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
.likhari-spell-note {
|
|
939
|
-
margin: 4px 0;
|
|
940
|
-
opacity: 0.8;
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
.likhari-spell-list {
|
|
944
|
-
list-style: none;
|
|
945
|
-
margin: 0;
|
|
946
|
-
padding: 0;
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
.likhari-spell-list li {
|
|
950
|
-
display: flex;
|
|
951
|
-
flex-wrap: wrap;
|
|
952
|
-
align-items: center;
|
|
953
|
-
gap: 4px;
|
|
954
|
-
padding: 4px 0;
|
|
955
|
-
border-top: 1px solid var(--editor-line);
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
.likhari-spell-word {
|
|
959
|
-
font-weight: 600;
|
|
960
|
-
color: #b42318 !important;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
.likhari-spell-suggestion {
|
|
964
|
-
font-size: 12px;
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
/* Misspelled words, underlined like the browser's own spellcheck. Styled
|
|
968
|
-
through the CSS Custom Highlight API by SpellHighlightPlugin. */
|
|
969
|
-
::highlight(likhari-spelling) {
|
|
970
|
-
text-decoration: red wavy underline;
|
|
971
|
-
text-decoration-skip-ink: none;
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
.likhari-spell-nav {
|
|
975
|
-
display: flex;
|
|
976
|
-
align-items: center;
|
|
977
|
-
justify-content: flex-end;
|
|
978
|
-
gap: 4px;
|
|
979
|
-
margin-bottom: 6px;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
.likhari-spell-status {
|
|
983
|
-
opacity: 0.8;
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
.likhari-spell-item {
|
|
987
|
-
display: flex;
|
|
988
|
-
flex-direction: column;
|
|
989
|
-
gap: 6px;
|
|
990
|
-
padding-top: 6px;
|
|
991
|
-
border-top: 1px solid var(--editor-line);
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
.likhari-spell-suggestions {
|
|
995
|
-
display: flex;
|
|
996
|
-
flex-wrap: wrap;
|
|
997
|
-
gap: 4px;
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
/* Auto-correct panel: the same floating spot as the spellcheck panel. */
|
|
1001
|
-
.likhari-autocorrect-panel {
|
|
1002
|
-
position: absolute;
|
|
1003
|
-
z-index: 5;
|
|
1004
|
-
top: 8px;
|
|
1005
|
-
right: 16px;
|
|
1006
|
-
width: 260px;
|
|
1007
|
-
max-width: calc(100% - 32px);
|
|
1008
|
-
padding: 8px;
|
|
1009
|
-
border: 1px solid var(--editor-line);
|
|
1010
|
-
border-radius: 6px;
|
|
1011
|
-
background: var(--editor-paper-dim);
|
|
1012
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
1013
|
-
font-size: 13px;
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
.likhari-autocorrect-panel[dir='rtl'] {
|
|
1017
|
-
right: auto;
|
|
1018
|
-
left: 16px;
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
.likhari-autocorrect-field {
|
|
1022
|
-
display: flex;
|
|
1023
|
-
flex-direction: column;
|
|
1024
|
-
gap: 2px;
|
|
1025
|
-
margin-bottom: 6px;
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
.likhari-autocorrect-field input,
|
|
1029
|
-
.likhari-autocorrect-field select {
|
|
1030
|
-
padding: 3px 6px;
|
|
1031
|
-
border: 1px solid var(--editor-line);
|
|
1032
|
-
border-radius: 4px;
|
|
1033
|
-
background: var(--editor-paper);
|
|
1034
|
-
color: inherit;
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
.likhari-autocorrect-actions {
|
|
1038
|
-
display: flex;
|
|
1039
|
-
flex-direction: column;
|
|
1040
|
-
gap: 6px;
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
.likhari-autocorrect-actions button {
|
|
1044
|
-
align-self: flex-start;
|
|
1045
|
-
padding: 2px 8px;
|
|
1046
|
-
border: 1px solid var(--editor-line);
|
|
1047
|
-
border-radius: 4px;
|
|
1048
|
-
background: transparent;
|
|
1049
|
-
color: inherit;
|
|
1050
|
-
cursor: pointer;
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
.likhari-autocorrect-actions button:disabled {
|
|
1054
|
-
opacity: 0.5;
|
|
1055
|
-
cursor: default;
|
|
1056
|
-
}
|
|
1057
|
-
|
package/package.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type AutoCorrectStore } from './autoCorrectStores.js';
|
|
2
|
-
/**
|
|
3
|
-
* Corrects typed words as the user finishes them, the way the reference editor
|
|
4
|
-
* does, but from any set of stores. Corrections are loaded once per change
|
|
5
|
-
* of `stores` or `version` (bump `version` after saving a new correction so
|
|
6
|
-
* the table reloads). The table used depends on the block's direction: RTL
|
|
7
|
-
* blocks use the Urdu and Shahmukhi tables, LTR blocks the English one.
|
|
8
|
-
*/
|
|
9
|
-
export declare function AutoCorrectPlugin({ stores, version, enabled }: {
|
|
10
|
-
stores: AutoCorrectStore[];
|
|
11
|
-
version: number;
|
|
12
|
-
enabled: boolean;
|
|
13
|
-
}): null;
|
|
14
|
-
//# sourceMappingURL=AutoCorrectPlugin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AutoCorrectPlugin.d.ts","sourceRoot":"","sources":["../../src/autocorrect/AutoCorrectPlugin.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAOjF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,QAuDhI"}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from 'react';
|
|
2
|
-
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
-
import { $getSelection, $isRangeSelection } from 'lexical';
|
|
4
|
-
import { $correctWordBeforeCaret } from './autoCorrectActions.js';
|
|
5
|
-
import { loadAutoCorrections } from './autoCorrectStores.js';
|
|
6
|
-
/** Keys that end a word: a space or punctuation, in Latin and Arabic-script forms. */
|
|
7
|
-
const BOUNDARY_KEYS = new Set([' ', '.', ',', ';', ':', '!', '?', '،', '؛', '؟', '۔']);
|
|
8
|
-
const LANGUAGES = ['en', 'ur', 'pa-shahmukhi'];
|
|
9
|
-
/**
|
|
10
|
-
* Corrects typed words as the user finishes them, the way the reference editor
|
|
11
|
-
* does, but from any set of stores. Corrections are loaded once per change
|
|
12
|
-
* of `stores` or `version` (bump `version` after saving a new correction so
|
|
13
|
-
* the table reloads). The table used depends on the block's direction: RTL
|
|
14
|
-
* blocks use the Urdu and Shahmukhi tables, LTR blocks the English one.
|
|
15
|
-
*/
|
|
16
|
-
export function AutoCorrectPlugin({ stores, version, enabled }) {
|
|
17
|
-
const [editor] = useLexicalComposerContext();
|
|
18
|
-
const tables = useRef(new Map());
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
if (!enabled)
|
|
21
|
-
return;
|
|
22
|
-
let active = true;
|
|
23
|
-
Promise.all(LANGUAGES.map(async (language) => [language, await loadAutoCorrections(stores, language)])).then((loaded) => {
|
|
24
|
-
if (!active)
|
|
25
|
-
return;
|
|
26
|
-
tables.current = new Map(loaded);
|
|
27
|
-
});
|
|
28
|
-
return () => {
|
|
29
|
-
active = false;
|
|
30
|
-
};
|
|
31
|
-
}, [stores, version, enabled]);
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (!enabled)
|
|
34
|
-
return;
|
|
35
|
-
const tableFor = (rtl) => {
|
|
36
|
-
const language = rtl ? 'ur' : 'en';
|
|
37
|
-
return tables.current.get(language);
|
|
38
|
-
};
|
|
39
|
-
const onKeyDown = (event) => {
|
|
40
|
-
if (event.isComposing || !BOUNDARY_KEYS.has(event.key))
|
|
41
|
-
return;
|
|
42
|
-
// The character is inserted after this event; correct the word once it is there.
|
|
43
|
-
setTimeout(() => {
|
|
44
|
-
editor.update(() => {
|
|
45
|
-
const selection = $getSelection();
|
|
46
|
-
if (!$isRangeSelection(selection))
|
|
47
|
-
return;
|
|
48
|
-
const block = selection.anchor.getNode().getTopLevelElement();
|
|
49
|
-
const table = tableFor(block?.getDirection() === 'rtl');
|
|
50
|
-
if (table)
|
|
51
|
-
$correctWordBeforeCaret(table);
|
|
52
|
-
}, { discrete: true });
|
|
53
|
-
}, 0);
|
|
54
|
-
};
|
|
55
|
-
let root = null;
|
|
56
|
-
const attach = (next) => {
|
|
57
|
-
root?.removeEventListener('keydown', onKeyDown);
|
|
58
|
-
root = next;
|
|
59
|
-
root?.addEventListener('keydown', onKeyDown);
|
|
60
|
-
};
|
|
61
|
-
const unregister = editor.registerRootListener((next) => attach(next));
|
|
62
|
-
return () => {
|
|
63
|
-
unregister();
|
|
64
|
-
attach(null);
|
|
65
|
-
};
|
|
66
|
-
}, [editor, enabled]);
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Corrects the word that ends just before the caret, when the character just
|
|
3
|
-
* typed (the word boundary: space or punctuation) is not a word character. The
|
|
4
|
-
* correction replaces only the word, and the caret stays right after the
|
|
5
|
-
* boundary. Returns true if a correction was made.
|
|
6
|
-
*/
|
|
7
|
-
export declare function $correctWordBeforeCaret(table: Map<string, string>): boolean;
|
|
8
|
-
//# sourceMappingURL=autoCorrectActions.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"autoCorrectActions.d.ts","sourceRoot":"","sources":["../../src/autocorrect/autoCorrectActions.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAiC3E"}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { $getSelection, $isRangeSelection, $isTextNode } from 'lexical';
|
|
2
|
-
import { $replaceMatch } from '../find/findReplaceActions.js';
|
|
3
|
-
/** The part of a word that counts as word characters at its end. */
|
|
4
|
-
const WORD_END = /[\p{L}\p{M}'’]+$/u;
|
|
5
|
-
const WORD_CHAR = /[\p{L}\p{M}'’]/u;
|
|
6
|
-
/**
|
|
7
|
-
* Corrects the word that ends just before the caret, when the character just
|
|
8
|
-
* typed (the word boundary: space or punctuation) is not a word character. The
|
|
9
|
-
* correction replaces only the word, and the caret stays right after the
|
|
10
|
-
* boundary. Returns true if a correction was made.
|
|
11
|
-
*/
|
|
12
|
-
export function $correctWordBeforeCaret(table) {
|
|
13
|
-
const selection = $getSelection();
|
|
14
|
-
if (!$isRangeSelection(selection) || !selection.isCollapsed())
|
|
15
|
-
return false;
|
|
16
|
-
const anchor = selection.anchor;
|
|
17
|
-
const node = anchor.getNode();
|
|
18
|
-
if (!$isTextNode(node))
|
|
19
|
-
return false;
|
|
20
|
-
const before = node.getTextContent().slice(0, anchor.offset);
|
|
21
|
-
const boundary = before.slice(-1);
|
|
22
|
-
if (boundary === '' || WORD_CHAR.test(boundary))
|
|
23
|
-
return false;
|
|
24
|
-
const body = before.slice(0, -1);
|
|
25
|
-
const word = WORD_END.exec(body)?.[0];
|
|
26
|
-
if (!word)
|
|
27
|
-
return false;
|
|
28
|
-
const replacement = table.get(word);
|
|
29
|
-
if (replacement === undefined || replacement === word)
|
|
30
|
-
return false;
|
|
31
|
-
const start = body.length - word.length;
|
|
32
|
-
$replaceMatch({ anchorKey: node.getKey(), anchorOffset: start, focusKey: node.getKey(), focusOffset: body.length }, replacement);
|
|
33
|
-
// Put the caret back after the boundary the user typed, not at the end of the replacement.
|
|
34
|
-
const after = $getSelection();
|
|
35
|
-
if ($isRangeSelection(after)) {
|
|
36
|
-
const focusNode = after.focus.getNode();
|
|
37
|
-
const caret = after.focus.offset + boundary.length;
|
|
38
|
-
after.anchor.set(focusNode.getKey(), caret, 'text');
|
|
39
|
-
after.focus.set(focusNode.getKey(), caret, 'text');
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { SpellLanguage } from '../spellcheck/spellDictionaries.js';
|
|
2
|
-
/** One correction: a typed word and what it should become. */
|
|
3
|
-
export interface AutoCorrectEntry {
|
|
4
|
-
from: string;
|
|
5
|
-
to: string;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Where auto-corrections come from and go. The host supplies any number of
|
|
9
|
-
* stores; corrections from all of them are merged, and when two stores
|
|
10
|
-
* correct the same word, the one listed first wins. New corrections are
|
|
11
|
-
* appended to the first store that accepts writes.
|
|
12
|
-
*/
|
|
13
|
-
export interface AutoCorrectStore {
|
|
14
|
-
readonly id: string;
|
|
15
|
-
/** A store without `append` (or with `readOnly`) is never written to. */
|
|
16
|
-
readonly readOnly?: boolean;
|
|
17
|
-
load(language: SpellLanguage): Promise<AutoCorrectEntry[]>;
|
|
18
|
-
append?(language: SpellLanguage, entry: AutoCorrectEntry): Promise<void>;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Corrections kept in this browser's localStorage. Storage can be disabled or
|
|
22
|
-
* full, so every access is guarded: a failure means "no corrections", never a
|
|
23
|
-
* broken editor.
|
|
24
|
-
*/
|
|
25
|
-
export declare function localStorageAutoCorrectStore(options?: {
|
|
26
|
-
key?: string;
|
|
27
|
-
}): AutoCorrectStore;
|
|
28
|
-
/**
|
|
29
|
-
* Corrections served by an API. `load` calls `GET {url}?language=xx` and expects
|
|
30
|
-
* a JSON array of `{ from, to }`; `append` calls `POST {url}` with
|
|
31
|
-
* `{ language, from, to }`. Credentials and headers belong to the host.
|
|
32
|
-
*/
|
|
33
|
-
export declare function apiAutoCorrectStore(options: {
|
|
34
|
-
id?: string;
|
|
35
|
-
url: string;
|
|
36
|
-
headers?: Record<string, string>;
|
|
37
|
-
fetch?: typeof fetch;
|
|
38
|
-
}): AutoCorrectStore;
|
|
39
|
-
/**
|
|
40
|
-
* Corrections from a JSON file the host publishes — a list of `{ language, from, to }`.
|
|
41
|
-
* Read-only: it has no way to write back to a static file.
|
|
42
|
-
*/
|
|
43
|
-
export declare function fileAutoCorrectStore(options: {
|
|
44
|
-
id?: string;
|
|
45
|
-
url: string;
|
|
46
|
-
fetch?: typeof fetch;
|
|
47
|
-
}): AutoCorrectStore;
|
|
48
|
-
/** Corrections for one language, merged across stores. Failing stores are skipped. */
|
|
49
|
-
export declare function loadAutoCorrections(stores: AutoCorrectStore[], language: SpellLanguage): Promise<Map<string, string>>;
|
|
50
|
-
/** Saves a correction to the first store that accepts writes. Returns false if none does. */
|
|
51
|
-
export declare function appendAutoCorrection(stores: AutoCorrectStore[], language: SpellLanguage, entry: AutoCorrectEntry): Promise<boolean>;
|
|
52
|
-
//# sourceMappingURL=autoCorrectStores.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"autoCorrectStores.d.ts","sourceRoot":"","sources":["../../src/autocorrect/autoCorrectStores.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAErE,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC3D,MAAM,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1E;AAkBD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,gBAAgB,CA6B7F;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB,GAAG,gBAAgB,CAmBnB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CAAE,GAAG,gBAAgB,CAkBlH;AAED,sFAAsF;AACtF,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAQ3H;AAED,6FAA6F;AAC7F,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAKzI"}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
const STORAGE_KEY = 'likhari-autocorrect';
|
|
2
|
-
function isEntry(value) {
|
|
3
|
-
return (typeof value === 'object' &&
|
|
4
|
-
value !== null &&
|
|
5
|
-
typeof value.from === 'string' &&
|
|
6
|
-
typeof value.to === 'string' &&
|
|
7
|
-
value.from !== '');
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Corrections kept in this browser's localStorage. Storage can be disabled or
|
|
11
|
-
* full, so every access is guarded: a failure means "no corrections", never a
|
|
12
|
-
* broken editor.
|
|
13
|
-
*/
|
|
14
|
-
export function localStorageAutoCorrectStore(options = {}) {
|
|
15
|
-
const key = options.key ?? STORAGE_KEY;
|
|
16
|
-
function readAll() {
|
|
17
|
-
try {
|
|
18
|
-
const parsed = JSON.parse(localStorage.getItem(key) ?? '[]');
|
|
19
|
-
return Array.isArray(parsed) ? parsed.filter((e) => isEntry(e) && 'language' in e) : [];
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return [];
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return {
|
|
26
|
-
id: 'local-storage',
|
|
27
|
-
async load(language) {
|
|
28
|
-
return readAll()
|
|
29
|
-
.filter((e) => e.language === language)
|
|
30
|
-
.map(({ from, to }) => ({ from, to }));
|
|
31
|
-
},
|
|
32
|
-
async append(language, entry) {
|
|
33
|
-
const all = readAll().filter((e) => !(e.language === language && e.from === entry.from));
|
|
34
|
-
all.push({ language, from: entry.from, to: entry.to });
|
|
35
|
-
try {
|
|
36
|
-
localStorage.setItem(key, JSON.stringify(all));
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
// Quota exceeded or storage disabled: the correction is kept for this session only.
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Corrections served by an API. `load` calls `GET {url}?language=xx` and expects
|
|
46
|
-
* a JSON array of `{ from, to }`; `append` calls `POST {url}` with
|
|
47
|
-
* `{ language, from, to }`. Credentials and headers belong to the host.
|
|
48
|
-
*/
|
|
49
|
-
export function apiAutoCorrectStore(options) {
|
|
50
|
-
const doFetch = options.fetch ?? fetch;
|
|
51
|
-
return {
|
|
52
|
-
id: options.id ?? 'api',
|
|
53
|
-
async load(language) {
|
|
54
|
-
const response = await doFetch(`${options.url}?language=${encodeURIComponent(language)}`, { headers: options.headers });
|
|
55
|
-
if (!response.ok)
|
|
56
|
-
throw new Error(`Auto-correct API failed: ${response.status}`);
|
|
57
|
-
const data = await response.json();
|
|
58
|
-
return Array.isArray(data) ? data.filter(isEntry).map(({ from, to }) => ({ from, to })) : [];
|
|
59
|
-
},
|
|
60
|
-
async append(language, entry) {
|
|
61
|
-
const response = await doFetch(options.url, {
|
|
62
|
-
method: 'POST',
|
|
63
|
-
headers: { 'Content-Type': 'application/json', ...options.headers },
|
|
64
|
-
body: JSON.stringify({ language, from: entry.from, to: entry.to }),
|
|
65
|
-
});
|
|
66
|
-
if (!response.ok)
|
|
67
|
-
throw new Error(`Auto-correct API rejected the entry: ${response.status}`);
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Corrections from a JSON file the host publishes — a list of `{ language, from, to }`.
|
|
73
|
-
* Read-only: it has no way to write back to a static file.
|
|
74
|
-
*/
|
|
75
|
-
export function fileAutoCorrectStore(options) {
|
|
76
|
-
const doFetch = options.fetch ?? fetch;
|
|
77
|
-
let cached = null;
|
|
78
|
-
const all = () => {
|
|
79
|
-
cached ?? (cached = doFetch(options.url).then(async (response) => {
|
|
80
|
-
if (!response.ok)
|
|
81
|
-
throw new Error(`Auto-correct file failed: ${response.status}`);
|
|
82
|
-
const data = await response.json();
|
|
83
|
-
return Array.isArray(data) ? data.filter((e) => isEntry(e) && 'language' in e) : [];
|
|
84
|
-
}));
|
|
85
|
-
return cached;
|
|
86
|
-
};
|
|
87
|
-
return {
|
|
88
|
-
id: options.id ?? 'file',
|
|
89
|
-
readOnly: true,
|
|
90
|
-
async load(language) {
|
|
91
|
-
return (await all()).filter((e) => e.language === language).map(({ from, to }) => ({ from, to }));
|
|
92
|
-
},
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
/** Corrections for one language, merged across stores. Failing stores are skipped. */
|
|
96
|
-
export async function loadAutoCorrections(stores, language) {
|
|
97
|
-
const table = new Map();
|
|
98
|
-
const results = await Promise.allSettled(stores.map((store) => store.load(language)));
|
|
99
|
-
results.forEach((result) => {
|
|
100
|
-
if (result.status !== 'fulfilled')
|
|
101
|
-
return;
|
|
102
|
-
for (const entry of result.value)
|
|
103
|
-
if (!table.has(entry.from))
|
|
104
|
-
table.set(entry.from, entry.to);
|
|
105
|
-
});
|
|
106
|
-
return table;
|
|
107
|
-
}
|
|
108
|
-
/** Saves a correction to the first store that accepts writes. Returns false if none does. */
|
|
109
|
-
export async function appendAutoCorrection(stores, language, entry) {
|
|
110
|
-
const writable = stores.find((store) => !store.readOnly && store.append);
|
|
111
|
-
if (!writable?.append)
|
|
112
|
-
return false;
|
|
113
|
-
await writable.append(language, entry);
|
|
114
|
-
return true;
|
|
115
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Strings } from '../i18n/strings.js';
|
|
2
|
-
import { type AutoCorrectStore } from '../autocorrect/autoCorrectStores.js';
|
|
3
|
-
/**
|
|
4
|
-
* Adds one correction (a typed word and its replacement) to the first store
|
|
5
|
-
* that accepts writes. Saving bumps the editor's correction version, so the new
|
|
6
|
-
* entry applies to the next word the user types.
|
|
7
|
-
*/
|
|
8
|
-
export declare function AutoCorrectPanel({ strings, dir, stores, onSaved, onClose, }: {
|
|
9
|
-
strings: Strings;
|
|
10
|
-
dir: 'ltr' | 'rtl';
|
|
11
|
-
stores: AutoCorrectStore[];
|
|
12
|
-
onSaved: () => void;
|
|
13
|
-
onClose: () => void;
|
|
14
|
-
}): import("react").JSX.Element;
|
|
15
|
-
//# sourceMappingURL=AutoCorrectPanel.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AutoCorrectPanel.d.ts","sourceRoot":"","sources":["../../src/components/AutoCorrectPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAwB,KAAK,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAS/F;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,GAAG,EACH,MAAM,EACN,OAAO,EACP,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,KAAK,GAAG,KAAK,CAAC;IACnB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,+BAqEA"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { IconX } from '@tabler/icons-react';
|
|
4
|
-
import { appendAutoCorrection } from '../autocorrect/autoCorrectStores.js';
|
|
5
|
-
const LANGUAGES = [
|
|
6
|
-
{ value: 'en', label: 'English' },
|
|
7
|
-
{ value: 'ur', label: 'اردو' },
|
|
8
|
-
{ value: 'pa-shahmukhi', label: 'پنجابی (شاہ مکھی)' },
|
|
9
|
-
];
|
|
10
|
-
/**
|
|
11
|
-
* Adds one correction (a typed word and its replacement) to the first store
|
|
12
|
-
* that accepts writes. Saving bumps the editor's correction version, so the new
|
|
13
|
-
* entry applies to the next word the user types.
|
|
14
|
-
*/
|
|
15
|
-
export function AutoCorrectPanel({ strings, dir, stores, onSaved, onClose, }) {
|
|
16
|
-
const t = strings.autoCorrect;
|
|
17
|
-
const [language, setLanguage] = useState('en');
|
|
18
|
-
const [from, setFrom] = useState('');
|
|
19
|
-
const [to, setTo] = useState('');
|
|
20
|
-
const [status, setStatus] = useState('idle');
|
|
21
|
-
const save = async () => {
|
|
22
|
-
const entry = { from: from.trim(), to: to.trim() };
|
|
23
|
-
if (entry.from === '' || entry.to === '' || entry.from === entry.to)
|
|
24
|
-
return;
|
|
25
|
-
try {
|
|
26
|
-
const written = await appendAutoCorrection(stores, language, entry);
|
|
27
|
-
if (!written) {
|
|
28
|
-
setStatus('nowhere');
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
setStatus('saved');
|
|
32
|
-
setFrom('');
|
|
33
|
-
setTo('');
|
|
34
|
-
onSaved();
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
setStatus('failed');
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
return (_jsxs("div", { className: "likhari-autocorrect-panel", role: "region", "aria-label": t.title, dir: dir, children: [_jsxs("div", { className: "likhari-spell-header", children: [_jsx("strong", { children: t.title }), _jsx("button", { type: "button", className: "likhari-spell-icon", onClick: onClose, "aria-label": t.close, title: t.close, children: _jsx(IconX, { size: 14, stroke: 1.75 }) })] }), _jsxs("label", { className: "likhari-autocorrect-field", children: [t.language, _jsx("select", { value: language, onChange: (e) => {
|
|
41
|
-
setLanguage(e.target.value);
|
|
42
|
-
setStatus('idle');
|
|
43
|
-
}, children: LANGUAGES.map((l) => (_jsx("option", { value: l.value, children: l.label }, l.value))) })] }), _jsxs("label", { className: "likhari-autocorrect-field", children: [t.from, _jsx("input", { value: from, onChange: (e) => setFrom(e.target.value), placeholder: t.fromPlaceholder })] }), _jsxs("label", { className: "likhari-autocorrect-field", children: [t.to, _jsx("input", { value: to, onChange: (e) => setTo(e.target.value), placeholder: t.toPlaceholder })] }), _jsxs("div", { className: "likhari-autocorrect-actions", children: [_jsx("button", { type: "button", onClick: save, disabled: from.trim() === '' || to.trim() === '', children: t.save }), _jsxs("span", { className: "likhari-spell-note", "aria-live": "polite", children: [status === 'saved' && t.saved, status === 'nowhere' && t.noWritableStore, status === 'failed' && t.failed] })] })] }));
|
|
44
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Strings } from '../i18n/strings.js';
|
|
2
|
-
/**
|
|
3
|
-
* Steps through the misspelled words one at a time, like the find widget.
|
|
4
|
-
* Each word is selected in the editor as it comes up, and its suggestions
|
|
5
|
-
* can replace it. Checking reads the document on demand, so it never flags
|
|
6
|
-
* words while the user is still typing.
|
|
7
|
-
*/
|
|
8
|
-
export declare function SpellcheckPanel({ strings, dir, onClose }: {
|
|
9
|
-
strings: Strings;
|
|
10
|
-
dir: 'ltr' | 'rtl';
|
|
11
|
-
onClose: () => void;
|
|
12
|
-
}): import("react").JSX.Element;
|
|
13
|
-
//# sourceMappingURL=SpellcheckPanel.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SpellcheckPanel.d.ts","sourceRoot":"","sources":["../../src/components/SpellcheckPanel.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAmB/C;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,KAAK,GAAG,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,+BA2IvH"}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
4
|
-
import { IconChevronDown, IconX } from '@tabler/icons-react';
|
|
5
|
-
import { $replaceMatch, $selectMatch } from '../find/findReplaceActions.js';
|
|
6
|
-
import { $collectMisspellings } from '../spellcheck/spellcheckActions.js';
|
|
7
|
-
import { getSpeller, hasSpellDictionary } from '../spellcheck/spellDictionaries.js';
|
|
8
|
-
const LANGUAGES = [
|
|
9
|
-
{ value: 'en', label: 'English' },
|
|
10
|
-
{ value: 'ur', label: 'اردو' },
|
|
11
|
-
{ value: 'pa-shahmukhi', label: 'پنجابی (شاہ مکھی)' },
|
|
12
|
-
];
|
|
13
|
-
const SUGGESTIONS_PER_WORD = 3;
|
|
14
|
-
/**
|
|
15
|
-
* Steps through the misspelled words one at a time, like the find widget.
|
|
16
|
-
* Each word is selected in the editor as it comes up, and its suggestions
|
|
17
|
-
* can replace it. Checking reads the document on demand, so it never flags
|
|
18
|
-
* words while the user is still typing.
|
|
19
|
-
*/
|
|
20
|
-
export function SpellcheckPanel({ strings, dir, onClose }) {
|
|
21
|
-
const [editor] = useLexicalComposerContext();
|
|
22
|
-
const t = strings.spellcheck;
|
|
23
|
-
const [language, setLanguage] = useState('en');
|
|
24
|
-
const [items, setItems] = useState(null);
|
|
25
|
-
const [index, setIndex] = useState(0);
|
|
26
|
-
const [checking, setChecking] = useState(false);
|
|
27
|
-
const available = hasSpellDictionary(language);
|
|
28
|
-
const current = items?.[index];
|
|
29
|
-
// Selects an item in the editor and focuses the editor, so the selection is
|
|
30
|
-
// drawn (Lexical only draws it while the editor has focus).
|
|
31
|
-
const show = (list, at) => {
|
|
32
|
-
const item = list[at];
|
|
33
|
-
if (!item)
|
|
34
|
-
return;
|
|
35
|
-
editor.update(() => $selectMatch(item.match), { discrete: true });
|
|
36
|
-
editor.getElementByKey(item.match.anchorKey)?.scrollIntoView({ block: 'center' });
|
|
37
|
-
editor.focus();
|
|
38
|
-
};
|
|
39
|
-
const check = async () => {
|
|
40
|
-
const speller = getSpeller(language);
|
|
41
|
-
if (!speller)
|
|
42
|
-
return;
|
|
43
|
-
setChecking(true);
|
|
44
|
-
const resolved = await speller;
|
|
45
|
-
const found = editor.getEditorState().read(() => $collectMisspellings({ ltr: resolved, rtl: resolved }));
|
|
46
|
-
const list = found.map((m) => ({
|
|
47
|
-
...m,
|
|
48
|
-
suggestions: resolved.suggest(m.word).slice(0, SUGGESTIONS_PER_WORD),
|
|
49
|
-
}));
|
|
50
|
-
setItems(list);
|
|
51
|
-
setIndex(0);
|
|
52
|
-
setChecking(false);
|
|
53
|
-
show(list, 0);
|
|
54
|
-
};
|
|
55
|
-
const step = (delta) => {
|
|
56
|
-
if (!items || items.length === 0)
|
|
57
|
-
return;
|
|
58
|
-
const next = (index + delta + items.length) % items.length;
|
|
59
|
-
setIndex(next);
|
|
60
|
-
show(items, next);
|
|
61
|
-
};
|
|
62
|
-
// Replacing changes the document, so the list is checked again afterwards.
|
|
63
|
-
// Only a word still at the same place is replaced, in case the document
|
|
64
|
-
// changed since the check.
|
|
65
|
-
const replace = async (item, suggestion) => {
|
|
66
|
-
const speller = getSpeller(language);
|
|
67
|
-
if (!speller)
|
|
68
|
-
return;
|
|
69
|
-
const resolved = await speller;
|
|
70
|
-
editor.update(() => {
|
|
71
|
-
const match = $collectMisspellings({ ltr: resolved, rtl: resolved }).find((m) => m.word === item.word && m.match.anchorKey === item.match.anchorKey && m.match.anchorOffset === item.match.anchorOffset);
|
|
72
|
-
if (match)
|
|
73
|
-
$replaceMatch(match.match, suggestion);
|
|
74
|
-
}, { discrete: true });
|
|
75
|
-
await check();
|
|
76
|
-
};
|
|
77
|
-
const status = items === null ? '' : items.length === 0 ? t.noMisspellings : `${index + 1} / ${items.length}`;
|
|
78
|
-
return (_jsxs("div", { className: "likhari-spell-panel", role: "region", "aria-label": t.title, dir: dir, children: [_jsxs("div", { className: "likhari-spell-header", children: [_jsx("strong", { children: t.title }), _jsx("button", { type: "button", className: "likhari-spell-icon", onClick: onClose, "aria-label": t.close, title: t.close, children: _jsx(IconX, { size: 14, stroke: 1.75 }) })] }), _jsxs("div", { className: "likhari-spell-controls", children: [_jsx("select", { "aria-label": t.language, value: language, onChange: (e) => {
|
|
79
|
-
setLanguage(e.target.value);
|
|
80
|
-
setItems(null);
|
|
81
|
-
}, children: LANGUAGES.map((l) => (_jsxs("option", { value: l.value, children: [l.label, hasSpellDictionary(l.value) ? '' : ` (${t.noDictionary})`] }, l.value))) }), _jsx("button", { type: "button", onClick: check, disabled: !available || checking, children: t.check })] }), !available && _jsx("p", { className: "likhari-spell-note", children: t.noDictionary }), items !== null && (_jsxs("div", { className: "likhari-spell-nav", children: [_jsx("span", { className: "likhari-spell-status", "aria-live": "polite", children: status }), _jsx("button", { type: "button", className: "likhari-spell-icon", onClick: () => step(-1), disabled: items.length === 0, "aria-label": t.previous, title: t.previous, children: _jsx(IconChevronDown, { size: 14, stroke: 1.75, style: { transform: 'rotate(180deg)' } }) }), _jsx("button", { type: "button", className: "likhari-spell-icon", onClick: () => step(1), disabled: items.length === 0, "aria-label": t.next, title: t.next, children: _jsx(IconChevronDown, { size: 14, stroke: 1.75 }) })] })), current && (_jsxs("div", { className: "likhari-spell-item", children: [_jsx("span", { className: "likhari-spell-word", children: current.word }), current.suggestions.length === 0 ? (_jsx("span", { className: "likhari-spell-note", children: t.noSuggestions })) : (_jsx("div", { className: "likhari-spell-suggestions", children: current.suggestions.map((s) => (_jsx("button", { type: "button", className: "likhari-spell-suggestion", onClick: () => replace(current, s), children: s }, s))) }))] }))] }));
|
|
82
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Underlines misspelled words the way the browser does, without changing the
|
|
3
|
-
* document: ranges are set on the rendered text through the CSS Custom
|
|
4
|
-
* Highlight API. Checking is debounced so typing stays smooth. In browsers
|
|
5
|
-
* without the API, nothing is underlined.
|
|
6
|
-
*/
|
|
7
|
-
export declare function SpellHighlightPlugin(): null;
|
|
8
|
-
//# sourceMappingURL=SpellHighlightPlugin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SpellHighlightPlugin.d.ts","sourceRoot":"","sources":["../../src/spellcheck/SpellHighlightPlugin.tsx"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,wBAAgB,oBAAoB,SAgDnC"}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
-
import { $collectMisspellings } from './spellcheckActions.js';
|
|
4
|
-
import { getSpeller } from './spellDictionaries.js';
|
|
5
|
-
/** The CSS Custom Highlight name; editor.css styles it as a red wavy underline. */
|
|
6
|
-
const HIGHLIGHT = 'likhari-spelling';
|
|
7
|
-
const DEBOUNCE_MS = 300;
|
|
8
|
-
/**
|
|
9
|
-
* Underlines misspelled words the way the browser does, without changing the
|
|
10
|
-
* document: ranges are set on the rendered text through the CSS Custom
|
|
11
|
-
* Highlight API. Checking is debounced so typing stays smooth. In browsers
|
|
12
|
-
* without the API, nothing is underlined.
|
|
13
|
-
*/
|
|
14
|
-
export function SpellHighlightPlugin() {
|
|
15
|
-
const [editor] = useLexicalComposerContext();
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
if (typeof CSS === 'undefined' || !('highlights' in CSS))
|
|
18
|
-
return;
|
|
19
|
-
let checkers = null;
|
|
20
|
-
let timer;
|
|
21
|
-
let active = true;
|
|
22
|
-
const paint = () => {
|
|
23
|
-
if (!active || !checkers)
|
|
24
|
-
return;
|
|
25
|
-
const found = editor.getEditorState().read(() => $collectMisspellings(checkers));
|
|
26
|
-
const ranges = [];
|
|
27
|
-
for (const misspelling of found) {
|
|
28
|
-
for (const segment of misspelling.segments) {
|
|
29
|
-
const text = editor.getElementByKey(segment.key)?.firstChild;
|
|
30
|
-
if (!text || text.nodeType !== Node.TEXT_NODE)
|
|
31
|
-
continue;
|
|
32
|
-
const range = document.createRange();
|
|
33
|
-
range.setStart(text, segment.start);
|
|
34
|
-
range.setEnd(text, segment.end);
|
|
35
|
-
ranges.push(range);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
CSS.highlights.set(HIGHLIGHT, new Highlight(...ranges));
|
|
39
|
-
};
|
|
40
|
-
const schedule = () => {
|
|
41
|
-
clearTimeout(timer);
|
|
42
|
-
timer = setTimeout(paint, DEBOUNCE_MS);
|
|
43
|
-
};
|
|
44
|
-
const unregister = editor.registerUpdateListener(schedule);
|
|
45
|
-
Promise.all([getSpeller('en'), getSpeller('ur')]).then(async ([en, ur]) => {
|
|
46
|
-
checkers = { ltr: en ? await en : undefined, rtl: ur ? await ur : undefined };
|
|
47
|
-
schedule();
|
|
48
|
-
});
|
|
49
|
-
return () => {
|
|
50
|
-
active = false;
|
|
51
|
-
clearTimeout(timer);
|
|
52
|
-
unregister();
|
|
53
|
-
CSS.highlights.delete(HIGHLIGHT);
|
|
54
|
-
};
|
|
55
|
-
}, [editor]);
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { type FindMatch } from '../find/findReplaceActions.js';
|
|
2
|
-
import { type Speller } from './spellDictionaries.js';
|
|
3
|
-
/** The checker for each text direction: English for LTR blocks, Urdu for RTL. */
|
|
4
|
-
export interface Checkers {
|
|
5
|
-
ltr?: Speller;
|
|
6
|
-
rtl?: Speller;
|
|
7
|
-
}
|
|
8
|
-
/** The part of a misspelled word that falls inside one text node. */
|
|
9
|
-
export interface Segment {
|
|
10
|
-
key: string;
|
|
11
|
-
start: number;
|
|
12
|
-
end: number;
|
|
13
|
-
}
|
|
14
|
-
export interface Misspelling {
|
|
15
|
-
word: string;
|
|
16
|
-
match: FindMatch;
|
|
17
|
-
segments: Segment[];
|
|
18
|
-
}
|
|
19
|
-
/** Every word in the document its block's checker does not recognise. */
|
|
20
|
-
export declare function $collectMisspellings(checkers: Checkers): Misspelling[];
|
|
21
|
-
//# sourceMappingURL=spellcheckActions.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spellcheckActions.d.ts","sourceRoot":"","sources":["../../src/spellcheck/spellcheckActions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,EAAW,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE5D,iFAAiF;AACjF,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,qEAAqE;AACrE,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,WAAW,EAAE,CAmBtE"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { $textGroups, $locate } from '../find/findReplaceActions.js';
|
|
2
|
-
import { wordsIn } from './spellDictionaries.js';
|
|
3
|
-
/** Every word in the document its block's checker does not recognise. */
|
|
4
|
-
export function $collectMisspellings(checkers) {
|
|
5
|
-
const found = [];
|
|
6
|
-
for (const group of $textGroups()) {
|
|
7
|
-
const direction = group[0].getParentOrThrow().getDirection();
|
|
8
|
-
const speller = direction === 'rtl' ? checkers.rtl : checkers.ltr;
|
|
9
|
-
if (!speller)
|
|
10
|
-
continue;
|
|
11
|
-
const text = group.map((node) => node.getTextContent()).join('');
|
|
12
|
-
for (const span of wordsIn(text)) {
|
|
13
|
-
if (speller.correct(span.word))
|
|
14
|
-
continue;
|
|
15
|
-
const start = $locate(group, span.start, false);
|
|
16
|
-
const end = $locate(group, span.end, true);
|
|
17
|
-
found.push({
|
|
18
|
-
word: span.word,
|
|
19
|
-
match: { anchorKey: start.key, anchorOffset: start.offset, focusKey: end.key, focusOffset: end.offset },
|
|
20
|
-
segments: segmentsOf(group, span.start, span.end),
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return found;
|
|
25
|
-
}
|
|
26
|
-
function segmentsOf(group, start, end) {
|
|
27
|
-
const segments = [];
|
|
28
|
-
let offset = 0;
|
|
29
|
-
for (const node of group) {
|
|
30
|
-
const length = node.getTextContent().length;
|
|
31
|
-
const from = Math.max(start, offset);
|
|
32
|
-
const to = Math.min(end, offset + length);
|
|
33
|
-
if (to > from)
|
|
34
|
-
segments.push({ key: node.getKey(), start: from - offset, end: to - offset });
|
|
35
|
-
offset += length;
|
|
36
|
-
}
|
|
37
|
-
return segments;
|
|
38
|
-
}
|