@inshapardaz/likhari-react 0.1.24 → 0.1.25-dev.226
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 +6 -0
- package/dist/EditorRoot.d.ts.map +1 -1
- package/dist/EditorRoot.js +13 -3
- package/dist/autocomplete/AutocompletePlugin.d.ts +16 -0
- package/dist/autocomplete/AutocompletePlugin.d.ts.map +1 -0
- package/dist/autocomplete/AutocompletePlugin.js +193 -0
- package/dist/autocomplete/completionStores.d.ts +25 -0
- package/dist/autocomplete/completionStores.d.ts.map +1 -0
- package/dist/autocomplete/completionStores.js +33 -0
- package/dist/autocomplete/wordIndex.d.ts +13 -0
- package/dist/autocomplete/wordIndex.d.ts.map +1 -0
- package/dist/autocomplete/wordIndex.js +37 -0
- package/dist/autocorrect/AutoCorrectPlugin.d.ts.map +1 -1
- package/dist/autocorrect/AutoCorrectPlugin.js +18 -2
- package/dist/autocorrect/autoCorrectActions.d.ts +6 -0
- package/dist/autocorrect/autoCorrectActions.d.ts.map +1 -1
- package/dist/autocorrect/autoCorrectActions.js +30 -0
- package/dist/components/AutoCorrectPanel.d.ts +5 -1
- package/dist/components/AutoCorrectPanel.d.ts.map +1 -1
- package/dist/components/AutoCorrectPanel.js +3 -3
- package/dist/components/SpellcheckPanel.d.ts +3 -1
- package/dist/components/SpellcheckPanel.d.ts.map +1 -1
- package/dist/components/SpellcheckPanel.js +2 -2
- package/dist/components/Toolbar.d.ts +4 -1
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +5 -2
- package/dist/i18n/strings.d.ts +4 -0
- package/dist/i18n/strings.d.ts.map +1 -1
- package/dist/i18n/strings.js +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/spellcheck/spellDictionaries.d.ts +4 -0
- package/dist/spellcheck/spellDictionaries.d.ts.map +1 -1
- package/dist/spellcheck/spellDictionaries.js +29 -3
- package/dist/spellcheck/userWords.d.ts +2 -0
- package/dist/spellcheck/userWords.d.ts.map +1 -1
- package/dist/spellcheck/userWords.js +4 -0
- package/dist/theme/editor.css +22 -0
- package/package.json +1 -1
package/dist/EditorRoot.d.ts
CHANGED
|
@@ -7,7 +7,9 @@ import { type DraftRestoreMode } from './components/DraftRestore.js';
|
|
|
7
7
|
import { type AutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
8
8
|
import type { UrduNormalizationOptions } from './normalization/urduNormalize.js';
|
|
9
9
|
import type { PunctuationOptions } from './autocorrect/punctuationRules.js';
|
|
10
|
+
import { type CompletionStore } from './autocomplete/completionStores.js';
|
|
10
11
|
import { type UserWordStore } from './spellcheck/userWords.js';
|
|
12
|
+
import type { SpellLanguage } from './spellcheck/spellDictionaries.js';
|
|
11
13
|
import { type Locale } from './i18n/index.js';
|
|
12
14
|
/** What happens when the user is about to leave with unsaved changes. */
|
|
13
15
|
export type NavigationGuardMode = 'confirm' | 'save-draft' | 'off';
|
|
@@ -21,6 +23,10 @@ export interface EditorRootProps {
|
|
|
21
23
|
autoCorrectStores?: AutoCorrectStore[];
|
|
22
24
|
/** Where words added to the spelling dictionary are saved, in priority order. Pass a stable array. */
|
|
23
25
|
dictionaryStores?: UserWordStore[];
|
|
26
|
+
/** Where autocomplete words come from, combined per language. Defaults to the dictionaries and the user's words. Pass a stable array. */
|
|
27
|
+
completionStores?: CompletionStore[];
|
|
28
|
+
/** The language autocomplete works in: 'auto' follows each block's direction (English for LTR, Urdu for RTL). */
|
|
29
|
+
autoCompleteLanguage?: SpellLanguage | 'auto';
|
|
24
30
|
/** Urdu normalisation applied as part of auto-correct. Diacritics are kept unless `removeDiacritics` is set. */
|
|
25
31
|
urduNormalization?: UrduNormalizationOptions;
|
|
26
32
|
/** Common punctuation fixes, and whether a straight " becomes ”. Both on by default. */
|
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;AAIhF,OAAO,EAAgC,KAAK,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACtG,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"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"}
|
package/dist/EditorRoot.js
CHANGED
|
@@ -32,6 +32,8 @@ import { AutoCorrectPlugin } from './autocorrect/AutoCorrectPlugin.js';
|
|
|
32
32
|
import { localStorageAutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
33
33
|
import { SpellcheckPanel } from './components/SpellcheckPanel.js';
|
|
34
34
|
import { SpellHighlightPlugin } from './spellcheck/SpellHighlightPlugin.js';
|
|
35
|
+
import { AutocompletePlugin } from './autocomplete/AutocompletePlugin.js';
|
|
36
|
+
import { dictionaryCompletionStore } from './autocomplete/completionStores.js';
|
|
35
37
|
import { loadUserWords, localStorageUserWordStore } from './spellcheck/userWords.js';
|
|
36
38
|
import { LeaveDialog } from './components/LeaveDialog.js';
|
|
37
39
|
import { clearDraft, createDraftId, hasDraftContent, pruneDrafts, writeDraft, } from './persistence/draftStorage.js';
|
|
@@ -43,6 +45,8 @@ const DEFAULT_AUTOSAVE_MAX_BYTES = 2000000;
|
|
|
43
45
|
const DEFAULT_AUTOSAVE_MAX_DRAFTS = 20;
|
|
44
46
|
/** Used when the host passes no stores: corrections are kept in this browser. */
|
|
45
47
|
const DEFAULT_AUTOCORRECT_STORES = [localStorageAutoCorrectStore()];
|
|
48
|
+
/** Used when the host passes no completion stores: the dictionary's words and the user's added words. */
|
|
49
|
+
const DEFAULT_COMPLETION_STORES = [dictionaryCompletionStore()];
|
|
46
50
|
/** Used when the host passes no dictionary stores: added words are kept in this browser. */
|
|
47
51
|
const DEFAULT_DICTIONARY_STORES = [localStorageUserWordStore()];
|
|
48
52
|
function initialEditorStateJson(initialContent) {
|
|
@@ -51,7 +55,7 @@ function initialEditorStateJson(initialContent) {
|
|
|
51
55
|
const state = defaultFormatRegistry.parse(initialContent.format, initialContent.value);
|
|
52
56
|
return JSON.stringify(state);
|
|
53
57
|
}
|
|
54
|
-
export const EditorRoot = forwardRef(function EditorRoot({ documentId, autoCorrectStores, dictionaryStores, urduNormalization, punctuation, 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) {
|
|
58
|
+
export const EditorRoot = forwardRef(function EditorRoot({ documentId, autoCorrectStores, dictionaryStores, completionStores, autoCompleteLanguage = 'auto', urduNormalization, punctuation, 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) {
|
|
55
59
|
const config = useMemo(() => resolveFeatureConfig(featureConfig, featurePreset), [featureConfig, featurePreset]);
|
|
56
60
|
const strings = useMemo(() => getStrings(locale), [locale]);
|
|
57
61
|
const resolvedPlaceholder = placeholder ?? strings.editor.placeholder;
|
|
@@ -79,9 +83,15 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, autoCorre
|
|
|
79
83
|
const lastSavedJsonRef = useRef(null);
|
|
80
84
|
const [isDirty, setIsDirty] = useState(false);
|
|
81
85
|
const [openPanel, setOpenPanel] = useState(null);
|
|
86
|
+
const [autoCorrectPrefill, setAutoCorrectPrefill] = useState(null);
|
|
87
|
+
const openAutoCorrectFor = (from, language) => {
|
|
88
|
+
setAutoCorrectPrefill({ id: Date.now(), from, language });
|
|
89
|
+
setOpenPanel('autocorrect');
|
|
90
|
+
};
|
|
82
91
|
const [autoCorrectVersion, setAutoCorrectVersion] = useState(0);
|
|
83
92
|
const stores = autoCorrectStores ?? DEFAULT_AUTOCORRECT_STORES;
|
|
84
93
|
const wordStores = dictionaryStores ?? DEFAULT_DICTIONARY_STORES;
|
|
94
|
+
const resolvedCompletionStores = completionStores ?? DEFAULT_COMPLETION_STORES;
|
|
85
95
|
useEffect(() => {
|
|
86
96
|
void loadUserWords(wordStores);
|
|
87
97
|
}, [wordStores]);
|
|
@@ -298,9 +308,9 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, autoCorre
|
|
|
298
308
|
// rather than colliding on a shared one.
|
|
299
309
|
const portalTargetId = useId();
|
|
300
310
|
const portalTargetSelector = `#${CSS.escape(portalTargetId)}`;
|
|
301
|
-
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, dictionaryStores: wordStores, onSave: handleSave, findOpen: openPanel === 'find', onToggleFind: () => togglePanel('find'), spellOpen: openPanel === 'spell', onToggleSpell: () => togglePanel('spell'), autoCorrectOpen: openPanel === 'autocorrect', onToggleAutoCorrect: () => togglePanel('autocorrect'), isDirty: isDirty, showSave: showSave, fontOptions: fontOptions, direction: dir, locale: locale, drafts: autosave
|
|
311
|
+
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, dictionaryStores: wordStores, onAddAutoCorrect: config.language.autocorrect ? openAutoCorrectFor : undefined, onSave: handleSave, findOpen: openPanel === 'find', onToggleFind: () => togglePanel('find'), spellOpen: openPanel === 'spell', onToggleSpell: () => togglePanel('spell'), autoCorrectOpen: openPanel === 'autocorrect', onToggleAutoCorrect: () => togglePanel('autocorrect'), isDirty: isDirty, showSave: showSave, fontOptions: fontOptions, direction: dir, locale: locale, drafts: autosave
|
|
302
312
|
? { currentId: draftId, maxBytes: autosaveMaxBytes, adoptOnRestore: !documentId, onRestored: handleDraftRestored }
|
|
303
|
-
: undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsxs("div", { className: "likhari-canvas-frame", children: [config.findReplace && openPanel === 'find' && _jsx(FindReplaceBar, { strings: strings, dir: dir, onClose: () => setOpenPanel(null) }), config.language.spellCheck && openPanel === 'spell' && (_jsx(SpellcheckPanel, { strings: strings, dir: dir, dictionaryStores: wordStores, onClose: () => setOpenPanel(null) })), config.language.autocorrect && openPanel === 'autocorrect' && (_jsx(AutoCorrectPanel, { strings: strings, dir: dir, stores: stores, onSaved: () => setAutoCorrectVersion((v) => v + 1), onClose: () => setOpenPanel(null) })), _jsx("div", { className: "likhari-canvas", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "likhari-content-editable", dir: dir, spellCheck: false, "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.language.spellCheck && _jsx(SpellHighlightPlugin, {}), (config.language.autocorrect || config.language.textCleanup) && _jsx(AutoCorrectPlugin, { stores: stores, version: autoCorrectVersion, enabled: true, typing: config.language.autocorrect, urduNormalization: urduNormalization, punctuation: punctuation }), 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: () => {
|
|
313
|
+
: undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsxs("div", { className: "likhari-canvas-frame", children: [config.findReplace && openPanel === 'find' && _jsx(FindReplaceBar, { strings: strings, dir: dir, onClose: () => setOpenPanel(null) }), config.language.spellCheck && openPanel === 'spell' && (_jsx(SpellcheckPanel, { strings: strings, dir: dir, dictionaryStores: wordStores, onAddAutoCorrect: config.language.autocorrect ? openAutoCorrectFor : undefined, onClose: () => setOpenPanel(null) })), config.language.autocorrect && openPanel === 'autocorrect' && (_jsx(AutoCorrectPanel, { strings: strings, dir: dir, stores: stores, initialFrom: autoCorrectPrefill?.from, initialLanguage: autoCorrectPrefill?.language, onSaved: () => setAutoCorrectVersion((v) => v + 1), onClose: () => setOpenPanel(null) }, autoCorrectPrefill?.id ?? 0)), _jsx("div", { className: "likhari-canvas", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "likhari-content-editable", dir: dir, spellCheck: false, "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.language.spellCheck && _jsx(SpellHighlightPlugin, {}), config.language.autocomplete && (_jsx(AutocompletePlugin, { label: strings.autoComplete.label, stores: resolvedCompletionStores, language: autoCompleteLanguage })), (config.language.autocorrect || config.language.textCleanup) && _jsx(AutoCorrectPlugin, { stores: stores, version: autoCorrectVersion, enabled: true, typing: config.language.autocorrect, urduNormalization: urduNormalization, punctuation: punctuation }), 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: () => {
|
|
304
314
|
handleSave();
|
|
305
315
|
settleLeave(true);
|
|
306
316
|
}, onSaveDraft: () => {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SpellLanguage } from '../spellcheck/spellDictionaries.js';
|
|
2
|
+
import type { CompletionStore } from './completionStores.js';
|
|
3
|
+
/**
|
|
4
|
+
* Suggests completions for the word being typed, from the dictionary's words and
|
|
5
|
+
* the user's own. Shown only while typing, at the caret. Tab or Enter accepts the
|
|
6
|
+
* highlighted suggestion, the arrow keys move through the list, and Escape (or
|
|
7
|
+
* moving the caret) dismisses it. Left-to-right text uses the English dictionary,
|
|
8
|
+
* right-to-left text the Urdu one.
|
|
9
|
+
*/
|
|
10
|
+
export declare function AutocompletePlugin({ label, stores, language: chosenLanguage, }: {
|
|
11
|
+
label: string;
|
|
12
|
+
stores: CompletionStore[];
|
|
13
|
+
/** The language to complete in, or 'auto' to follow the block's direction. */
|
|
14
|
+
language: SpellLanguage | 'auto';
|
|
15
|
+
}): import("react").JSX.Element | null;
|
|
16
|
+
//# sourceMappingURL=AutocompletePlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutocompletePlugin.d.ts","sourceRoot":"","sources":["../../src/autocomplete/AutocompletePlugin.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAmB1D;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,MAAM,EACN,QAAQ,EAAE,cAAc,GACzB,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,EAAE,aAAa,GAAG,MAAM,CAAC;CAClC,sCA6KA"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
4
|
+
import { $getSelection, $isRangeSelection, $isTextNode, COMMAND_PRIORITY_HIGH, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ENTER_COMMAND, KEY_TAB_COMMAND, } from 'lexical';
|
|
5
|
+
import { $replaceMatch } from '../find/findReplaceActions.js';
|
|
6
|
+
import { onSpellWordsChange } from '../spellcheck/userWords.js';
|
|
7
|
+
import { WordIndex } from './wordIndex.js';
|
|
8
|
+
/** The letters at the end of the text before the caret. */
|
|
9
|
+
const WORD_END = /[\p{L}\p{M}]+$/u;
|
|
10
|
+
const LETTER = /[\p{L}\p{M}]/u;
|
|
11
|
+
const MOVEMENT_KEYS = new Set(['ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown']);
|
|
12
|
+
/** Suggestions only appear once the typed part of a word is this long. */
|
|
13
|
+
const MIN_PREFIX = 2;
|
|
14
|
+
/**
|
|
15
|
+
* Suggests completions for the word being typed, from the dictionary's words and
|
|
16
|
+
* the user's own. Shown only while typing, at the caret. Tab or Enter accepts the
|
|
17
|
+
* highlighted suggestion, the arrow keys move through the list, and Escape (or
|
|
18
|
+
* moving the caret) dismisses it. Left-to-right text uses the English dictionary,
|
|
19
|
+
* right-to-left text the Urdu one.
|
|
20
|
+
*/
|
|
21
|
+
export function AutocompletePlugin({ label, stores, language: chosenLanguage, }) {
|
|
22
|
+
const [editor] = useLexicalComposerContext();
|
|
23
|
+
// Effects run once per editor, so they read the latest props through refs.
|
|
24
|
+
const storesRef = useRef(stores);
|
|
25
|
+
storesRef.current = stores;
|
|
26
|
+
const languageRef = useRef(chosenLanguage);
|
|
27
|
+
languageRef.current = chosenLanguage;
|
|
28
|
+
const [popup, setPopup] = useState(null);
|
|
29
|
+
const popupRef = useRef(null);
|
|
30
|
+
const typing = useRef(false);
|
|
31
|
+
const indexes = useRef(new Map());
|
|
32
|
+
const show = (next) => {
|
|
33
|
+
popupRef.current = next;
|
|
34
|
+
setPopup(next);
|
|
35
|
+
};
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const indexFor = (language) => {
|
|
38
|
+
let index = indexes.current.get(language);
|
|
39
|
+
if (!index) {
|
|
40
|
+
index = Promise.all(storesRef.current.map((store) => store.load(language).catch(() => []))).then((lists) => new WordIndex(lists.flat()));
|
|
41
|
+
indexes.current.set(language, index);
|
|
42
|
+
}
|
|
43
|
+
return index;
|
|
44
|
+
};
|
|
45
|
+
const hide = () => show(null);
|
|
46
|
+
const refresh = () => {
|
|
47
|
+
if (!typing.current)
|
|
48
|
+
return hide();
|
|
49
|
+
let target = null;
|
|
50
|
+
editor.getEditorState().read(() => {
|
|
51
|
+
const selection = $getSelection();
|
|
52
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed())
|
|
53
|
+
return;
|
|
54
|
+
const node = selection.anchor.getNode();
|
|
55
|
+
if (!$isTextNode(node))
|
|
56
|
+
return;
|
|
57
|
+
const text = node.getTextContent();
|
|
58
|
+
const before = text.slice(0, selection.anchor.offset);
|
|
59
|
+
const prefix = WORD_END.exec(before)?.[0];
|
|
60
|
+
const after = text.charAt(selection.anchor.offset);
|
|
61
|
+
if (!prefix || prefix.length < MIN_PREFIX || (after !== '' && LETTER.test(after)))
|
|
62
|
+
return;
|
|
63
|
+
target = { prefix, rtl: node.getParentOrThrow().getDirection() === 'rtl' };
|
|
64
|
+
});
|
|
65
|
+
if (target === null)
|
|
66
|
+
return hide();
|
|
67
|
+
const { prefix, rtl } = target;
|
|
68
|
+
const language = languageRef.current === 'auto' ? (rtl ? 'ur' : 'en') : languageRef.current;
|
|
69
|
+
void indexFor(language).then((loaded) => {
|
|
70
|
+
const items = loaded.complete(prefix);
|
|
71
|
+
if (items.length === 0)
|
|
72
|
+
return hide();
|
|
73
|
+
const rect = caretRect(editor);
|
|
74
|
+
show({ items, index: 0, selected: false, x: rect.left, y: rect.bottom, dir: rtl ? 'rtl' : 'ltr' });
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
const move = (delta) => {
|
|
78
|
+
const current = popupRef.current;
|
|
79
|
+
if (!current)
|
|
80
|
+
return false;
|
|
81
|
+
const count = current.items.length;
|
|
82
|
+
show({ ...current, index: (current.index + delta + count) % count, selected: true });
|
|
83
|
+
return true;
|
|
84
|
+
};
|
|
85
|
+
const onKeyDown = (event) => {
|
|
86
|
+
// Up, Down, Tab and Enter act on the list through their editor commands, which
|
|
87
|
+
// run after this listener, so the list must stay open for them.
|
|
88
|
+
const current = popupRef.current;
|
|
89
|
+
if (current && (event.key === 'ArrowUp' || event.key === 'ArrowDown' || event.key === 'Tab' || (event.key === 'Enter' && current.selected)))
|
|
90
|
+
return;
|
|
91
|
+
if (event.key === 'Escape' && popupRef.current) {
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
show(null);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Left, Right, Home and End move the caret away from the word, so the list closes.
|
|
97
|
+
if (MOVEMENT_KEYS.has(event.key)) {
|
|
98
|
+
typing.current = false;
|
|
99
|
+
return hide();
|
|
100
|
+
}
|
|
101
|
+
// Printable keys and Backspace are typing; anything else (Enter, Tab, ...) ends the word.
|
|
102
|
+
typing.current = (event.key.length === 1 && !event.ctrlKey && !event.metaKey) || event.key === 'Backspace';
|
|
103
|
+
if (!typing.current)
|
|
104
|
+
hide();
|
|
105
|
+
setTimeout(refresh, 0);
|
|
106
|
+
};
|
|
107
|
+
const onMouseDown = () => {
|
|
108
|
+
typing.current = false;
|
|
109
|
+
hide();
|
|
110
|
+
};
|
|
111
|
+
let root = null;
|
|
112
|
+
const attach = (next) => {
|
|
113
|
+
root?.removeEventListener('keydown', onKeyDown);
|
|
114
|
+
root?.removeEventListener('mousedown', onMouseDown);
|
|
115
|
+
root = next;
|
|
116
|
+
root?.addEventListener('keydown', onKeyDown);
|
|
117
|
+
root?.addEventListener('mousedown', onMouseDown);
|
|
118
|
+
};
|
|
119
|
+
const unregisterRoot = editor.registerRootListener((next) => attach(next));
|
|
120
|
+
const unregisterUpdate = editor.registerUpdateListener(() => {
|
|
121
|
+
// Keydown already schedules a refresh; this keeps the list right after the
|
|
122
|
+
// dictionary or user words change.
|
|
123
|
+
if (typing.current)
|
|
124
|
+
setTimeout(refresh, 0);
|
|
125
|
+
});
|
|
126
|
+
const unregisterWords = onSpellWordsChange(() => {
|
|
127
|
+
indexes.current.clear();
|
|
128
|
+
if (typing.current)
|
|
129
|
+
setTimeout(refresh, 0);
|
|
130
|
+
});
|
|
131
|
+
const unregisterCommands = [
|
|
132
|
+
editor.registerCommand(KEY_ARROW_DOWN_COMMAND, () => move(1), COMMAND_PRIORITY_HIGH),
|
|
133
|
+
editor.registerCommand(KEY_ARROW_UP_COMMAND, () => move(-1), COMMAND_PRIORITY_HIGH),
|
|
134
|
+
editor.registerCommand(KEY_TAB_COMMAND, (event) => acceptHighlighted(event), COMMAND_PRIORITY_HIGH),
|
|
135
|
+
editor.registerCommand(KEY_ENTER_COMMAND, (event) => (popupRef.current?.selected ? acceptHighlighted(event) : false), COMMAND_PRIORITY_HIGH),
|
|
136
|
+
];
|
|
137
|
+
function acceptHighlighted(event) {
|
|
138
|
+
const current = popupRef.current;
|
|
139
|
+
if (!current)
|
|
140
|
+
return false;
|
|
141
|
+
event?.preventDefault();
|
|
142
|
+
acceptItem(editor, current.items[current.index]);
|
|
143
|
+
show(null);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
return () => {
|
|
147
|
+
unregisterRoot();
|
|
148
|
+
unregisterUpdate();
|
|
149
|
+
unregisterWords();
|
|
150
|
+
unregisterCommands.forEach((unregister) => unregister());
|
|
151
|
+
attach(null);
|
|
152
|
+
show(null);
|
|
153
|
+
};
|
|
154
|
+
}, [editor]);
|
|
155
|
+
// The index is per store set and language; a change of stores starts again.
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
indexes.current.clear();
|
|
158
|
+
}, [stores]);
|
|
159
|
+
if (!popup)
|
|
160
|
+
return null;
|
|
161
|
+
return (_jsx("div", { className: "likhari-autocomplete", role: "listbox", "aria-label": label, dir: popup.dir, style: { position: 'fixed', left: popup.x, top: popup.y + 4 }, children: popup.items.map((item, i) => (_jsx("div", { role: "option", "aria-selected": i === popup.index, className: i === popup.index ? 'likhari-autocomplete-item likhari-autocomplete-item--active' : 'likhari-autocomplete-item', onMouseDown: (event) => {
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
acceptItem(editor, item);
|
|
164
|
+
}, children: item }, item))) }));
|
|
165
|
+
}
|
|
166
|
+
/** Where to put the popup: under the caret, or the editor's top-left if the caret has no position yet. */
|
|
167
|
+
function caretRect(editor) {
|
|
168
|
+
const selection = window.getSelection();
|
|
169
|
+
if (selection && selection.rangeCount > 0) {
|
|
170
|
+
const rect = selection.getRangeAt(0).getBoundingClientRect();
|
|
171
|
+
if (rect.width > 0 || rect.height > 0)
|
|
172
|
+
return { left: rect.left, bottom: rect.bottom };
|
|
173
|
+
}
|
|
174
|
+
const root = editor.getRootElement()?.getBoundingClientRect();
|
|
175
|
+
return { left: root?.left ?? 0, bottom: root?.top ?? 0 };
|
|
176
|
+
}
|
|
177
|
+
function acceptItem(editor, item) {
|
|
178
|
+
editor.update(() => {
|
|
179
|
+
const selection = $getSelection();
|
|
180
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed())
|
|
181
|
+
return;
|
|
182
|
+
const node = selection.anchor.getNode();
|
|
183
|
+
if (!$isTextNode(node))
|
|
184
|
+
return;
|
|
185
|
+
const before = node.getTextContent().slice(0, selection.anchor.offset);
|
|
186
|
+
const prefix = WORD_END.exec(before)?.[0];
|
|
187
|
+
if (!prefix)
|
|
188
|
+
return;
|
|
189
|
+
const start = before.length - prefix.length;
|
|
190
|
+
$replaceMatch({ anchorKey: node.getKey(), anchorOffset: start, focusKey: node.getKey(), focusOffset: before.length }, item);
|
|
191
|
+
}, { discrete: true });
|
|
192
|
+
editor.focus();
|
|
193
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type SpellLanguage } from '../spellcheck/spellDictionaries.js';
|
|
2
|
+
/**
|
|
3
|
+
* Where autocomplete words come from. The host can pass several; their words
|
|
4
|
+
* are combined per language. Like the other stores, a failing store is skipped.
|
|
5
|
+
*/
|
|
6
|
+
export interface CompletionStore {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
load(language: SpellLanguage): Promise<string[]>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The default: the dictionary's words plus the words the user has added. Nothing
|
|
12
|
+
* to configure; it follows whichever spelling dictionaries are registered.
|
|
13
|
+
*/
|
|
14
|
+
export declare function dictionaryCompletionStore(): CompletionStore;
|
|
15
|
+
/**
|
|
16
|
+
* Words served by an API. `load` calls `GET {url}?language=xx` and expects a JSON
|
|
17
|
+
* array of strings.
|
|
18
|
+
*/
|
|
19
|
+
export declare function apiCompletionStore(options: {
|
|
20
|
+
id?: string;
|
|
21
|
+
url: string;
|
|
22
|
+
headers?: Record<string, string>;
|
|
23
|
+
fetch?: typeof fetch;
|
|
24
|
+
}): CompletionStore;
|
|
25
|
+
//# sourceMappingURL=completionStores.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completionStores.d.ts","sourceRoot":"","sources":["../../src/autocomplete/completionStores.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGzF;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAClD;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,eAAe,CAS3D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,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,eAAe,CAWlB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getDictionaryWords } from '../spellcheck/spellDictionaries.js';
|
|
2
|
+
import { acceptedWords } from '../spellcheck/userWords.js';
|
|
3
|
+
/**
|
|
4
|
+
* The default: the dictionary's words plus the words the user has added. Nothing
|
|
5
|
+
* to configure; it follows whichever spelling dictionaries are registered.
|
|
6
|
+
*/
|
|
7
|
+
export function dictionaryCompletionStore() {
|
|
8
|
+
return {
|
|
9
|
+
id: 'dictionary',
|
|
10
|
+
async load(language) {
|
|
11
|
+
const words = getDictionaryWords(language);
|
|
12
|
+
const dictionary = words ? await words : [];
|
|
13
|
+
return [...dictionary, ...acceptedWords(language)];
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Words served by an API. `load` calls `GET {url}?language=xx` and expects a JSON
|
|
19
|
+
* array of strings.
|
|
20
|
+
*/
|
|
21
|
+
export function apiCompletionStore(options) {
|
|
22
|
+
const doFetch = options.fetch ?? fetch;
|
|
23
|
+
return {
|
|
24
|
+
id: options.id ?? 'api',
|
|
25
|
+
async load(language) {
|
|
26
|
+
const response = await doFetch(`${options.url}?language=${encodeURIComponent(language)}`, { headers: options.headers });
|
|
27
|
+
if (!response.ok)
|
|
28
|
+
throw new Error(`Completion API failed: ${response.status}`);
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
return Array.isArray(data) ? data.filter((w) => typeof w === 'string') : [];
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Words sorted once, so every prefix lookup is a binary search rather than a scan. */
|
|
2
|
+
export declare class WordIndex {
|
|
3
|
+
private readonly words;
|
|
4
|
+
constructor(words: Iterable<string>);
|
|
5
|
+
/**
|
|
6
|
+
* Completions for a prefix: words that start with it (other than the prefix
|
|
7
|
+
* itself), shortest first, then alphabetical. Only the first `scanLimit`
|
|
8
|
+
* matches are considered, so a one-letter prefix stays quick.
|
|
9
|
+
*/
|
|
10
|
+
complete(prefix: string, limit?: number, scanLimit?: number): string[];
|
|
11
|
+
private lowerBound;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=wordIndex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wordIndex.d.ts","sourceRoot":"","sources":["../../src/autocomplete/wordIndex.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAW;gBAErB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC;IAInC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAI,EAAE,SAAS,SAAM,GAAG,MAAM,EAAE;IAY9D,OAAO,CAAC,UAAU;CAUnB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Words sorted once, so every prefix lookup is a binary search rather than a scan. */
|
|
2
|
+
export class WordIndex {
|
|
3
|
+
constructor(words) {
|
|
4
|
+
this.words = [...new Set(words)].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Completions for a prefix: words that start with it (other than the prefix
|
|
8
|
+
* itself), shortest first, then alphabetical. Only the first `scanLimit`
|
|
9
|
+
* matches are considered, so a one-letter prefix stays quick.
|
|
10
|
+
*/
|
|
11
|
+
complete(prefix, limit = 5, scanLimit = 500) {
|
|
12
|
+
if (prefix === '')
|
|
13
|
+
return [];
|
|
14
|
+
const matches = [];
|
|
15
|
+
for (let i = this.lowerBound(prefix); i < this.words.length && matches.length < scanLimit; i++) {
|
|
16
|
+
const word = this.words[i];
|
|
17
|
+
if (!word.startsWith(prefix))
|
|
18
|
+
break;
|
|
19
|
+
if (word !== prefix)
|
|
20
|
+
matches.push(word);
|
|
21
|
+
}
|
|
22
|
+
matches.sort((a, b) => a.length - b.length || (a < b ? -1 : a > b ? 1 : 0));
|
|
23
|
+
return matches.slice(0, limit);
|
|
24
|
+
}
|
|
25
|
+
lowerBound(prefix) {
|
|
26
|
+
let low = 0;
|
|
27
|
+
let high = this.words.length;
|
|
28
|
+
while (low < high) {
|
|
29
|
+
const mid = (low + high) >>> 1;
|
|
30
|
+
if (this.words[mid] < prefix)
|
|
31
|
+
low = mid + 1;
|
|
32
|
+
else
|
|
33
|
+
high = mid;
|
|
34
|
+
}
|
|
35
|
+
return low;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutoCorrectPlugin.d.ts","sourceRoot":"","sources":["../../src/autocorrect/AutoCorrectPlugin.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"AutoCorrectPlugin.d.ts","sourceRoot":"","sources":["../../src/autocorrect/AutoCorrectPlugin.tsx"],"names":[],"mappings":"AAEA,OAAO,EAQL,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;AAWjB,OAAO,EAA0B,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAiB,KAAK,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAG9F,sFAAsF;AACtF,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,EAAE,cAAc,CAAC,IAAI,CAA6C,CAAC;AAMxG;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,OAAO,EACP,OAAO,EACP,MAAM,EACN,iBAAiB,EACjB,WAAW,GACZ,EAAE;IACD,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,OAAO,EAAE,OAAO,CAAC;IACjB,oFAAoF;IACpF,MAAM,EAAE,OAAO,CAAC;IAChB,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C,kEAAkE;IAClE,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC,QA0GA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useRef } from 'react';
|
|
2
2
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
-
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical';
|
|
4
|
-
import { $correctDocument, $correctPunctuationBeforeCaret, $correctPunctuationDocument, $correctWordBeforeCaret, $preservingSelection, $spacePunctuationDocument, } from './autoCorrectActions.js';
|
|
3
|
+
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR, BLUR_COMMAND, COMMAND_PRIORITY_HIGH, KEY_ENTER_COMMAND, createCommand, } from 'lexical';
|
|
4
|
+
import { $correctDocument, $correctPunctuationBeforeCaret, $correctPunctuationDocument, $correctWordBeforeCaret, $correctWordEndingAtCaret, $preservingSelection, $spacePunctuationDocument, } from './autoCorrectActions.js';
|
|
5
5
|
import { $cleanUpText } from '../cleanup/textCleanupActions.js';
|
|
6
6
|
import { activePunctuationRules } from './punctuationRules.js';
|
|
7
7
|
import { loadAutoCorrections } from './autoCorrectStores.js';
|
|
@@ -99,8 +99,24 @@ export function AutoCorrectPlugin({ stores, version, enabled, typing, urduNormal
|
|
|
99
99
|
root?.addEventListener('keydown', onKeyDown);
|
|
100
100
|
};
|
|
101
101
|
const unregister = editor.registerRootListener((next) => attach(next));
|
|
102
|
+
// A word with nothing after it (end of line or document) is corrected when the
|
|
103
|
+
// caret leaves it: Enter splits the line, and blur means the user has moved on.
|
|
104
|
+
const correctEndingWord = () => {
|
|
105
|
+
const selection = $getSelection();
|
|
106
|
+
if (!$isRangeSelection(selection))
|
|
107
|
+
return false;
|
|
108
|
+
const rtl = selection.anchor.getNode().getTopLevelElement()?.getDirection() === 'rtl';
|
|
109
|
+
const table = tableFor(rtl);
|
|
110
|
+
if (table)
|
|
111
|
+
$correctWordEndingAtCaret(table, rtl ? normalizeRtl : undefined);
|
|
112
|
+
return false;
|
|
113
|
+
};
|
|
114
|
+
const unregisterEnter = editor.registerCommand(KEY_ENTER_COMMAND, correctEndingWord, COMMAND_PRIORITY_HIGH);
|
|
115
|
+
const unregisterBlur = editor.registerCommand(BLUR_COMMAND, correctEndingWord, COMMAND_PRIORITY_EDITOR);
|
|
102
116
|
return () => {
|
|
103
117
|
unregister();
|
|
118
|
+
unregisterEnter();
|
|
119
|
+
unregisterBlur();
|
|
104
120
|
attach(null);
|
|
105
121
|
};
|
|
106
122
|
}, [editor, enabled, typing]);
|
|
@@ -32,4 +32,10 @@ export declare function $correctPunctuationDocument(rules: PunctuationRule[]): n
|
|
|
32
32
|
export declare function $preservingSelection(change: () => void): void;
|
|
33
33
|
/** Applies urduhack-style punctuation spacing to every text node. Returns how many changed. */
|
|
34
34
|
export declare function $spacePunctuationDocument(): number;
|
|
35
|
+
/**
|
|
36
|
+
* Corrects the word that ends at the caret when nothing follows it, which is the
|
|
37
|
+
* end of a line: the caret is about to leave the line (Enter). The caret ends
|
|
38
|
+
* after the replacement.
|
|
39
|
+
*/
|
|
40
|
+
export declare function $correctWordEndingAtCaret(table: Map<string, string>, normalize?: (word: string) => string): boolean;
|
|
35
41
|
//# sourceMappingURL=autoCorrectActions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoCorrectActions.d.ts","sourceRoot":"","sources":["../../src/autocorrect/autoCorrectActions.ts"],"names":[],"mappings":"AAWA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAMhF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAiCjH;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACxB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACxB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GACtC,MAAM,CA8BR;AAQD;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,OAAO,CAqBhF;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,MAAM,CA2B5E;AAID;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,IAAI,CAoB7D;AAED,+FAA+F;AAC/F,wBAAgB,yBAAyB,IAAI,MAAM,CAWlD"}
|
|
1
|
+
{"version":3,"file":"autoCorrectActions.d.ts","sourceRoot":"","sources":["../../src/autocorrect/autoCorrectActions.ts"],"names":[],"mappings":"AAWA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAMhF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAiCjH;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACxB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACxB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GACtC,MAAM,CA8BR;AAQD;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,OAAO,CAqBhF;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,MAAM,CA2B5E;AAID;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,IAAI,CAoB7D;AAED,+FAA+F;AAC/F,wBAAgB,yBAAyB,IAAI,MAAM,CAWlD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAuBnH"}
|
|
@@ -180,3 +180,33 @@ export function $spacePunctuationDocument() {
|
|
|
180
180
|
}
|
|
181
181
|
return changed;
|
|
182
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Corrects the word that ends at the caret when nothing follows it, which is the
|
|
185
|
+
* end of a line: the caret is about to leave the line (Enter). The caret ends
|
|
186
|
+
* after the replacement.
|
|
187
|
+
*/
|
|
188
|
+
export function $correctWordEndingAtCaret(table, normalize) {
|
|
189
|
+
const selection = $getSelection();
|
|
190
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed())
|
|
191
|
+
return false;
|
|
192
|
+
const anchor = selection.anchor;
|
|
193
|
+
const node = anchor.getNode();
|
|
194
|
+
if (!$isTextNode(node))
|
|
195
|
+
return false;
|
|
196
|
+
const before = node.getTextContent().slice(0, anchor.offset);
|
|
197
|
+
const word = WORD_END.exec(before)?.[0];
|
|
198
|
+
if (!word)
|
|
199
|
+
return false;
|
|
200
|
+
const replacement = correctionFor(word, table, normalize);
|
|
201
|
+
if (replacement === undefined || replacement === word)
|
|
202
|
+
return false;
|
|
203
|
+
const start = before.length - word.length;
|
|
204
|
+
$replaceMatch({ anchorKey: node.getKey(), anchorOffset: start, focusKey: node.getKey(), focusOffset: before.length }, replacement);
|
|
205
|
+
const after = $getSelection();
|
|
206
|
+
if ($isRangeSelection(after)) {
|
|
207
|
+
const caret = start + replacement.length;
|
|
208
|
+
after.anchor.set(node.getKey(), caret, 'text');
|
|
209
|
+
after.focus.set(node.getKey(), caret, 'text');
|
|
210
|
+
}
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import type { Strings } from '../i18n/strings.js';
|
|
2
2
|
import { type AutoCorrectStore } from '../autocorrect/autoCorrectStores.js';
|
|
3
|
+
import type { SpellLanguage } from '../spellcheck/spellDictionaries.js';
|
|
3
4
|
/**
|
|
4
5
|
* Adds one correction (a typed word and its replacement) to the first store
|
|
5
6
|
* that accepts writes. Saving bumps the editor's correction version, so the new
|
|
6
7
|
* entry applies to the next word the user types.
|
|
7
8
|
*/
|
|
8
|
-
export declare function AutoCorrectPanel({ strings, dir, stores, onSaved, onClose, }: {
|
|
9
|
+
export declare function AutoCorrectPanel({ strings, dir, stores, initialFrom, initialLanguage, onSaved, onClose, }: {
|
|
9
10
|
strings: Strings;
|
|
10
11
|
dir: 'ltr' | 'rtl';
|
|
11
12
|
stores: AutoCorrectStore[];
|
|
13
|
+
/** The typed word to start with, e.g. a misspelled word the user chose to correct. */
|
|
14
|
+
initialFrom?: string;
|
|
15
|
+
initialLanguage?: SpellLanguage;
|
|
12
16
|
onSaved: () => void;
|
|
13
17
|
onClose: () => void;
|
|
14
18
|
}): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAC/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAQrE;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,GAAG,EACH,MAAM,EACN,WAAgB,EAChB,eAAsB,EACtB,OAAO,EACP,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,KAAK,GAAG,KAAK,CAAC;IACnB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,aAAa,CAAC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,+BAqEA"}
|
|
@@ -12,10 +12,10 @@ const LANGUAGES = [
|
|
|
12
12
|
* that accepts writes. Saving bumps the editor's correction version, so the new
|
|
13
13
|
* entry applies to the next word the user types.
|
|
14
14
|
*/
|
|
15
|
-
export function AutoCorrectPanel({ strings, dir, stores, onSaved, onClose, }) {
|
|
15
|
+
export function AutoCorrectPanel({ strings, dir, stores, initialFrom = '', initialLanguage = 'en', onSaved, onClose, }) {
|
|
16
16
|
const t = strings.autoCorrect;
|
|
17
|
-
const [language, setLanguage] = useState(
|
|
18
|
-
const [from, setFrom] = useState(
|
|
17
|
+
const [language, setLanguage] = useState(initialLanguage);
|
|
18
|
+
const [from, setFrom] = useState(initialFrom);
|
|
19
19
|
const [to, setTo] = useState('');
|
|
20
20
|
const [status, setStatus] = useState('idle');
|
|
21
21
|
const save = async () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Strings } from '../i18n/strings.js';
|
|
2
|
+
import { type SpellLanguage } from '../spellcheck/spellDictionaries.js';
|
|
2
3
|
import { type UserWordStore } from '../spellcheck/userWords.js';
|
|
3
4
|
/**
|
|
4
5
|
* Steps through the misspelled words one at a time, like the find widget.
|
|
@@ -6,10 +7,11 @@ import { type UserWordStore } from '../spellcheck/userWords.js';
|
|
|
6
7
|
* can replace it. Checking reads the document on demand, so it never flags
|
|
7
8
|
* words while the user is still typing.
|
|
8
9
|
*/
|
|
9
|
-
export declare function SpellcheckPanel({ strings, dir, dictionaryStores, onClose, }: {
|
|
10
|
+
export declare function SpellcheckPanel({ strings, dir, dictionaryStores, onAddAutoCorrect, onClose, }: {
|
|
10
11
|
strings: Strings;
|
|
11
12
|
dir: 'ltr' | 'rtl';
|
|
12
13
|
dictionaryStores: UserWordStore[];
|
|
14
|
+
onAddAutoCorrect?: (word: string, language: SpellLanguage) => void;
|
|
13
15
|
onClose: () => void;
|
|
14
16
|
}): import("react").JSX.Element;
|
|
15
17
|
//# sourceMappingURL=SpellcheckPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpellcheckPanel.d.ts","sourceRoot":"","sources":["../../src/components/SpellcheckPanel.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"SpellcheckPanel.d.ts","sourceRoot":"","sources":["../../src/components/SpellcheckPanel.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAAkC,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrG,OAAO,EAA2B,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAgBtF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,GAAG,EACH,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,KAAK,GAAG,KAAK,CAAC;IACnB,gBAAgB,EAAE,aAAa,EAAE,CAAC;IAClC,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;IACnE,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,+BAqKA"}
|
|
@@ -18,7 +18,7 @@ const SUGGESTIONS_PER_WORD = 3;
|
|
|
18
18
|
* can replace it. Checking reads the document on demand, so it never flags
|
|
19
19
|
* words while the user is still typing.
|
|
20
20
|
*/
|
|
21
|
-
export function SpellcheckPanel({ strings, dir, dictionaryStores, onClose, }) {
|
|
21
|
+
export function SpellcheckPanel({ strings, dir, dictionaryStores, onAddAutoCorrect, onClose, }) {
|
|
22
22
|
const [editor] = useLexicalComposerContext();
|
|
23
23
|
const t = strings.spellcheck;
|
|
24
24
|
const [language, setLanguage] = useState('en');
|
|
@@ -87,5 +87,5 @@ export function SpellcheckPanel({ strings, dir, dictionaryStores, onClose, }) {
|
|
|
87
87
|
ignoreWord(language, current.word);
|
|
88
88
|
void check();
|
|
89
89
|
});
|
|
90
|
-
}, children: strings.contextMenu.addToDictionary })] }), 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))) }))] }))] }));
|
|
90
|
+
}, children: strings.contextMenu.addToDictionary }), onAddAutoCorrect && (_jsx("button", { type: "button", className: "likhari-spell-suggestion", onClick: () => onAddAutoCorrect(current.word, language), children: strings.contextMenu.addToAutoCorrect }))] }), 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))) }))] }))] }));
|
|
91
91
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SpellLanguage } from '../spellcheck/spellDictionaries.js';
|
|
1
2
|
import { type UserWordStore } from '../spellcheck/userWords.js';
|
|
2
3
|
import { type DraftsToolbarOptions } from './DraftsDialog.js';
|
|
3
4
|
import type { ResolvedEditorFeatureConfig } from '@inshapardaz/likhari-core';
|
|
@@ -7,6 +8,8 @@ export interface ToolbarProps {
|
|
|
7
8
|
config: ResolvedEditorFeatureConfig;
|
|
8
9
|
/** Where words added to the dictionary are saved. */
|
|
9
10
|
dictionaryStores?: UserWordStore[];
|
|
11
|
+
/** Opens the auto-correct panel with the word filled in. */
|
|
12
|
+
onAddAutoCorrect?: (word: string, language: SpellLanguage) => void;
|
|
10
13
|
/** Whether the find-and-replace widget is open, and how to toggle it (owned by EditorRoot). */
|
|
11
14
|
findOpen?: boolean;
|
|
12
15
|
onToggleFind?: () => void;
|
|
@@ -28,5 +31,5 @@ export interface ToolbarProps {
|
|
|
28
31
|
/** Autosave drafts: when set, the toolbar offers a Drafts button that lists and restores them. */
|
|
29
32
|
drafts?: DraftsToolbarOptions;
|
|
30
33
|
}
|
|
31
|
-
export declare function Toolbar({ config, dictionaryStores, onSave, isDirty, showSave, findOpen, onToggleFind, spellOpen, onToggleSpell, autoCorrectOpen, onToggleAutoCorrect, fontOptions, direction, locale, drafts }: ToolbarProps): import("react").JSX.Element;
|
|
34
|
+
export declare function Toolbar({ config, dictionaryStores, onAddAutoCorrect, onSave, isDirty, showSave, findOpen, onToggleFind, spellOpen, onToggleSpell, autoCorrectOpen, onToggleAutoCorrect, fontOptions, direction, locale, drafts }: ToolbarProps): import("react").JSX.Element;
|
|
32
35
|
//# 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":"AA0CA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,EAA2B,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAgDtF,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;AA6hBvD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,2BAA2B,CAAC;IACpC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,aAAa,EAAE,CAAC;IACnC,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;IACnE,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,wFAAwF;IACxF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,iGAAiG;IACjG,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,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,gBAAqB,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAgB,EAAE,YAAY,EAAE,SAAiB,EAAE,aAAa,EAAE,eAAuB,EAAE,mBAAmB,EAAE,WAAkC,EAAE,SAAiB,EAAE,MAAa,EAAE,MAAM,EAAE,EAAE,YAAY,+BAqnCjT"}
|
|
@@ -185,7 +185,7 @@ function PoetryMenuItems({ strings, layout, scale, centered, onAction, }) {
|
|
|
185
185
|
};
|
|
186
186
|
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')] }));
|
|
187
187
|
}
|
|
188
|
-
export function Toolbar({ config, dictionaryStores = [], onSave, isDirty, showSave, findOpen = false, onToggleFind, spellOpen = false, onToggleSpell, autoCorrectOpen = false, onToggleAutoCorrect, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
|
|
188
|
+
export function Toolbar({ config, dictionaryStores = [], onAddAutoCorrect, onSave, isDirty, showSave, findOpen = false, onToggleFind, spellOpen = false, onToggleSpell, autoCorrectOpen = false, onToggleAutoCorrect, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
|
|
189
189
|
const [editor] = useLexicalComposerContext();
|
|
190
190
|
const [state, setState] = useState(INITIAL_STATE);
|
|
191
191
|
const strings = useStrings(locale);
|
|
@@ -842,7 +842,10 @@ export function Toolbar({ config, dictionaryStores = [], onSave, isDirty, showSa
|
|
|
842
842
|
ignoreWord(language, word);
|
|
843
843
|
});
|
|
844
844
|
setContextMenu(null);
|
|
845
|
-
}, children: strings.contextMenu.addToDictionary }),
|
|
845
|
+
}, children: strings.contextMenu.addToDictionary }), onAddAutoCorrect && config.language.autocorrect && (_jsx(Menu.Item, { onClick: () => {
|
|
846
|
+
onAddAutoCorrect(contextMenu.spelling.word, contextMenu.spelling.language);
|
|
847
|
+
setContextMenu(null);
|
|
848
|
+
}, children: strings.contextMenu.addToAutoCorrect })), _jsx(Menu.Divider, {})] })), contextMenu?.link !== undefined && (_jsxs(_Fragment, { children: [_jsx(LinkMenuItems, { url: contextMenu.link, onEdit: () => {
|
|
846
849
|
restoreSelection();
|
|
847
850
|
openLinkDialog();
|
|
848
851
|
}, onRemove: removeLink, strings: strings }), _jsx(Menu.Divider, {})] })), contextMenu?.table && (_jsxs(_Fragment, { children: [_jsx(TableMenuItems, { strings: strings, direction: direction, rows: contextMenu.table.rows, columns: contextMenu.table.columns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction }), _jsx(Menu.Divider, {})] })), contextMenu?.poetry && (_jsxs(_Fragment, { children: [_jsx(PoetryMenuItems, { strings: strings, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction }), _jsx(Menu.Divider, {})] })), _jsx(Menu.Item, { leftSection: _jsx(IconCut, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: () => void copyOrCut(true)(), children: strings.contextMenu.cut }), _jsx(Menu.Item, { leftSection: _jsx(IconCopy, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: () => void copyOrCut(false)(), children: strings.contextMenu.copy }), _jsx(Menu.Item, { leftSection: _jsx(IconClipboard, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: () => void paste(), children: strings.contextMenu.paste }), _jsx(Menu.Item, { leftSection: _jsx(IconSelectAll, { size: ICON_SIZE, stroke: ICON_STROKE }), onClick: runMenuAction(() => $selectAll()), children: strings.contextMenu.selectAll })] })] }), _jsxs("div", { "aria-hidden": "true", ref: toolbarMeasureRef, style: {
|
package/dist/i18n/strings.d.ts
CHANGED
|
@@ -200,9 +200,13 @@ export interface Strings {
|
|
|
200
200
|
selectAll: string;
|
|
201
201
|
ignore: string;
|
|
202
202
|
addToDictionary: string;
|
|
203
|
+
addToAutoCorrect: string;
|
|
203
204
|
spelling: string;
|
|
204
205
|
noSuggestions: string;
|
|
205
206
|
};
|
|
207
|
+
autoComplete: {
|
|
208
|
+
label: string;
|
|
209
|
+
};
|
|
206
210
|
link: {
|
|
207
211
|
menuLabel: string;
|
|
208
212
|
noUrl: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/strings.js
CHANGED
|
@@ -183,9 +183,13 @@ const en = {
|
|
|
183
183
|
selectAll: 'Select all',
|
|
184
184
|
ignore: 'Ignore',
|
|
185
185
|
addToDictionary: 'Add to dictionary',
|
|
186
|
+
addToAutoCorrect: 'Add to auto-correct',
|
|
186
187
|
spelling: 'Spelling suggestions',
|
|
187
188
|
noSuggestions: 'No suggestions',
|
|
188
189
|
},
|
|
190
|
+
autoComplete: {
|
|
191
|
+
label: 'Suggestions',
|
|
192
|
+
},
|
|
189
193
|
link: {
|
|
190
194
|
menuLabel: 'Link',
|
|
191
195
|
noUrl: '(no URL)',
|
|
@@ -450,9 +454,13 @@ const ur = {
|
|
|
450
454
|
selectAll: 'سب منتخب کریں',
|
|
451
455
|
ignore: 'نظرانداز کریں',
|
|
452
456
|
addToDictionary: 'لغت میں شامل کریں',
|
|
457
|
+
addToAutoCorrect: 'خودکار تصحیح میں شامل کریں',
|
|
453
458
|
spelling: 'ہجے کی تجاویز',
|
|
454
459
|
noSuggestions: 'کوئی تجویز نہیں',
|
|
455
460
|
},
|
|
461
|
+
autoComplete: {
|
|
462
|
+
label: 'تجاویز',
|
|
463
|
+
},
|
|
456
464
|
link: {
|
|
457
465
|
menuLabel: 'لنک',
|
|
458
466
|
noUrl: '(کوئی یو آر ایل نہیں)',
|
|
@@ -717,9 +725,13 @@ const paShahmukhi = {
|
|
|
717
725
|
selectAll: 'سارا چنو',
|
|
718
726
|
ignore: 'نظر انداز کرو',
|
|
719
727
|
addToDictionary: 'شبدکوش وچ پاؤ',
|
|
728
|
+
addToAutoCorrect: 'خودکار درستی وچ پاؤ',
|
|
720
729
|
spelling: 'ہجے دیاں تجویزاں',
|
|
721
730
|
noSuggestions: 'کوئی تجویز نئیں',
|
|
722
731
|
},
|
|
732
|
+
autoComplete: {
|
|
733
|
+
label: 'تجویزاں',
|
|
734
|
+
},
|
|
723
735
|
link: {
|
|
724
736
|
menuLabel: 'لنک',
|
|
725
737
|
noUrl: '(کوئی یو آر ایل نئیں)',
|
package/dist/index.d.ts
CHANGED
|
@@ -16,4 +16,6 @@ export type { UrduNormalizationOptions } from './normalization/urduNormalize.js'
|
|
|
16
16
|
export type { PunctuationOptions, PunctuationRule } from './autocorrect/punctuationRules.js';
|
|
17
17
|
export { localStorageUserWordStore, apiUserWordStore, ignoreWord, addUserWord, onSpellWordsChange } from './spellcheck/userWords.js';
|
|
18
18
|
export type { UserWordStore } from './spellcheck/userWords.js';
|
|
19
|
+
export { dictionaryCompletionStore, apiCompletionStore } from './autocomplete/completionStores.js';
|
|
20
|
+
export type { CompletionStore } from './autocomplete/completionStores.js';
|
|
19
21
|
//# 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;AACrI,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC1H,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAChI,YAAY,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAClI,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,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;AACrI,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC1H,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAChI,YAAY,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAClI,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAChG,YAAY,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,3 +7,4 @@ export { registerSpellDictionary, hasSpellDictionary } from './spellcheck/spellD
|
|
|
7
7
|
export { localStorageAutoCorrectStore, apiAutoCorrectStore, fileAutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
8
8
|
export { normalizeUrdu, normalizeUrduCharacters, removeUrduDiacritics, replaceUrduDigits } from './normalization/urduNormalize.js';
|
|
9
9
|
export { localStorageUserWordStore, apiUserWordStore, ignoreWord, addUserWord, onSpellWordsChange } from './spellcheck/userWords.js';
|
|
10
|
+
export { dictionaryCompletionStore, apiCompletionStore } from './autocomplete/completionStores.js';
|
|
@@ -27,6 +27,10 @@ export declare function hasSpellDictionary(language: SpellLanguage): boolean;
|
|
|
27
27
|
* can skip spellchecking that language rather than flag every word.
|
|
28
28
|
*/
|
|
29
29
|
export declare function getSpeller(language: SpellLanguage): Promise<Speller> | null;
|
|
30
|
+
/** The dictionary's root words (its .dic entries without affix flags), for completion. */
|
|
31
|
+
export declare function dictionaryWords(dic: string): string[];
|
|
32
|
+
/** The language's dictionary words, or null when no dictionary is registered. */
|
|
33
|
+
export declare function getDictionaryWords(language: SpellLanguage): Promise<string[]> | null;
|
|
30
34
|
/** A word in a text, with its position as character offsets. */
|
|
31
35
|
export interface WordSpan {
|
|
32
36
|
word: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spellDictionaries.d.ts","sourceRoot":"","sources":["../../src/spellcheck/spellDictionaries.ts"],"names":[],"mappings":"AAGA,4DAA4D;AAC5D,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,cAAc,CAAC;AAEzD,wFAAwF;AACxF,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACjC;AAED,KAAK,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"spellDictionaries.d.ts","sourceRoot":"","sources":["../../src/spellcheck/spellDictionaries.ts"],"names":[],"mappings":"AAGA,4DAA4D;AAC5D,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,cAAc,CAAC;AAEzD,wFAAwF;AACxF,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACjC;AAED,KAAK,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;AAoB3C;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAIpG;AAED,2DAA2D;AAC3D,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAc3E;AAYD,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAOrD;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAGpF;AAED,gEAAgE;AAChE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AASD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAMhD;AAED,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,EAAE,CAEzE"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import nspell from 'nspell';
|
|
2
2
|
import { isAcceptedWord } from './userWords.js';
|
|
3
3
|
const loaders = new Map();
|
|
4
|
+
const loadedFiles = new Map();
|
|
4
5
|
const spellers = new Map();
|
|
5
6
|
async function fetchText(url) {
|
|
6
7
|
const response = await fetch(url);
|
|
@@ -23,6 +24,7 @@ loaders.set('en', englishLoader);
|
|
|
23
24
|
export function registerSpellDictionary(language, files) {
|
|
24
25
|
loaders.set(language, typeof files === 'function' ? files : async () => files);
|
|
25
26
|
spellers.delete(language);
|
|
27
|
+
loadedFiles.delete(language);
|
|
26
28
|
}
|
|
27
29
|
/** Whether a dictionary is registered for the language. */
|
|
28
30
|
export function hasSpellDictionary(language) {
|
|
@@ -34,12 +36,11 @@ export function hasSpellDictionary(language) {
|
|
|
34
36
|
* can skip spellchecking that language rather than flag every word.
|
|
35
37
|
*/
|
|
36
38
|
export function getSpeller(language) {
|
|
37
|
-
|
|
38
|
-
if (!loader)
|
|
39
|
+
if (!loaders.has(language))
|
|
39
40
|
return null;
|
|
40
41
|
let speller = spellers.get(language);
|
|
41
42
|
if (!speller) {
|
|
42
|
-
speller =
|
|
43
|
+
speller = filesFor(language)
|
|
43
44
|
.then(({ aff, dic }) => nspell(aff, dic))
|
|
44
45
|
.then((base) => ({
|
|
45
46
|
// Words the user added or ignored count as correct, whatever the dictionary says.
|
|
@@ -50,6 +51,31 @@ export function getSpeller(language) {
|
|
|
50
51
|
}
|
|
51
52
|
return speller;
|
|
52
53
|
}
|
|
54
|
+
/** The dictionary's files, loaded once per language and shared by the speller and the word list. */
|
|
55
|
+
function filesFor(language) {
|
|
56
|
+
let loaded = loadedFiles.get(language);
|
|
57
|
+
if (!loaded) {
|
|
58
|
+
loaded = loaders.get(language)();
|
|
59
|
+
loadedFiles.set(language, loaded);
|
|
60
|
+
}
|
|
61
|
+
return loaded;
|
|
62
|
+
}
|
|
63
|
+
/** The dictionary's root words (its .dic entries without affix flags), for completion. */
|
|
64
|
+
export function dictionaryWords(dic) {
|
|
65
|
+
const words = new Set();
|
|
66
|
+
for (const line of dic.split(/\r?\n/).slice(1)) {
|
|
67
|
+
const word = line.split('/')[0].trim();
|
|
68
|
+
if (word)
|
|
69
|
+
words.add(word);
|
|
70
|
+
}
|
|
71
|
+
return [...words];
|
|
72
|
+
}
|
|
73
|
+
/** The language's dictionary words, or null when no dictionary is registered. */
|
|
74
|
+
export function getDictionaryWords(language) {
|
|
75
|
+
if (!loaders.has(language))
|
|
76
|
+
return null;
|
|
77
|
+
return filesFor(language).then(({ dic }) => dictionaryWords(dic));
|
|
78
|
+
}
|
|
53
79
|
/**
|
|
54
80
|
* Letters and combining marks, with apostrophes inside a word kept. The
|
|
55
81
|
* Unicode classes cover Arabic-script letters and their diacritics, so Urdu
|
|
@@ -24,6 +24,8 @@ export declare function apiUserWordStore(options: {
|
|
|
24
24
|
headers?: Record<string, string>;
|
|
25
25
|
fetch?: typeof fetch;
|
|
26
26
|
}): UserWordStore;
|
|
27
|
+
/** The words the user has added to the dictionary for a language. */
|
|
28
|
+
export declare function acceptedWords(language: SpellLanguage): string[];
|
|
27
29
|
/** Calls `listener` whenever accepted or ignored words change. Returns an unsubscribe function. */
|
|
28
30
|
export declare function onSpellWordsChange(listener: () => void): () => void;
|
|
29
31
|
/** Whether the speller should treat the word as correct: it is in the user's dictionary or ignored this session. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"userWords.d.ts","sourceRoot":"","sources":["../../src/spellcheck/userWords.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjD,MAAM,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAoBD,0EAA0E;AAC1E,wBAAgB,yBAAyB,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,aAAa,CAoBvF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACxC,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,aAAa,CAmBhB;AAWD,mGAAmG;AACnG,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAGnE;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7E;AAED,2EAA2E;AAC3E,wBAAsB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ1E;AAED,sFAAsF;AACtF,wBAAsB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOlH;AAWD,+DAA+D;AAC/D,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAUtE"}
|
|
1
|
+
{"version":3,"file":"userWords.d.ts","sourceRoot":"","sources":["../../src/spellcheck/userWords.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjD,MAAM,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAoBD,0EAA0E;AAC1E,wBAAgB,yBAAyB,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,aAAa,CAoBvF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACxC,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,aAAa,CAmBhB;AAWD,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAE/D;AAED,mGAAmG;AACnG,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAGnE;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7E;AAED,2EAA2E;AAC3E,wBAAsB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ1E;AAED,sFAAsF;AACtF,wBAAsB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOlH;AAWD,+DAA+D;AAC/D,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAUtE"}
|
|
@@ -68,6 +68,10 @@ function notify() {
|
|
|
68
68
|
for (const listener of listeners)
|
|
69
69
|
listener();
|
|
70
70
|
}
|
|
71
|
+
/** The words the user has added to the dictionary for a language. */
|
|
72
|
+
export function acceptedWords(language) {
|
|
73
|
+
return [...(accepted.get(language) ?? [])];
|
|
74
|
+
}
|
|
71
75
|
/** Calls `listener` whenever accepted or ignored words change. Returns an unsubscribe function. */
|
|
72
76
|
export function onSpellWordsChange(listener) {
|
|
73
77
|
listeners.add(listener);
|
package/dist/theme/editor.css
CHANGED
|
@@ -1055,3 +1055,25 @@
|
|
|
1055
1055
|
cursor: default;
|
|
1056
1056
|
}
|
|
1057
1057
|
|
|
1058
|
+
/* Autocomplete suggestions, shown under the caret while typing. */
|
|
1059
|
+
.likhari-autocomplete {
|
|
1060
|
+
z-index: 20;
|
|
1061
|
+
min-width: 160px;
|
|
1062
|
+
max-width: 280px;
|
|
1063
|
+
padding: 4px 0;
|
|
1064
|
+
border: 1px solid var(--editor-line);
|
|
1065
|
+
border-radius: 6px;
|
|
1066
|
+
background: var(--editor-paper-dim);
|
|
1067
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.16);
|
|
1068
|
+
font-size: 14px;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
.likhari-autocomplete-item {
|
|
1072
|
+
padding: 3px 10px;
|
|
1073
|
+
cursor: pointer;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
.likhari-autocomplete-item--active {
|
|
1077
|
+
background: var(--editor-accent-soft);
|
|
1078
|
+
}
|
|
1079
|
+
|