@inshapardaz/likhari-react 0.1.50 → 0.1.51-dev.407
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/autocorrect/AutoCorrectPlugin.d.ts.map +1 -1
- package/dist/autocorrect/AutoCorrectPlugin.js +25 -5
- package/dist/autocorrect/autoCorrectActions.d.ts.map +1 -1
- package/dist/autocorrect/autoCorrectActions.js +5 -3
- package/dist/autocorrect/autoCorrectStores.d.ts +17 -1
- package/dist/autocorrect/autoCorrectStores.d.ts.map +1 -1
- package/dist/autocorrect/autoCorrectStores.js +68 -12
- package/dist/autocorrect/punctuationRules.d.ts +8 -0
- package/dist/autocorrect/punctuationRules.d.ts.map +1 -1
- package/dist/autocorrect/punctuationRules.js +13 -2
- package/dist/cleanup/textCleanupActions.d.ts +3 -2
- package/dist/cleanup/textCleanupActions.d.ts.map +1 -1
- package/dist/cleanup/textCleanupActions.js +21 -3
- package/dist/components/AutoCorrectPanel.d.ts.map +1 -1
- package/dist/components/AutoCorrectPanel.js +3 -2
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +107 -29
- package/dist/components/ToolbarSettingsPanel.d.ts +17 -0
- package/dist/components/ToolbarSettingsPanel.d.ts.map +1 -0
- package/dist/components/ToolbarSettingsPanel.js +12 -0
- package/dist/i18n/strings.d.ts +18 -0
- package/dist/i18n/strings.d.ts.map +1 -1
- package/dist/i18n/strings.js +48 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/theme/editor.css +54 -0
- package/dist/toolbar/toolbarVisibility.d.ts +23 -0
- package/dist/toolbar/toolbarVisibility.d.ts.map +1 -0
- package/dist/toolbar/toolbarVisibility.js +40 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,EAAwB,MAAM,oBAAoB,CAAC;AAC3G,OAAO,EAAiD,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC3G,OAAO,EAAiB,KAAK,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAG9F,sFAAsF;AACtF,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,EAAE,cAAc,CAAC,IAAI,CAA6C,CAAC;AAqBxG;;;;;;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,QAgHA"}
|
|
@@ -4,7 +4,7 @@ import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR, BLUR_COMMAND
|
|
|
4
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
|
-
import {
|
|
7
|
+
import { loadAutoCorrectEntries } from './autoCorrectStores.js';
|
|
8
8
|
import { normalizeUrdu } from '../normalization/urduNormalize.js';
|
|
9
9
|
/** Keys that end a word: a space or punctuation, in Latin and Arabic-script forms. */
|
|
10
10
|
/** Corrects every word in the document, e.g. after pasting or loading content. */
|
|
@@ -12,6 +12,21 @@ export const CORRECT_DOCUMENT_COMMAND = createCommand('CORRECT_DOCUMENT_COMMAND'
|
|
|
12
12
|
const BOUNDARY_KEYS = new Set([' ', '.', ',', ';', ':', '!', '?', '،', '؛', '؟', '۔']);
|
|
13
13
|
const LANGUAGES = ['en', 'ur', 'pa-shahmukhi'];
|
|
14
14
|
const RTL_LANGUAGES = ['ur', 'pa-shahmukhi'];
|
|
15
|
+
/** The whole-word entries (the default) as a from-to table. */
|
|
16
|
+
function wholeWordTable(entries) {
|
|
17
|
+
const table = new Map();
|
|
18
|
+
for (const entry of entries)
|
|
19
|
+
if (entry.wholeWord !== false)
|
|
20
|
+
table.set(entry.from, entry.to);
|
|
21
|
+
return table;
|
|
22
|
+
}
|
|
23
|
+
/** Entries marked "not whole word only", as substring-matching rules, longest first. */
|
|
24
|
+
function substringAutoCorrectRules(entries) {
|
|
25
|
+
return entries
|
|
26
|
+
.filter((entry) => entry.wholeWord === false)
|
|
27
|
+
.map((entry) => ({ incorrect: entry.from, correct: entry.to, completeWord: false }))
|
|
28
|
+
.sort((a, b) => b.incorrect.length - a.incorrect.length);
|
|
29
|
+
}
|
|
15
30
|
/**
|
|
16
31
|
* Corrects typed words as the user finishes them, the way the reference editor
|
|
17
32
|
* does, but from any set of stores. Corrections are loaded once per change
|
|
@@ -26,17 +41,21 @@ export function AutoCorrectPlugin({ stores, version, enabled, typing, urduNormal
|
|
|
26
41
|
normalizeOptions.current = urduNormalization;
|
|
27
42
|
const punctuationRules = useRef(activePunctuationRules(punctuation));
|
|
28
43
|
punctuationRules.current = activePunctuationRules(punctuation);
|
|
44
|
+
const combinedRules = () => [...punctuationRules.current, ...substringRules.current].sort((a, b) => b.incorrect.length - a.incorrect.length);
|
|
29
45
|
const normalizeRtl = (text) => normalizeUrdu(text, normalizeOptions.current);
|
|
30
46
|
const tables = useRef(new Map());
|
|
31
47
|
const rtlTable = useRef(new Map());
|
|
48
|
+
// Corrections marked "not whole word only" apply even inside a longer word, so they
|
|
49
|
+
// run through the same substring-matching machinery as the punctuation rules.
|
|
50
|
+
const substringRules = useRef([]);
|
|
32
51
|
useEffect(() => {
|
|
33
52
|
if (!enabled)
|
|
34
53
|
return;
|
|
35
54
|
let active = true;
|
|
36
|
-
Promise.all(LANGUAGES.map(async (language) => [language, await
|
|
55
|
+
Promise.all(LANGUAGES.map(async (language) => [language, await loadAutoCorrectEntries(stores, language)])).then((loaded) => {
|
|
37
56
|
if (!active)
|
|
38
57
|
return;
|
|
39
|
-
tables.current = new Map(loaded);
|
|
58
|
+
tables.current = new Map(loaded.map(([language, entries]) => [language, wholeWordTable(entries)]));
|
|
40
59
|
// Urdu and Shahmukhi share right-to-left blocks, so both apply there; Urdu wins a clash.
|
|
41
60
|
const combined = new Map();
|
|
42
61
|
for (const language of RTL_LANGUAGES) {
|
|
@@ -45,6 +64,7 @@ export function AutoCorrectPlugin({ stores, version, enabled, typing, urduNormal
|
|
|
45
64
|
combined.set(from, to);
|
|
46
65
|
}
|
|
47
66
|
rtlTable.current = combined;
|
|
67
|
+
substringRules.current = loaded.flatMap(([, entries]) => substringAutoCorrectRules(entries));
|
|
48
68
|
});
|
|
49
69
|
return () => {
|
|
50
70
|
active = false;
|
|
@@ -59,7 +79,7 @@ export function AutoCorrectPlugin({ stores, version, enabled, typing, urduNormal
|
|
|
59
79
|
$cleanUpText();
|
|
60
80
|
if (punctuation?.spacing)
|
|
61
81
|
$spacePunctuationDocument();
|
|
62
|
-
$correctPunctuationDocument(
|
|
82
|
+
$correctPunctuationDocument(combinedRules());
|
|
63
83
|
$correctDocument(tables.current.get('en') ?? new Map(), rtlTable.current, normalizeRtl);
|
|
64
84
|
});
|
|
65
85
|
}, { discrete: true });
|
|
@@ -81,7 +101,7 @@ export function AutoCorrectPlugin({ stores, version, enabled, typing, urduNormal
|
|
|
81
101
|
if (!$isRangeSelection(selection))
|
|
82
102
|
return;
|
|
83
103
|
// Punctuation can end in any character (e.g. the letter ه), so every key is checked.
|
|
84
|
-
$correctPunctuationBeforeCaret(
|
|
104
|
+
$correctPunctuationBeforeCaret(combinedRules());
|
|
85
105
|
if (!boundary)
|
|
86
106
|
return;
|
|
87
107
|
const block = selection.anchor.getNode().getTopLevelElement();
|
|
@@ -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,
|
|
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,CAsBhF;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,MAAM,CA4B5E;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"}
|
|
@@ -100,10 +100,11 @@ export function $correctPunctuationBeforeCaret(rules) {
|
|
|
100
100
|
if (!rule)
|
|
101
101
|
return false;
|
|
102
102
|
const start = before.length - rule.incorrect.length;
|
|
103
|
-
|
|
103
|
+
const replacement = rule.resolve ? rule.resolve(before.slice(0, start)) : rule.correct;
|
|
104
|
+
$replaceMatch({ anchorKey: node.getKey(), anchorOffset: start, focusKey: node.getKey(), focusOffset: before.length }, replacement);
|
|
104
105
|
const after = $getSelection();
|
|
105
106
|
if ($isRangeSelection(after)) {
|
|
106
|
-
const caret = start +
|
|
107
|
+
const caret = start + replacement.length;
|
|
107
108
|
after.anchor.set(node.getKey(), caret, 'text');
|
|
108
109
|
after.focus.set(node.getKey(), caret, 'text');
|
|
109
110
|
}
|
|
@@ -121,7 +122,8 @@ export function $correctPunctuationDocument(rules) {
|
|
|
121
122
|
for (const rule of rules) {
|
|
122
123
|
let index = text.indexOf(rule.incorrect);
|
|
123
124
|
while (index !== -1) {
|
|
124
|
-
|
|
125
|
+
const correct = rule.resolve ? rule.resolve(text.slice(0, index)) : rule.correct;
|
|
126
|
+
candidates.push({ start: index, end: index + rule.incorrect.length, correct });
|
|
125
127
|
index = text.indexOf(rule.incorrect, index + 1);
|
|
126
128
|
}
|
|
127
129
|
}
|
|
@@ -3,6 +3,8 @@ import type { SpellLanguage } from '../spellcheck/spellDictionaries.js';
|
|
|
3
3
|
export interface AutoCorrectEntry {
|
|
4
4
|
from: string;
|
|
5
5
|
to: string;
|
|
6
|
+
/** Whole word only (default), or applied even inside a longer word. */
|
|
7
|
+
wholeWord?: boolean;
|
|
6
8
|
}
|
|
7
9
|
/**
|
|
8
10
|
* Where auto-corrections come from and go. The host supplies any number of
|
|
@@ -45,7 +47,21 @@ export declare function fileAutoCorrectStore(options: {
|
|
|
45
47
|
url: string;
|
|
46
48
|
fetch?: typeof fetch;
|
|
47
49
|
}): AutoCorrectStore;
|
|
48
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* The bundled Urdu auto-correct corpus from
|
|
52
|
+
* https://api.nawishta.co.uk/tools/ur/spellchecker/autocorrect, which serves a
|
|
53
|
+
* fixed Urdu list regardless of the `language` requested — so this store only
|
|
54
|
+
* answers for `'ur'`. Read-only: it has no documented endpoint for adding
|
|
55
|
+
* entries, so pair it with a writable store (e.g. `localStorageAutoCorrectStore`)
|
|
56
|
+
* for corrections added through the editor.
|
|
57
|
+
*/
|
|
58
|
+
export declare function nawishtaAutoCorrectStore(options?: {
|
|
59
|
+
url?: string;
|
|
60
|
+
fetch?: typeof fetch;
|
|
61
|
+
}): AutoCorrectStore;
|
|
62
|
+
/** Every correction for one language, merged across stores (the first listed wins a clash). Failing stores are skipped. */
|
|
63
|
+
export declare function loadAutoCorrectEntries(stores: AutoCorrectStore[], language: SpellLanguage): Promise<AutoCorrectEntry[]>;
|
|
64
|
+
/** The whole-word corrections for one language, merged across stores, as a from-to table. */
|
|
49
65
|
export declare function loadAutoCorrections(stores: AutoCorrectStore[], language: SpellLanguage): Promise<Map<string, string>>;
|
|
50
66
|
/** Saves a correction to the first store that accepts writes. Returns false if none does. */
|
|
51
67
|
export declare function appendAutoCorrection(stores: AutoCorrectStore[], language: SpellLanguage, entry: AutoCorrectEntry): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;IACX,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;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;AAmBD;;;;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,CAoBlH;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CAAO,GAAG,gBAAgB,CAwC/G;AAED,2HAA2H;AAC3H,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAa7H;AAED,6FAA6F;AAC7F,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAK3H;AAED,6FAA6F;AAC7F,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAKzI"}
|
|
@@ -4,7 +4,8 @@ function isEntry(value) {
|
|
|
4
4
|
value !== null &&
|
|
5
5
|
typeof value.from === 'string' &&
|
|
6
6
|
typeof value.to === 'string' &&
|
|
7
|
-
value.from !== ''
|
|
7
|
+
value.from !== '' &&
|
|
8
|
+
(value.wholeWord === undefined || typeof value.wholeWord === 'boolean'));
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
11
|
* Corrections kept in this browser's localStorage. Storage can be disabled or
|
|
@@ -27,11 +28,11 @@ export function localStorageAutoCorrectStore(options = {}) {
|
|
|
27
28
|
async load(language) {
|
|
28
29
|
return readAll()
|
|
29
30
|
.filter((e) => e.language === language)
|
|
30
|
-
.map(({ from, to }) => ({ from, to }));
|
|
31
|
+
.map(({ from, to, wholeWord }) => ({ from, to, wholeWord }));
|
|
31
32
|
},
|
|
32
33
|
async append(language, entry) {
|
|
33
34
|
const all = readAll().filter((e) => !(e.language === language && e.from === entry.from));
|
|
34
|
-
all.push({ language, from: entry.from, to: entry.to });
|
|
35
|
+
all.push({ language, from: entry.from, to: entry.to, wholeWord: entry.wholeWord });
|
|
35
36
|
try {
|
|
36
37
|
localStorage.setItem(key, JSON.stringify(all));
|
|
37
38
|
}
|
|
@@ -55,13 +56,13 @@ export function apiAutoCorrectStore(options) {
|
|
|
55
56
|
if (!response.ok)
|
|
56
57
|
throw new Error(`Auto-correct API failed: ${response.status}`);
|
|
57
58
|
const data = await response.json();
|
|
58
|
-
return Array.isArray(data) ? data.filter(isEntry).map(({ from, to }) => ({ from, to })) : [];
|
|
59
|
+
return Array.isArray(data) ? data.filter(isEntry).map(({ from, to, wholeWord }) => ({ from, to, wholeWord })) : [];
|
|
59
60
|
},
|
|
60
61
|
async append(language, entry) {
|
|
61
62
|
const response = await doFetch(options.url, {
|
|
62
63
|
method: 'POST',
|
|
63
64
|
headers: { 'Content-Type': 'application/json', ...options.headers },
|
|
64
|
-
body: JSON.stringify({ language, from: entry.from, to: entry.to }),
|
|
65
|
+
body: JSON.stringify({ language, from: entry.from, to: entry.to, wholeWord: entry.wholeWord }),
|
|
65
66
|
});
|
|
66
67
|
if (!response.ok)
|
|
67
68
|
throw new Error(`Auto-correct API rejected the entry: ${response.status}`);
|
|
@@ -88,21 +89,76 @@ export function fileAutoCorrectStore(options) {
|
|
|
88
89
|
id: options.id ?? 'file',
|
|
89
90
|
readOnly: true,
|
|
90
91
|
async load(language) {
|
|
91
|
-
return (await all())
|
|
92
|
+
return (await all())
|
|
93
|
+
.filter((e) => e.language === language)
|
|
94
|
+
.map(({ from, to, wholeWord }) => ({ from, to, wholeWord }));
|
|
92
95
|
},
|
|
93
96
|
};
|
|
94
97
|
}
|
|
95
|
-
/**
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
/**
|
|
99
|
+
* The bundled Urdu auto-correct corpus from
|
|
100
|
+
* https://api.nawishta.co.uk/tools/ur/spellchecker/autocorrect, which serves a
|
|
101
|
+
* fixed Urdu list regardless of the `language` requested — so this store only
|
|
102
|
+
* answers for `'ur'`. Read-only: it has no documented endpoint for adding
|
|
103
|
+
* entries, so pair it with a writable store (e.g. `localStorageAutoCorrectStore`)
|
|
104
|
+
* for corrections added through the editor.
|
|
105
|
+
*/
|
|
106
|
+
export function nawishtaAutoCorrectStore(options = {}) {
|
|
107
|
+
const url = options.url ?? 'https://api.nawishta.co.uk/tools/ur/spellchecker/autocorrect';
|
|
108
|
+
const doFetch = options.fetch ?? fetch;
|
|
109
|
+
let cached = null;
|
|
110
|
+
function isNawishtaEntry(value) {
|
|
111
|
+
return (typeof value === 'object' &&
|
|
112
|
+
value !== null &&
|
|
113
|
+
typeof value.incorrectText === 'string' &&
|
|
114
|
+
typeof value.correctText === 'string' &&
|
|
115
|
+
value.incorrectText !== '');
|
|
116
|
+
}
|
|
117
|
+
const load = () => {
|
|
118
|
+
cached ?? (cached = doFetch(url).then(async (response) => {
|
|
119
|
+
if (!response.ok)
|
|
120
|
+
throw new Error(`Nawishta auto-correct API failed: ${response.status}`);
|
|
121
|
+
const data = await response.json();
|
|
122
|
+
return Array.isArray(data)
|
|
123
|
+
? data
|
|
124
|
+
.filter(isNawishtaEntry)
|
|
125
|
+
.map(({ incorrectText, correctText, completeWord }) => ({ from: incorrectText, to: correctText, wholeWord: completeWord }))
|
|
126
|
+
: [];
|
|
127
|
+
}));
|
|
128
|
+
return cached;
|
|
129
|
+
};
|
|
130
|
+
return {
|
|
131
|
+
id: 'nawishta',
|
|
132
|
+
readOnly: true,
|
|
133
|
+
async load(language) {
|
|
134
|
+
return language === 'ur' ? load() : [];
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/** Every correction for one language, merged across stores (the first listed wins a clash). Failing stores are skipped. */
|
|
139
|
+
export async function loadAutoCorrectEntries(stores, language) {
|
|
140
|
+
const seen = new Set();
|
|
141
|
+
const merged = [];
|
|
98
142
|
const results = await Promise.allSettled(stores.map((store) => store.load(language)));
|
|
99
143
|
results.forEach((result) => {
|
|
100
144
|
if (result.status !== 'fulfilled')
|
|
101
145
|
return;
|
|
102
|
-
for (const entry of result.value)
|
|
103
|
-
if (
|
|
104
|
-
|
|
146
|
+
for (const entry of result.value) {
|
|
147
|
+
if (seen.has(entry.from))
|
|
148
|
+
continue;
|
|
149
|
+
seen.add(entry.from);
|
|
150
|
+
merged.push(entry);
|
|
151
|
+
}
|
|
105
152
|
});
|
|
153
|
+
return merged;
|
|
154
|
+
}
|
|
155
|
+
/** The whole-word corrections for one language, merged across stores, as a from-to table. */
|
|
156
|
+
export async function loadAutoCorrections(stores, language) {
|
|
157
|
+
const entries = await loadAutoCorrectEntries(stores, language);
|
|
158
|
+
const table = new Map();
|
|
159
|
+
for (const entry of entries)
|
|
160
|
+
if (entry.wholeWord !== false)
|
|
161
|
+
table.set(entry.from, entry.to);
|
|
106
162
|
return table;
|
|
107
163
|
}
|
|
108
164
|
/** Saves a correction to the first store that accepts writes. Returns false if none does. */
|
|
@@ -9,6 +9,14 @@ export interface PunctuationRule {
|
|
|
9
9
|
correct: string;
|
|
10
10
|
/** When true, the match must be a whole word (not part of a longer one). */
|
|
11
11
|
completeWord: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* When set, chooses the replacement from the text immediately before the
|
|
14
|
+
* match instead of using the fixed `correct` form. Used for the straight
|
|
15
|
+
* double quote, which opens or closes depending on what comes before it —
|
|
16
|
+
* macOS's native text substitution already does this, so without it the
|
|
17
|
+
* same editor behaves differently depending on OS.
|
|
18
|
+
*/
|
|
19
|
+
resolve?: (before: string) => string;
|
|
12
20
|
}
|
|
13
21
|
export declare const URDU_PUNCTUATION_RULES: PunctuationRule[];
|
|
14
22
|
export interface PunctuationOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"punctuationRules.d.ts","sourceRoot":"","sources":["../../src/autocorrect/punctuationRules.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,YAAY,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"punctuationRules.d.ts","sourceRoot":"","sources":["../../src/autocorrect/punctuationRules.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC;AAED,eAAO,MAAM,sBAAsB,EAAE,eAAe,EAmCnD,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,kDAAkD;IAClD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yFAAyF;IACzF,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kHAAkH;IAClH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAcD,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,kBAAuB,GAAG,eAAe,EAAE,CAO1F;AAOD,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD"}
|
|
@@ -34,13 +34,24 @@ export const URDU_PUNCTUATION_RULES = [
|
|
|
34
34
|
{ incorrect: " :", correct: ":", completeWord: false },
|
|
35
35
|
{ incorrect: "” ", correct: "”", completeWord: false },
|
|
36
36
|
];
|
|
37
|
+
/**
|
|
38
|
+
* A double quote opens (“) when it starts a quotation — at the start of the
|
|
39
|
+
* text, or after whitespace, an opening bracket, a dash, or another opening
|
|
40
|
+
* quote — and otherwise closes (”), the same heuristic macOS's native
|
|
41
|
+
* substitution uses.
|
|
42
|
+
*/
|
|
43
|
+
const OPENING_QUOTE_CONTEXT = /[\s([{—–-“‘]$/u;
|
|
44
|
+
function resolveDoubleQuote(before) {
|
|
45
|
+
return before === '' || OPENING_QUOTE_CONTEXT.test(before) ? '“' : '”';
|
|
46
|
+
}
|
|
37
47
|
/** The rules in use for the options, longest match first, so `۔"` wins over `"`. */
|
|
38
48
|
export function activePunctuationRules(options = {}) {
|
|
39
49
|
if (options.enabled === false)
|
|
40
50
|
return [];
|
|
41
51
|
const rules = URDU_PUNCTUATION_RULES.filter((rule) => rule.incorrect !== rule.correct);
|
|
42
|
-
if (options.straightDoubleQuote !== false)
|
|
43
|
-
rules.push({ incorrect: '"', correct: '”', completeWord: false });
|
|
52
|
+
if (options.straightDoubleQuote !== false) {
|
|
53
|
+
rules.push({ incorrect: '"', correct: '”', completeWord: false, resolve: resolveDoubleQuote });
|
|
54
|
+
}
|
|
44
55
|
return rules.sort((a, b) => b.incorrect.length - a.incorrect.length);
|
|
45
56
|
}
|
|
46
57
|
/** Space after Urdu punctuation, when the next character is not punctuation, a digit or a space. */
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tidies the whole document in place: Unicode NFC normalisation (Arabic-script
|
|
3
3
|
* text can store the same visible letters in different code points), collapsed
|
|
4
|
-
* repeated spaces,
|
|
5
|
-
*
|
|
4
|
+
* repeated spaces, empty text nodes removed, and runs of two or more blank
|
|
5
|
+
* paragraphs collapsed to one. Formatting is kept, since each text node is only
|
|
6
|
+
* changed, never replaced. Returns how many text nodes and blank lines changed.
|
|
6
7
|
*/
|
|
7
8
|
export declare function $cleanUpText(): number;
|
|
8
9
|
//# sourceMappingURL=textCleanupActions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textCleanupActions.d.ts","sourceRoot":"","sources":["../../src/cleanup/textCleanupActions.ts"],"names":[],"mappings":"AAKA
|
|
1
|
+
{"version":3,"file":"textCleanupActions.d.ts","sourceRoot":"","sources":["../../src/cleanup/textCleanupActions.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAOrC"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { $getRoot } from 'lexical';
|
|
1
|
+
import { $getRoot, $isParagraphNode } from 'lexical';
|
|
2
2
|
/** Runs of two or more spaces or tabs, collapsed to one space. */
|
|
3
3
|
const REPEATED_SPACE = /[ \t]{2,}/g;
|
|
4
4
|
/**
|
|
5
5
|
* Tidies the whole document in place: Unicode NFC normalisation (Arabic-script
|
|
6
6
|
* text can store the same visible letters in different code points), collapsed
|
|
7
|
-
* repeated spaces,
|
|
8
|
-
*
|
|
7
|
+
* repeated spaces, empty text nodes removed, and runs of two or more blank
|
|
8
|
+
* paragraphs collapsed to one. Formatting is kept, since each text node is only
|
|
9
|
+
* changed, never replaced. Returns how many text nodes and blank lines changed.
|
|
9
10
|
*/
|
|
10
11
|
export function $cleanUpText() {
|
|
11
12
|
let changed = 0;
|
|
@@ -13,8 +14,25 @@ export function $cleanUpText() {
|
|
|
13
14
|
if (cleanNode(node))
|
|
14
15
|
changed += 1;
|
|
15
16
|
}
|
|
17
|
+
changed += $collapseBlankParagraphs();
|
|
16
18
|
return changed;
|
|
17
19
|
}
|
|
20
|
+
/** Removes every blank paragraph that directly follows another blank one, keeping the first. */
|
|
21
|
+
function $collapseBlankParagraphs() {
|
|
22
|
+
let removed = 0;
|
|
23
|
+
let previousWasBlank = false;
|
|
24
|
+
for (const child of $getRoot().getChildren()) {
|
|
25
|
+
const isBlank = $isParagraphNode(child) && child.getTextContent() === '';
|
|
26
|
+
if (isBlank && previousWasBlank) {
|
|
27
|
+
child.remove();
|
|
28
|
+
removed += 1;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
previousWasBlank = isBlank;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return removed;
|
|
35
|
+
}
|
|
18
36
|
function cleanNode(node) {
|
|
19
37
|
const text = node.getTextContent();
|
|
20
38
|
const cleaned = text.normalize('NFC').replace(REPEATED_SPACE, ' ');
|
|
@@ -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;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,+
|
|
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,+BA0EA"}
|
|
@@ -17,9 +17,10 @@ export function AutoCorrectPanel({ strings, dir, stores, initialFrom = '', initi
|
|
|
17
17
|
const [language, setLanguage] = useState(initialLanguage);
|
|
18
18
|
const [from, setFrom] = useState(initialFrom);
|
|
19
19
|
const [to, setTo] = useState('');
|
|
20
|
+
const [wholeWord, setWholeWord] = useState(true);
|
|
20
21
|
const [status, setStatus] = useState('idle');
|
|
21
22
|
const save = async () => {
|
|
22
|
-
const entry = { from: from.trim(), to: to.trim() };
|
|
23
|
+
const entry = { from: from.trim(), to: to.trim(), wholeWord };
|
|
23
24
|
if (entry.from === '' || entry.to === '' || entry.from === entry.to)
|
|
24
25
|
return;
|
|
25
26
|
try {
|
|
@@ -40,5 +41,5 @@ export function AutoCorrectPanel({ strings, dir, stores, initialFrom = '', initi
|
|
|
40
41
|
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
42
|
setLanguage(e.target.value);
|
|
42
43
|
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
|
+
}, 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("label", { className: "likhari-autocorrect-field likhari-autocorrect-checkbox", children: [_jsx("input", { type: "checkbox", checked: wholeWord, onChange: (e) => setWholeWord(e.target.checked) }), t.wholeWord] }), _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
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AA2CA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnF,OAAO,EAA2B,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAmDtF,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment, forwardRef, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { Menu, Select, Toolbar as MantineToolbar } from '@mantine/core';
|
|
3
|
+
import { Menu, Popover, Select, Toolbar as MantineToolbar } from '@mantine/core';
|
|
4
4
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
5
5
|
import { $getSelection, $isRangeSelection, $isElementNode, $setSelection, $getRoot, $selectAll, $getNearestNodeFromDOMNode, $createTextNode, KEY_MODIFIER_COMMAND, COMMAND_PRIORITY_NORMAL, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, INDENT_CONTENT_COMMAND, OUTDENT_CONTENT_COMMAND, UNDO_COMMAND, REDO_COMMAND, SELECTION_CHANGE_COMMAND, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, COMMAND_PRIORITY_LOW, } from 'lexical';
|
|
6
6
|
import { $getSelectionStyleValueForProperty, $patchStyleText, $setBlocksType } from '@lexical/selection';
|
|
@@ -31,12 +31,14 @@ import { $canMergeSelectedCells, $canUnmergeSelectedCell, $deleteTable, $deleteT
|
|
|
31
31
|
import { $createLinkNode, $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
|
|
32
32
|
import { LinkDialog } from './LinkDialog.js';
|
|
33
33
|
import { DraftsDialog } from './DraftsDialog.js';
|
|
34
|
+
import { ToolbarSettingsPanel } from './ToolbarSettingsPanel.js';
|
|
35
|
+
import { useToolbarItemVisibility } from '../toolbar/toolbarVisibility.js';
|
|
34
36
|
import { normalizeLinkUrl } from '../utils/linkUrl.js';
|
|
35
37
|
import { CANVAS_FONT_DEFAULTS, DEFAULT_FONT_OPTIONS, FONT_SIZES_PX, ZOOM_LEVELS_PERCENT } from '../fonts/index.js';
|
|
36
38
|
import { setStyleProperty } from '../utils/style.js';
|
|
37
39
|
import { useStrings } from '../i18n/useStrings.js';
|
|
38
40
|
import { usePortalTarget } from '../PortalTargetContext.js';
|
|
39
|
-
import { IconAbc, IconAlignCenter, IconAlignJustified, IconAlignLeft, IconAlignRight, IconArrowBackUp, IconArrowForwardUp, IconArrowsJoin, IconBold, IconClearFormatting, IconDeviceFloppy, IconBook, IconChevronDown, IconChevronUp, IconDots, IconHelpCircle, IconHistory, IconExternalLink, IconFeather, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconIndentDecrease, IconIndentIncrease, IconItalic, IconLetterCase, IconLetterCaseLower, IconLetterCaseUpper, IconLink, IconLinkOff, IconList, IconListCheck, IconListNumbers, IconPageBreak, IconPencil, IconPhoto, IconPilcrow, IconQuote, IconSeparatorHorizontal, IconSparkles, IconStrikethrough, IconSubscript, IconSuperscript, IconArrowMergeBoth, IconArrowsSplit2, IconColumnInsertLeft, IconColumnInsertRight, IconColumnRemove, IconColumns, IconClipboard, IconCopy, IconCut, IconSearch, IconSelectAll, IconColumns1, IconColumns2, IconNumber1Small, IconRowInsertBottom, IconRowInsertTop, IconRowRemove, IconArrowsShuffle, IconTable, IconTableMinus, IconTableOptions, IconMinus, IconPlus, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
|
|
41
|
+
import { IconAbc, IconAlignCenter, IconAlignJustified, IconAlignLeft, IconAlignRight, IconArrowBackUp, IconArrowForwardUp, IconArrowsJoin, IconBold, IconClearFormatting, IconDeviceFloppy, IconBook, IconChevronDown, IconChevronUp, IconDots, IconHelpCircle, IconHistory, IconExternalLink, IconFeather, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconIndentDecrease, IconIndentIncrease, IconItalic, IconLetterCase, IconLetterCaseLower, IconLetterCaseUpper, IconLink, IconLinkOff, IconList, IconListCheck, IconListNumbers, IconPageBreak, IconPencil, IconPhoto, IconPilcrow, IconQuote, IconSeparatorHorizontal, IconSettings, IconSparkles, IconStrikethrough, IconSubscript, IconSuperscript, IconArrowMergeBoth, IconArrowsSplit2, IconColumnInsertLeft, IconColumnInsertRight, IconColumnRemove, IconColumns, IconClipboard, IconCopy, IconCut, IconSearch, IconSelectAll, IconColumns1, IconColumns2, IconNumber1Small, IconRowInsertBottom, IconRowInsertTop, IconRowRemove, IconArrowsShuffle, IconTable, IconTableMinus, IconTableOptions, IconMinus, IconPlus, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
|
|
40
42
|
import { IconCoupletCenterNarrow, IconCoupletCenterWide, IconCoupletDelete, IconCoupletGutterNarrow, IconCoupletGutterWide, IconCoupletSpacingLoose, IconCoupletSpacingTight, IconCoupletStaggerNarrow, IconCoupletStaggerWide, IconPoetryDelete, } from '../icons/poetryIcons.js';
|
|
41
43
|
/** Sentinel for "no inline style": Lexical returns the default it is given when
|
|
42
44
|
* the selection has none, so this tells "unstyled" (show the canvas default)
|
|
@@ -277,6 +279,8 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
277
279
|
const strings = useStrings(locale);
|
|
278
280
|
const portalTarget = usePortalTarget();
|
|
279
281
|
const [draftsOpen, setDraftsOpen] = useState(false);
|
|
282
|
+
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
283
|
+
const { isHidden, toggle: toggleHidden } = useToolbarItemVisibility();
|
|
280
284
|
const rtl = direction === 'rtl';
|
|
281
285
|
const ALIGN_ICONS = rtl ? ALIGN_ICONS_RTL : ALIGN_ICONS_LTR;
|
|
282
286
|
// Responsive "priority+" overflow (UI spec §3.3): the toolbar's outer
|
|
@@ -289,6 +293,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
289
293
|
// join lines) is lower priority still, so it is first to move.
|
|
290
294
|
const toolbarContainerRef = useRef(null);
|
|
291
295
|
const toolbarMeasureRef = useRef(null);
|
|
296
|
+
const toolbarOverflowMeasureRef = useRef(null);
|
|
292
297
|
const [overflowGroupKeys, setOverflowGroupKeys] = useState(EMPTY_OVERFLOW);
|
|
293
298
|
const updateToolbar = useCallback(() => {
|
|
294
299
|
editor.getEditorState().read(() => {
|
|
@@ -845,9 +850,9 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
845
850
|
(config.poetry.enabled && locale !== 'en') ||
|
|
846
851
|
(config.tables && state.inTable) ||
|
|
847
852
|
(config.poetry.enabled && state.inPoetry);
|
|
848
|
-
const
|
|
853
|
+
const allMoreItems = [];
|
|
849
854
|
if (fmt.superscript) {
|
|
850
|
-
|
|
855
|
+
allMoreItems.push({
|
|
851
856
|
key: 'superscript',
|
|
852
857
|
icon: IconSuperscript,
|
|
853
858
|
label: strings.toolbar.superscript,
|
|
@@ -856,7 +861,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
856
861
|
});
|
|
857
862
|
}
|
|
858
863
|
if (fmt.subscript) {
|
|
859
|
-
|
|
864
|
+
allMoreItems.push({
|
|
860
865
|
key: 'subscript',
|
|
861
866
|
icon: IconSubscript,
|
|
862
867
|
label: strings.toolbar.subscript,
|
|
@@ -865,14 +870,16 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
865
870
|
});
|
|
866
871
|
}
|
|
867
872
|
if (fmt.caseTransforms) {
|
|
868
|
-
|
|
873
|
+
allMoreItems.push({ key: 'upper', icon: IconLetterCaseUpper, label: strings.toolbar.uppercase, onClick: () => applyCaseTransform('upper') }, { key: 'lower', icon: IconLetterCaseLower, label: strings.toolbar.lowercase, onClick: () => applyCaseTransform('lower') }, { key: 'capitalize', icon: IconLetterCase, label: strings.toolbar.capitalize, onClick: () => applyCaseTransform('capitalize') });
|
|
869
874
|
}
|
|
870
875
|
if (fmt.clearFormatting) {
|
|
871
|
-
|
|
876
|
+
allMoreItems.push({ key: 'clear', icon: IconClearFormatting, label: strings.toolbar.clearFormatting, onClick: clearFormatting });
|
|
872
877
|
}
|
|
878
|
+
// The user can hide any of these individually from the toolbar settings panel.
|
|
879
|
+
const moreItems = allMoreItems.filter((item) => !isHidden(item.key));
|
|
873
880
|
// UI spec §5: indent/outdent arrows are direction-relative and swap in RTL
|
|
874
881
|
// (outdent moves content toward the start edge, which is the right in RTL).
|
|
875
|
-
const
|
|
882
|
+
const allIndentItems = config.indent
|
|
876
883
|
? [
|
|
877
884
|
{
|
|
878
885
|
key: 'outdent',
|
|
@@ -888,6 +895,7 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
888
895
|
},
|
|
889
896
|
]
|
|
890
897
|
: [];
|
|
898
|
+
const indentItems = allIndentItems.filter((item) => !isHidden(item.key));
|
|
891
899
|
// Grouped for the dropdown when options declare groups (Latin / Urdu).
|
|
892
900
|
const fontData = (() => {
|
|
893
901
|
const data = [];
|
|
@@ -933,22 +941,31 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
933
941
|
];
|
|
934
942
|
const formattingValue = state.listType ?? state.blockType;
|
|
935
943
|
const AlignIcon = ALIGN_ICONS[state.elementFormat] ?? IconAlignLeft;
|
|
936
|
-
const
|
|
937
|
-
const
|
|
938
|
-
const
|
|
944
|
+
const showParagraphStyle = showFormattingGroup && !isHidden('paragraphStyle');
|
|
945
|
+
const showBold = fmt.bold && !isHidden('bold');
|
|
946
|
+
const showItalic = fmt.italic && !isHidden('italic');
|
|
947
|
+
const showUnderline = fmt.underline && !isHidden('underline');
|
|
948
|
+
const showStrikethrough = fmt.strikethrough && !isHidden('strikethrough');
|
|
949
|
+
const formatSection = (showParagraphStyle || showBold || showItalic || showUnderline || showStrikethrough || moreItems.length > 0) && (_jsxs(Fragment, { children: [showParagraphStyle && (_jsx(MantineToolbar.Group, { children: _jsx(ToolbarSelect, { icon: IconPilcrow, label: strings.toolbar.formattingLabel, width: 148, value: formattingValue, data: formattingOptions, comingSoon: strings.toolbar.comingSoon, renderOption: iconOptionRenderer(FORMATTING_ICONS, IconPilcrow), onMouseDown: snapshotSelection, onChange: withRefocus((v) => applyFormatting(v)) }) })), (showBold || showItalic || showUnderline || showStrikethrough || moreItems.length > 0) && (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [showBold && _jsx(ToolbarButton, { icon: IconBold, title: strings.toolbar.bold, active: state.activeFormats.has('bold'), onClick: () => formatText('bold') }), showItalic && (_jsx(ToolbarButton, { icon: IconItalic, title: strings.toolbar.italic, active: state.activeFormats.has('italic'), onClick: () => formatText('italic') })), showUnderline && (_jsx(ToolbarButton, { icon: IconUnderline, title: strings.toolbar.underline, active: state.activeFormats.has('underline'), onClick: () => formatText('underline') })), showStrikethrough && (_jsx(ToolbarButton, { icon: IconStrikethrough, title: strings.toolbar.strikethrough, active: state.activeFormats.has('strikethrough'), onClick: () => formatText('strikethrough') })), moreItems.length > 0 && (_jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 210, closeOnItemClick: true, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx(ToolbarButton, { icon: IconDots, title: strings.toolbar.moreFormatting }) }), _jsx(Menu.Dropdown, { children: moreItems.map((item) => (_jsx(MoreMenuItem, { icon: item.icon, label: item.label, active: item.active, onClick: runMenuItem(item.onClick) }, item.key))) })] }))] }))] }, "format"));
|
|
950
|
+
const showAlignSelect = showAlignGroup && !isHidden('alignment');
|
|
951
|
+
const alignSection = (showAlignSelect || indentItems.length > 0) && (_jsxs(Fragment, { children: [showAlignSelect && (_jsx(MantineToolbar.Group, { children: _jsx(ToolbarSelect, { icon: AlignIcon, label: strings.toolbar.alignment, width: 138, value: state.elementFormat || 'start', data: alignOptions, renderOption: iconOptionRenderer(ALIGN_ICONS, IconAlignLeft), onMouseDown: snapshotSelection, onChange: withRefocus((v) => formatElement(v)) }) })), indentItems.length > 0 && (_jsx(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: indentItems.map((item) => (_jsx(ToolbarButton, { icon: item.icon, title: item.label, onClick: item.onClick }, item.key))) }))] }, "align"));
|
|
952
|
+
const showFontFamily = config.font.family && !isHidden('fontFamily');
|
|
953
|
+
const showFontSize = config.font.size && !uniform && !isHidden('fontSize');
|
|
954
|
+
const fontSection = (showFontFamily || showFontSize) && (_jsxs(MantineToolbar.Group, { children: [showFontFamily && (_jsx(ToolbarSelect, { icon: IconTypography, label: strings.toolbar.fontFamily, width: 150, value: fontOptions.some((f) => f.family === shownFontFamily) ? shownFontFamily : null, placeholder: strings.toolbar.fontFamilyPlaceholder, data: fontData, searchable: true, noMatchMessage: strings.toolbar.noMatch, renderOption: ({ option }) => _jsx("span", { style: { fontFamily: option.value }, children: option.label }), onMouseDown: snapshotSelection, onChange: uniform
|
|
939
955
|
? // A view setting: leave the editor state and selection alone, just hand the caret back.
|
|
940
956
|
(v) => {
|
|
941
957
|
onUniformFontFamilyChange?.(v);
|
|
942
958
|
editor.focus();
|
|
943
959
|
}
|
|
944
|
-
: withRefocus((v) => applyFont('font-family', v)) })),
|
|
960
|
+
: withRefocus((v) => applyFont('font-family', v)) })), showFontSize && (_jsx(ToolbarSelect, { icon: IconTextSize, label: strings.toolbar.fontSize, width: 84, value: FONT_SIZES_PX.some((px) => `${px}px` === shownFontSize) ? shownFontSize : null, placeholder: strings.toolbar.fontSizePlaceholder, data: FONT_SIZES_PX.map((px) => ({ value: `${px}px`, label: String(px) })), onMouseDown: snapshotSelection, onChange: withRefocus((v) => applyFont('font-size', v)) }))] }, "font"));
|
|
945
961
|
/** The insert commands. `contextual` also puts the link, table and poetry option menus among them (the classic
|
|
946
962
|
* toolbar); the ribbon shows those on their own tabs instead. */
|
|
947
963
|
const insertButtons = (contextual) => (_jsxs(_Fragment, { children: [config.links &&
|
|
964
|
+
!isHidden('link') &&
|
|
948
965
|
(contextual && state.isLink ? (_jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 240, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.linkOptions, active: true, "aria-haspopup": "menu" }) }), _jsx(Menu.Dropdown, { children: _jsx(LinkMenuItems, { url: state.linkUrl, onEdit: () => {
|
|
949
966
|
restoreSelection();
|
|
950
967
|
openLinkDialog();
|
|
951
|
-
}, onRemove: removeLink, strings: strings }) })] })) : (_jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.insertLink, onClick: openLinkDialog }))), (config.images.linked || config.images.embedded) && (_jsx(ToolbarButton, { icon: IconPhoto, title: strings.toolbar.insertImage, onClick: openImageDialog })), config.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.tables && _jsx(ToolbarButton, { icon: IconTable, title: strings.toolbar.insertTable, onClick: openTableDialog }), contextual && config.tables && state.inTable && (_jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 240, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx(ToolbarButton, { icon: IconTableOptions, title: strings.toolbar.tableOptions, active: true, "aria-haspopup": "menu" }) }), _jsx(Menu.Dropdown, { children: _jsx(TableMenuItems, { strings: strings, direction: direction, rows: state.tableRows, columns: state.tableColumns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction }) })] })), 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.pageBreak && (_jsx(ToolbarButton, { icon: IconPageBreak, title: strings.toolbar.insertPageBreak, onClick: () => editor.dispatchCommand(INSERT_PAGE_BREAK_COMMAND, undefined) })), config.poetry.enabled && locale !== 'en' && (_jsx(ToolbarButton, { icon: IconFeather, title: strings.toolbar.insertPoetryCouplet, onClick: () => editor.dispatchCommand(INSERT_POETRY_COUPLET_COMMAND, { layout: config.poetry.defaultLayout }) })), contextual && config.poetry.enabled && state.inPoetry && (_jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 200, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx(ToolbarButton, { icon: IconFeather, title: strings.toolbar.poetryOptions, active: true, "aria-haspopup": "menu" }) }), _jsx(Menu.Dropdown, { children: _jsx(PoetryMenuItems, { strings: strings, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction }) })] }))] }));
|
|
968
|
+
}, onRemove: removeLink, strings: strings }) })] })) : (_jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.insertLink, onClick: openLinkDialog }))), (config.images.linked || config.images.embedded) && !isHidden('image') && (_jsx(ToolbarButton, { icon: IconPhoto, title: strings.toolbar.insertImage, onClick: openImageDialog })), config.blocks.horizontalRule && !isHidden('horizontalRule') && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.tables && !isHidden('table') && _jsx(ToolbarButton, { icon: IconTable, title: strings.toolbar.insertTable, onClick: openTableDialog }), contextual && config.tables && state.inTable && (_jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 240, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx(ToolbarButton, { icon: IconTableOptions, title: strings.toolbar.tableOptions, active: true, "aria-haspopup": "menu" }) }), _jsx(Menu.Dropdown, { children: _jsx(TableMenuItems, { strings: strings, direction: direction, rows: state.tableRows, columns: state.tableColumns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction }) })] })), config.columns && !isHidden('columns') && _jsx(ToolbarButton, { icon: IconColumns, title: strings.toolbar.insertColumns, onClick: openLayoutDialog }), config.footnotes && !isHidden('footnote') && (_jsx(ToolbarButton, { icon: IconNumber1Small, title: strings.toolbar.insertFootnote, onClick: () => editor.dispatchCommand(INSERT_FOOTNOTE_COMMAND, undefined) })), config.blocks.pageBreak && !isHidden('pageBreak') && (_jsx(ToolbarButton, { icon: IconPageBreak, title: strings.toolbar.insertPageBreak, onClick: () => editor.dispatchCommand(INSERT_PAGE_BREAK_COMMAND, undefined) })), config.poetry.enabled && locale !== 'en' && !isHidden('poetry') && (_jsx(ToolbarButton, { icon: IconFeather, title: strings.toolbar.insertPoetryCouplet, onClick: () => editor.dispatchCommand(INSERT_POETRY_COUPLET_COMMAND, { layout: config.poetry.defaultLayout }) })), contextual && config.poetry.enabled && state.inPoetry && (_jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 200, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx(ToolbarButton, { icon: IconFeather, title: strings.toolbar.poetryOptions, active: true, "aria-haspopup": "menu" }) }), _jsx(Menu.Dropdown, { children: _jsx(PoetryMenuItems, { strings: strings, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction }) })] }))] }));
|
|
952
969
|
const insertSection = showInsertGroup && (_jsx(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: insertButtons(true) }, "insert"));
|
|
953
970
|
const joinLines = () => {
|
|
954
971
|
editor.update(() => {
|
|
@@ -1031,23 +1048,79 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1031
1048
|
});
|
|
1032
1049
|
// The tools group is always built, even when every command in it is off, so the ribbon asks first.
|
|
1033
1050
|
const hasToolsGroup = config.language.autocorrect || config.language.textCleanup || config.language.spellCheck || config.joinLines;
|
|
1034
|
-
const toolsSection = (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [config.language.autocorrect && (_jsx(ToolbarButton, { icon: IconWand, title: strings.toolbar.autocorrect, active: autoCorrectOpen, onClick: onToggleAutoCorrect })), config.language.textCleanup && (_jsx(ToolbarButton, { icon: IconSparkles, title: strings.autoCorrect.correctDocument, onClick: () => editor.dispatchCommand(CORRECT_DOCUMENT_COMMAND, undefined) })), config.language.spellCheck && (_jsx(ToolbarButton, { icon: IconAbc, title: strings.toolbar.spellChecker, active: spellOpen, onClick: onToggleSpell })), config.joinLines && state.canJoinLines && (_jsx(ToolbarButton, { icon: IconArrowsJoin, title: strings.toolbar.joinLines, onClick: joinLines }))] }, "tools"));
|
|
1051
|
+
const toolsSection = (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [config.language.autocorrect && !isHidden('autocorrect') && (_jsx(ToolbarButton, { icon: IconWand, title: strings.toolbar.autocorrect, active: autoCorrectOpen, onClick: onToggleAutoCorrect })), config.language.textCleanup && !isHidden('textCleanup') && (_jsx(ToolbarButton, { icon: IconSparkles, title: strings.autoCorrect.correctDocument, onClick: () => editor.dispatchCommand(CORRECT_DOCUMENT_COMMAND, undefined) })), config.language.spellCheck && !isHidden('spellCheck') && (_jsx(ToolbarButton, { icon: IconAbc, title: strings.toolbar.spellChecker, active: spellOpen, onClick: onToggleSpell })), config.joinLines && state.canJoinLines && !isHidden('joinLines') && (_jsx(ToolbarButton, { icon: IconArrowsJoin, title: strings.toolbar.joinLines, onClick: joinLines }))] }, "tools"));
|
|
1035
1052
|
// Uniform mode's zoom: [-] 100% [+], stepping through the preset levels; the
|
|
1036
1053
|
// percentage resets to 100%. Always laid out left-to-right, like a number.
|
|
1037
|
-
const showZoom = uniform && config.font.size;
|
|
1054
|
+
const showZoom = uniform && config.font.size && !isHidden('zoom');
|
|
1038
1055
|
const zoomOutTo = [...ZOOM_LEVELS_PERCENT].reverse().find((level) => level < zoom);
|
|
1039
1056
|
const zoomInTo = ZOOM_LEVELS_PERCENT.find((level) => level > zoom);
|
|
1040
|
-
const hasEndUtilities = Boolean(drafts || config.findReplace || helpUrl !== false);
|
|
1041
1057
|
const zoomGroup = showZoom && (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", role: "group", "aria-label": strings.toolbar.zoom, dir: "ltr", children: [_jsx(ToolbarButton, { icon: IconMinus, title: strings.toolbar.zoomOut, disabled: zoomOutTo === undefined, onClick: () => zoomOutTo !== undefined && onZoomChange?.(zoomOutTo) }), _jsxs(MantineToolbar.Toggle, { title: strings.toolbar.zoomReset, "aria-label": `${strings.toolbar.zoomReset} (${zoom}%)`, onMouseDown: (e) => e.preventDefault(), onClick: () => onZoomChange?.(100), style: { width: 'auto', minWidth: 52, padding: '0 6px', fontSize: 12 }, children: [zoom, "%"] }), _jsx(ToolbarButton, { icon: IconPlus, title: strings.toolbar.zoomIn, disabled: zoomInTo === undefined, onClick: () => zoomInTo !== undefined && onZoomChange?.(zoomInTo) })] }, "zoom"));
|
|
1042
|
-
const draftsButton = drafts && _jsx(ToolbarButton, { icon: IconHistory, title: strings.toolbar.drafts, onClick: () => setDraftsOpen(true) });
|
|
1043
|
-
const findButton = config.findReplace && (_jsx(ToolbarButton, { icon: IconSearch, title: strings.findReplace.toggle, active: findOpen, onClick: onToggleFind }));
|
|
1044
|
-
const helpButton = helpUrl !== false && (_jsx(MantineToolbar.Toggle, { component: "a", href: helpUrl ?? DEFAULT_HELP_URL, target: "_blank", rel: "noopener noreferrer", "aria-label": strings.toolbar.help, title: strings.toolbar.help, children: _jsx(IconHelpCircle, { size: ICON_SIZE, stroke: ICON_STROKE }) }));
|
|
1045
|
-
//
|
|
1046
|
-
|
|
1047
|
-
|
|
1058
|
+
const draftsButton = drafts && !isHidden('drafts') && _jsx(ToolbarButton, { icon: IconHistory, title: strings.toolbar.drafts, onClick: () => setDraftsOpen(true) });
|
|
1059
|
+
const findButton = config.findReplace && !isHidden('find') && (_jsx(ToolbarButton, { icon: IconSearch, title: strings.findReplace.toggle, active: findOpen, onClick: onToggleFind }));
|
|
1060
|
+
const helpButton = helpUrl !== false && !isHidden('help') && (_jsx(MantineToolbar.Toggle, { component: "a", href: helpUrl ?? DEFAULT_HELP_URL, target: "_blank", rel: "noopener noreferrer", "aria-label": strings.toolbar.help, title: strings.toolbar.help, children: _jsx(IconHelpCircle, { size: ICON_SIZE, stroke: ICON_STROKE }) }));
|
|
1061
|
+
// Every item the settings panel can show/hide, grouped the way it appears in the
|
|
1062
|
+
// toolbar. Built from what the host's EditorFeatureConfig makes available — a
|
|
1063
|
+
// feature the host turned off is never offered here, since this panel only lets
|
|
1064
|
+
// the user declutter what the host already enabled.
|
|
1065
|
+
const settingsGroup = (id, label, items) => {
|
|
1066
|
+
const present = items.filter((item) => Boolean(item));
|
|
1067
|
+
return present.length > 0 ? { id, label, items: present } : null;
|
|
1068
|
+
};
|
|
1069
|
+
const t = strings.toolbar;
|
|
1070
|
+
const settingsGroups = [
|
|
1071
|
+
settingsGroup('formatting', strings.toolbarSettings.groups.formatting, [
|
|
1072
|
+
showFormattingGroup && { id: 'paragraphStyle', label: t.formattingLabel },
|
|
1073
|
+
fmt.bold && { id: 'bold', label: t.bold },
|
|
1074
|
+
fmt.italic && { id: 'italic', label: t.italic },
|
|
1075
|
+
fmt.underline && { id: 'underline', label: t.underline },
|
|
1076
|
+
fmt.strikethrough && { id: 'strikethrough', label: t.strikethrough },
|
|
1077
|
+
...allMoreItems.map((item) => ({ id: item.key, label: item.label })),
|
|
1078
|
+
]),
|
|
1079
|
+
settingsGroup('alignment', strings.toolbarSettings.groups.alignment, [
|
|
1080
|
+
showAlignGroup && { id: 'alignment', label: t.alignment },
|
|
1081
|
+
...allIndentItems.map((item) => ({ id: item.key, label: item.label })),
|
|
1082
|
+
]),
|
|
1083
|
+
settingsGroup('font', strings.toolbarSettings.groups.font, [
|
|
1084
|
+
config.font.family && { id: 'fontFamily', label: t.fontFamily },
|
|
1085
|
+
config.font.size && !uniform && { id: 'fontSize', label: t.fontSize },
|
|
1086
|
+
]),
|
|
1087
|
+
settingsGroup('insert', strings.toolbarSettings.groups.insert, [
|
|
1088
|
+
config.links && { id: 'link', label: t.insertLink },
|
|
1089
|
+
(config.images.linked || config.images.embedded) && { id: 'image', label: t.insertImage },
|
|
1090
|
+
config.blocks.horizontalRule && { id: 'horizontalRule', label: t.insertHorizontalRule },
|
|
1091
|
+
config.tables && { id: 'table', label: t.insertTable },
|
|
1092
|
+
config.columns && { id: 'columns', label: t.insertColumns },
|
|
1093
|
+
config.footnotes && { id: 'footnote', label: t.insertFootnote },
|
|
1094
|
+
config.blocks.pageBreak && { id: 'pageBreak', label: t.insertPageBreak },
|
|
1095
|
+
config.poetry.enabled && locale !== 'en' && { id: 'poetry', label: t.insertPoetryCouplet },
|
|
1096
|
+
]),
|
|
1097
|
+
settingsGroup('tools', strings.toolbarSettings.groups.tools, [
|
|
1098
|
+
config.language.autocorrect && { id: 'autocorrect', label: t.autocorrect },
|
|
1099
|
+
config.language.textCleanup && { id: 'textCleanup', label: strings.autoCorrect.correctDocument },
|
|
1100
|
+
config.language.spellCheck && { id: 'spellCheck', label: t.spellChecker },
|
|
1101
|
+
config.joinLines && { id: 'joinLines', label: t.joinLines },
|
|
1102
|
+
]),
|
|
1103
|
+
settingsGroup('zoom', strings.toolbarSettings.groups.zoom, [uniform && config.font.size && { id: 'zoom', label: t.zoom }]),
|
|
1104
|
+
settingsGroup('utilities', strings.toolbarSettings.groups.utilities, [
|
|
1105
|
+
drafts && { id: 'drafts', label: t.drafts },
|
|
1106
|
+
config.findReplace && { id: 'find', label: strings.findReplace.toggle },
|
|
1107
|
+
helpUrl !== false && { id: 'help', label: t.help },
|
|
1108
|
+
]),
|
|
1109
|
+
settingsGroup('history', strings.toolbarSettings.groups.history, [
|
|
1110
|
+
showSave && { id: 'save', label: t.save },
|
|
1111
|
+
config.history && { id: 'undo', label: t.undo },
|
|
1112
|
+
config.history && { id: 'redo', label: t.redo },
|
|
1113
|
+
]),
|
|
1114
|
+
].filter((g) => g !== null);
|
|
1115
|
+
const settingsButton = (_jsxs(Popover, { opened: settingsOpen, onChange: setSettingsOpen, position: "bottom-end", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 280, children: [_jsx(Popover.Target, { children: _jsx(ToolbarButton, { icon: IconSettings, title: strings.toolbar.settings, active: settingsOpen, onClick: () => setSettingsOpen((v) => !v) }) }), _jsx(Popover.Dropdown, { p: 0, children: _jsx(ToolbarSettingsPanel, { strings: strings, dir: direction, groups: settingsGroups, isHidden: isHidden, onToggle: toggleHidden, onClose: () => setSettingsOpen(false) }) })] }));
|
|
1116
|
+
// Drafts, search, help and the settings gear: the far-end group (see `endMovable` below).
|
|
1117
|
+
const utilitiesGroup = (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [draftsButton, findButton, helpButton, settingsButton] }, "end"));
|
|
1118
|
+
const saveGroup = showSave && !isHidden('save') && (_jsx(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: _jsx(ToolbarButton, { icon: IconDeviceFloppy, title: strings.toolbar.save, dirty: Boolean(isDirty),
|
|
1048
1119
|
// Nothing to save until the content has changed since it was loaded or last saved.
|
|
1049
1120
|
disabled: !isDirty, onClick: onSave }) }, "save"));
|
|
1050
|
-
const
|
|
1121
|
+
const showUndo = !isHidden('undo');
|
|
1122
|
+
const showRedo = !isHidden('redo');
|
|
1123
|
+
const historyGroup = config.history && (showUndo || showRedo) && (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [showUndo && (_jsx(ToolbarButton, { icon: IconArrowBackUp, title: strings.toolbar.undo, disabled: !state.canUndo, onClick: () => editor.dispatchCommand(UNDO_COMMAND, undefined) })), showRedo && (_jsx(ToolbarButton, { icon: IconArrowForwardUp, title: strings.toolbar.redo, disabled: !state.canRedo, onClick: () => editor.dispatchCommand(REDO_COMMAND, undefined) }))] }, "history"));
|
|
1051
1124
|
const startSections = [
|
|
1052
1125
|
saveGroup,
|
|
1053
1126
|
historyGroup,
|
|
@@ -1079,10 +1152,9 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1079
1152
|
const measure = toolbarMeasureRef.current;
|
|
1080
1153
|
if (!container || !measure)
|
|
1081
1154
|
return;
|
|
1082
|
-
//
|
|
1083
|
-
//
|
|
1084
|
-
|
|
1085
|
-
const OVERFLOW_BUTTON_WIDTH = 38;
|
|
1155
|
+
// Fallback only, in case the overflow button's own hidden measurement
|
|
1156
|
+
// element (below) isn't mounted yet on the very first pass.
|
|
1157
|
+
const OVERFLOW_BUTTON_FALLBACK_WIDTH = 38;
|
|
1086
1158
|
const recompute = () => {
|
|
1087
1159
|
const available = container.clientWidth;
|
|
1088
1160
|
const total = measure.scrollWidth;
|
|
@@ -1094,6 +1166,10 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1094
1166
|
measure.querySelectorAll('[data-group-key]').forEach((el) => {
|
|
1095
1167
|
widths.set(el.dataset.groupKey, el.getBoundingClientRect().width);
|
|
1096
1168
|
});
|
|
1169
|
+
// Measured from a real (hidden) copy of the "..." button, in the toolbar's own
|
|
1170
|
+
// CSS, rather than guessed — only charged against the budget once something
|
|
1171
|
+
// has actually moved into it, since it isn't rendered at all otherwise.
|
|
1172
|
+
const overflowButtonWidth = toolbarOverflowMeasureRef.current?.scrollWidth ?? OVERFLOW_BUTTON_FALLBACK_WIDTH;
|
|
1097
1173
|
let remaining = total;
|
|
1098
1174
|
const next = new Set();
|
|
1099
1175
|
for (const key of movableGroupKeys.split(',').filter(Boolean)) {
|
|
@@ -1106,13 +1182,15 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1106
1182
|
next.add(key);
|
|
1107
1183
|
}
|
|
1108
1184
|
if (next.size > 0)
|
|
1109
|
-
remaining +=
|
|
1185
|
+
remaining += overflowButtonWidth;
|
|
1110
1186
|
setOverflowGroupKeys((prev) => (setsEqual(prev, next) ? prev : next));
|
|
1111
1187
|
};
|
|
1112
1188
|
recompute();
|
|
1113
1189
|
const ro = new ResizeObserver(recompute);
|
|
1114
1190
|
ro.observe(container);
|
|
1115
1191
|
ro.observe(measure);
|
|
1192
|
+
if (toolbarOverflowMeasureRef.current)
|
|
1193
|
+
ro.observe(toolbarOverflowMeasureRef.current);
|
|
1116
1194
|
return () => ro.disconnect();
|
|
1117
1195
|
});
|
|
1118
1196
|
const isVisible = (section) => !overflowGroupKeys.has(section.key);
|
|
@@ -1255,5 +1333,5 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
1255
1333
|
setRibbonPeek(false);
|
|
1256
1334
|
}, children: _jsx(MantineToolbar, { "aria-label": strings.toolbar.ariaLabel, className: bordered ? 'likhari-toolbar likhari-ribbon-panel' : 'likhari-toolbar likhari-toolbar--plain likhari-ribbon-panel', withBorder: bordered, variant: variant, color: "var(--editor-accent)", children: withDividers(activeTab.groups) }) })), contextMenuEl, dialogsEl] }));
|
|
1257
1335
|
}
|
|
1258
|
-
return (_jsxs(MantineToolbar, { ref: toolbarContainerRef, "aria-label": strings.toolbar.ariaLabel, className: bordered ? 'likhari-toolbar' : 'likhari-toolbar likhari-toolbar--plain', withBorder: bordered, variant: variant, color: "var(--editor-accent)", children: [withDividers(startSections), visibleMovable.map((section) => (_jsxs(Fragment, { children: [_jsx(MantineToolbar.Divider, {}), section.node] }, section.key))), hiddenMovable.length > 0 && (_jsxs(_Fragment, { children: [_jsx(MantineToolbar.Divider, {}), _jsxs(Menu, { opened: overflowMenuOpen, onChange: handleOverflowMenuChange, position: "bottom-end", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: "max-content", closeOnItemClick: false, children: [_jsx(Menu.Target, { children: _jsx(ToolbarButton, { icon: IconDots, title: strings.toolbar.moreFormatting }) }), _jsx(Menu.Dropdown, { p: 6, children: _jsx(MantineToolbar, { withBorder: false, variant: variant, color: "var(--editor-accent)", style: { maxWidth: 320 }, children: withDividers(hiddenMovable.map((section) => section.node)) }) })] })] })), _jsx("span", { "aria-hidden": "true", style: { flex: '1 1 auto' } }), visibleEnd.map((section) => section.node), contextMenuEl, overflowEnabled && (_jsxs(MantineToolbar, { "aria-hidden": "true", ref: toolbarMeasureRef, withBorder: bordered, variant: variant, color: "var(--editor-accent)", style: { position: 'absolute', visibility: 'hidden', pointerEvents: 'none', top: 0, left: 0, flexWrap: 'nowrap', width: 'max-content' }, children: [withDividers(startSections),
|
|
1336
|
+
return (_jsxs(MantineToolbar, { ref: toolbarContainerRef, "aria-label": strings.toolbar.ariaLabel, className: bordered ? 'likhari-toolbar' : 'likhari-toolbar likhari-toolbar--plain', withBorder: bordered, variant: variant, color: "var(--editor-accent)", children: [withDividers(startSections), visibleMovable.map((section) => (_jsxs(Fragment, { children: [_jsx(MantineToolbar.Divider, {}), section.node] }, section.key))), hiddenMovable.length > 0 && (_jsxs(_Fragment, { children: [_jsx(MantineToolbar.Divider, {}), _jsxs(Menu, { opened: overflowMenuOpen, onChange: handleOverflowMenuChange, position: "bottom-end", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: "max-content", closeOnItemClick: false, children: [_jsx(Menu.Target, { children: _jsx(ToolbarButton, { icon: IconDots, title: strings.toolbar.moreFormatting }) }), _jsx(Menu.Dropdown, { p: 6, children: _jsx(MantineToolbar, { withBorder: false, variant: variant, color: "var(--editor-accent)", style: { maxWidth: 320 }, children: withDividers(hiddenMovable.map((section) => section.node)) }) })] })] })), _jsx("span", { "aria-hidden": "true", style: { flex: '1 1 auto' } }), visibleEnd.map((section) => section.node), contextMenuEl, overflowEnabled && (_jsxs(MantineToolbar, { "aria-hidden": "true", ref: toolbarMeasureRef, className: bordered ? 'likhari-toolbar' : 'likhari-toolbar likhari-toolbar--plain', withBorder: bordered, variant: variant, color: "var(--editor-accent)", style: { position: 'absolute', visibility: 'hidden', pointerEvents: 'none', top: 0, left: 0, flexWrap: 'nowrap', width: 'max-content' }, children: [withDividers(startSections), mainMovable.map((section) => (_jsxs(Fragment, { children: [_jsx(MantineToolbar.Divider, {}), _jsx("span", { "data-group-key": section.key, style: { display: 'inline-flex' }, children: section.node })] }, section.key))), endMovable.map((section) => (_jsx("span", { "data-group-key": section.key, style: { display: 'inline-flex' }, children: section.node }, section.key)))] })), overflowEnabled && (_jsxs(MantineToolbar, { "aria-hidden": "true", ref: toolbarOverflowMeasureRef, className: bordered ? 'likhari-toolbar' : 'likhari-toolbar likhari-toolbar--plain', withBorder: bordered, variant: variant, color: "var(--editor-accent)", style: { position: 'absolute', visibility: 'hidden', pointerEvents: 'none', top: 0, left: 0, width: 'max-content' }, children: [_jsx(MantineToolbar.Divider, {}), _jsx(ToolbarButton, { icon: IconDots, title: "Toolbar overflow measurement" })] })), dialogsEl] }));
|
|
1259
1337
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Strings } from '../i18n/strings.js';
|
|
2
|
+
import type { ToolbarVisibilityGroup } from '../toolbar/toolbarVisibility.js';
|
|
3
|
+
/**
|
|
4
|
+
* Lets the user show or hide individual toolbar buttons and dropdowns, grouped
|
|
5
|
+
* the way they appear in the toolbar. The choice is read from and saved to
|
|
6
|
+
* localStorage by the caller (`useToolbarItemVisibility`); this component only
|
|
7
|
+
* renders the checkboxes and reports clicks.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ToolbarSettingsPanel({ strings, dir, groups, isHidden, onToggle, onClose, }: {
|
|
10
|
+
strings: Strings;
|
|
11
|
+
dir: 'ltr' | 'rtl';
|
|
12
|
+
groups: ToolbarVisibilityGroup[];
|
|
13
|
+
isHidden: (id: string) => boolean;
|
|
14
|
+
onToggle: (id: string) => void;
|
|
15
|
+
onClose: () => void;
|
|
16
|
+
}): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=ToolbarSettingsPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolbarSettingsPanel.d.ts","sourceRoot":"","sources":["../../src/components/ToolbarSettingsPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAE3E;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,GAAG,EACH,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,KAAK,GAAG,KAAK,CAAC;IACnB,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACjC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,+BAyBA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { IconX } from '@tabler/icons-react';
|
|
3
|
+
/**
|
|
4
|
+
* Lets the user show or hide individual toolbar buttons and dropdowns, grouped
|
|
5
|
+
* the way they appear in the toolbar. The choice is read from and saved to
|
|
6
|
+
* localStorage by the caller (`useToolbarItemVisibility`); this component only
|
|
7
|
+
* renders the checkboxes and reports clicks.
|
|
8
|
+
*/
|
|
9
|
+
export function ToolbarSettingsPanel({ strings, dir, groups, isHidden, onToggle, onClose, }) {
|
|
10
|
+
const t = strings.toolbarSettings;
|
|
11
|
+
return (_jsxs("div", { className: "likhari-toolbar-settings-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 }) })] }), _jsx("div", { className: "likhari-toolbar-settings-groups", children: groups.map((group) => (_jsxs("fieldset", { className: "likhari-toolbar-settings-group", children: [_jsx("legend", { children: group.label }), group.items.map((item) => (_jsxs("label", { className: "likhari-toolbar-settings-item", children: [_jsx("input", { type: "checkbox", checked: !isHidden(item.id), onChange: () => onToggle(item.id) }), item.label] }, item.id)))] }, group.id))) })] }));
|
|
12
|
+
}
|
package/dist/i18n/strings.d.ts
CHANGED
|
@@ -74,6 +74,8 @@ export interface Strings {
|
|
|
74
74
|
clearFormatting: string;
|
|
75
75
|
outdent: string;
|
|
76
76
|
indent: string;
|
|
77
|
+
/** Opens/closes the toolbar settings panel (show/hide individual toolbar items). */
|
|
78
|
+
settings: string;
|
|
77
79
|
/** The ribbon layout (`toolbarStyle.layout: 'ribbon'`): its tab strip and tabs. */
|
|
78
80
|
ribbon: {
|
|
79
81
|
/** aria-label on the tab strip. */
|
|
@@ -110,6 +112,21 @@ export interface Strings {
|
|
|
110
112
|
right: string;
|
|
111
113
|
};
|
|
112
114
|
};
|
|
115
|
+
/** The toolbar settings panel (the gear button): show/hide individual toolbar buttons and dropdowns. Grouped the way they appear in the toolbar; group labels are below. */
|
|
116
|
+
toolbarSettings: {
|
|
117
|
+
title: string;
|
|
118
|
+
close: string;
|
|
119
|
+
groups: {
|
|
120
|
+
formatting: string;
|
|
121
|
+
alignment: string;
|
|
122
|
+
font: string;
|
|
123
|
+
insert: string;
|
|
124
|
+
tools: string;
|
|
125
|
+
zoom: string;
|
|
126
|
+
utilities: string;
|
|
127
|
+
history: string;
|
|
128
|
+
};
|
|
129
|
+
};
|
|
113
130
|
/** The popup `EditorRef.confirmDiscard()` shows when the user is about to leave with unsaved changes (lexical-editor-spec.md §6.4). */
|
|
114
131
|
leaveDialog: {
|
|
115
132
|
title: string;
|
|
@@ -221,6 +238,7 @@ export interface Strings {
|
|
|
221
238
|
failed: string;
|
|
222
239
|
close: string;
|
|
223
240
|
correctDocument: string;
|
|
241
|
+
wholeWord: string;
|
|
224
242
|
};
|
|
225
243
|
contextMenu: {
|
|
226
244
|
cut: 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
|
@@ -62,6 +62,7 @@ const en = {
|
|
|
62
62
|
clearFormatting: 'Clear formatting',
|
|
63
63
|
outdent: 'Outdent',
|
|
64
64
|
indent: 'Indent',
|
|
65
|
+
settings: 'Toolbar settings',
|
|
65
66
|
ribbon: {
|
|
66
67
|
tabsLabel: 'Ribbon tabs',
|
|
67
68
|
quickAccess: 'Quick access',
|
|
@@ -92,6 +93,20 @@ const en = {
|
|
|
92
93
|
right: 'Align right',
|
|
93
94
|
},
|
|
94
95
|
},
|
|
96
|
+
toolbarSettings: {
|
|
97
|
+
title: 'Toolbar settings',
|
|
98
|
+
close: 'Close',
|
|
99
|
+
groups: {
|
|
100
|
+
formatting: 'Formatting',
|
|
101
|
+
alignment: 'Alignment & indent',
|
|
102
|
+
font: 'Font',
|
|
103
|
+
insert: 'Insert',
|
|
104
|
+
tools: 'Tools',
|
|
105
|
+
zoom: 'Zoom',
|
|
106
|
+
utilities: 'Drafts, search & help',
|
|
107
|
+
history: 'Save, undo & redo',
|
|
108
|
+
},
|
|
109
|
+
},
|
|
95
110
|
leaveDialog: {
|
|
96
111
|
title: 'Unsaved changes',
|
|
97
112
|
message: 'You have unsaved changes. What would you like to do before leaving?',
|
|
@@ -196,6 +211,7 @@ const en = {
|
|
|
196
211
|
failed: 'Could not save the correction',
|
|
197
212
|
close: 'Close',
|
|
198
213
|
correctDocument: 'Correct whole document',
|
|
214
|
+
wholeWord: 'Whole word only',
|
|
199
215
|
},
|
|
200
216
|
contextMenu: {
|
|
201
217
|
cut: 'Cut',
|
|
@@ -360,6 +376,7 @@ const ur = {
|
|
|
360
376
|
clearFormatting: 'فارمیٹنگ ختم کریں',
|
|
361
377
|
outdent: 'حاشیہ کم کریں',
|
|
362
378
|
indent: 'حاشیہ بڑھائیں',
|
|
379
|
+
settings: 'ٹول بار کی ترتیبات',
|
|
363
380
|
ribbon: {
|
|
364
381
|
tabsLabel: 'ربن کے ٹیب',
|
|
365
382
|
quickAccess: 'فوری رسائی',
|
|
@@ -390,6 +407,20 @@ const ur = {
|
|
|
390
407
|
right: 'دائیں سیدھ',
|
|
391
408
|
},
|
|
392
409
|
},
|
|
410
|
+
toolbarSettings: {
|
|
411
|
+
title: 'ٹول بار کی ترتیبات',
|
|
412
|
+
close: 'بند کریں',
|
|
413
|
+
groups: {
|
|
414
|
+
formatting: 'فارمیٹنگ',
|
|
415
|
+
alignment: 'سیدھ اور حاشیہ',
|
|
416
|
+
font: 'فونٹ',
|
|
417
|
+
insert: 'داخل کریں',
|
|
418
|
+
tools: 'آلات',
|
|
419
|
+
zoom: 'زوم',
|
|
420
|
+
utilities: 'ڈرافٹس، تلاش اور مدد',
|
|
421
|
+
history: 'محفوظ کریں، واپس اور آگے',
|
|
422
|
+
},
|
|
423
|
+
},
|
|
393
424
|
leaveDialog: {
|
|
394
425
|
title: 'غیر محفوظ شدہ تبدیلیاں',
|
|
395
426
|
message: 'آپ کی تبدیلیاں محفوظ نہیں ہوئیں۔ جانے سے پہلے آپ کیا کرنا چاہیں گے؟',
|
|
@@ -494,6 +525,7 @@ const ur = {
|
|
|
494
525
|
failed: 'تصحیح محفوظ نہیں ہو سکی',
|
|
495
526
|
close: 'بند کریں',
|
|
496
527
|
correctDocument: 'تمام متن کی تصحیح کریں',
|
|
528
|
+
wholeWord: 'صرف پورا لفظ',
|
|
497
529
|
},
|
|
498
530
|
contextMenu: {
|
|
499
531
|
cut: 'کاٹیں',
|
|
@@ -658,6 +690,7 @@ const paShahmukhi = {
|
|
|
658
690
|
clearFormatting: 'فارمیٹنگ ہٹاؤ',
|
|
659
691
|
outdent: 'حاشیہ گھٹاؤ',
|
|
660
692
|
indent: 'حاشیہ ودھاؤ',
|
|
693
|
+
settings: 'ٹول بار دیاں ترتیباں',
|
|
661
694
|
ribbon: {
|
|
662
695
|
tabsLabel: 'ربن دے ٹیب',
|
|
663
696
|
quickAccess: 'جھٹ رسائی',
|
|
@@ -688,6 +721,20 @@ const paShahmukhi = {
|
|
|
688
721
|
right: 'سجے سیدھ',
|
|
689
722
|
},
|
|
690
723
|
},
|
|
724
|
+
toolbarSettings: {
|
|
725
|
+
title: 'ٹول بار دیاں ترتیباں',
|
|
726
|
+
close: 'بند کرو',
|
|
727
|
+
groups: {
|
|
728
|
+
formatting: 'فارمیٹنگ',
|
|
729
|
+
alignment: 'سیدھ تے حاشیہ',
|
|
730
|
+
font: 'فونٹ',
|
|
731
|
+
insert: 'داخل کرو',
|
|
732
|
+
tools: 'اوزار',
|
|
733
|
+
zoom: 'زوم',
|
|
734
|
+
utilities: 'ڈرافٹس، تلاش تے مدد',
|
|
735
|
+
history: 'سانبھو، واپس تے اگے',
|
|
736
|
+
},
|
|
737
|
+
},
|
|
691
738
|
leaveDialog: {
|
|
692
739
|
title: 'غیر محفوظ تبدیلیاں',
|
|
693
740
|
message: 'تہاڈیاں تبدیلیاں سنبھالیاں نئیں گئیاں۔ جان توں پہلاں تسی کی کرنا چاہو گے؟',
|
|
@@ -792,6 +839,7 @@ const paShahmukhi = {
|
|
|
792
839
|
failed: 'درستی سانبھی نئیں جا سکی',
|
|
793
840
|
close: 'بند کرو',
|
|
794
841
|
correctDocument: 'پورے متن دی درستی کرو',
|
|
842
|
+
wholeWord: 'صرف پورا لفظ',
|
|
795
843
|
},
|
|
796
844
|
contextMenu: {
|
|
797
845
|
cut: 'کٹو',
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type { FontOption, FontMode } from './fonts/index.js';
|
|
|
11
11
|
export { STRINGS, getStrings, useStrings, useUiStrings, UiStringsContext } from './i18n/index.js';
|
|
12
12
|
export type { Locale, Strings } from './i18n/index.js';
|
|
13
13
|
export { registerSpellDictionary, hasSpellDictionary, setEnglishDictionaryBaseUrl, type HunspellFiles, type SpellLanguage } from './spellcheck/spellDictionaries.js';
|
|
14
|
-
export { localStorageAutoCorrectStore, apiAutoCorrectStore, fileAutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
14
|
+
export { localStorageAutoCorrectStore, apiAutoCorrectStore, fileAutoCorrectStore, nawishtaAutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
15
15
|
export type { AutoCorrectStore, AutoCorrectEntry } from './autocorrect/autoCorrectStores.js';
|
|
16
16
|
export { normalizeUrdu, normalizeUrduCharacters, removeUrduDiacritics, replaceUrduDigits } from './normalization/urduNormalize.js';
|
|
17
17
|
export type { UrduNormalizationOptions } from './normalization/urduNormalize.js';
|
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,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,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,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAC1G,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACpD,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,2BAA2B,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAClK,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,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,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,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,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAC1G,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACpD,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,2BAA2B,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAClK,OAAO,EAAE,4BAA4B,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AACpJ,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
|
@@ -5,7 +5,7 @@ export { ImageNode, $createImageNode, $isImageNode } from './image/ImageNode.js'
|
|
|
5
5
|
export { DEFAULT_FONT_OPTIONS, URDU_WEB_FONT_OPTIONS, FONT_SIZES_PX, ZOOM_LEVELS_PERCENT } from './fonts/index.js';
|
|
6
6
|
export { STRINGS, getStrings, useStrings, useUiStrings, UiStringsContext } from './i18n/index.js';
|
|
7
7
|
export { registerSpellDictionary, hasSpellDictionary, setEnglishDictionaryBaseUrl } from './spellcheck/spellDictionaries.js';
|
|
8
|
-
export { localStorageAutoCorrectStore, apiAutoCorrectStore, fileAutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
8
|
+
export { localStorageAutoCorrectStore, apiAutoCorrectStore, fileAutoCorrectStore, nawishtaAutoCorrectStore } from './autocorrect/autoCorrectStores.js';
|
|
9
9
|
export { normalizeUrdu, normalizeUrduCharacters, removeUrduDiacritics, replaceUrduDigits } from './normalization/urduNormalize.js';
|
|
10
10
|
export { localStorageUserWordStore, apiUserWordStore, ignoreWord, addUserWord, onSpellWordsChange } from './spellcheck/userWords.js';
|
|
11
11
|
export { dictionaryCompletionStore, apiCompletionStore } from './autocomplete/completionStores.js';
|
package/dist/theme/editor.css
CHANGED
|
@@ -1076,6 +1076,16 @@
|
|
|
1076
1076
|
color: inherit;
|
|
1077
1077
|
}
|
|
1078
1078
|
|
|
1079
|
+
.likhari-autocorrect-checkbox {
|
|
1080
|
+
flex-direction: row;
|
|
1081
|
+
align-items: center;
|
|
1082
|
+
gap: 6px;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
.likhari-autocorrect-checkbox input {
|
|
1086
|
+
width: auto;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1079
1089
|
.likhari-autocorrect-actions {
|
|
1080
1090
|
display: flex;
|
|
1081
1091
|
flex-direction: column;
|
|
@@ -1097,6 +1107,50 @@
|
|
|
1097
1107
|
cursor: default;
|
|
1098
1108
|
}
|
|
1099
1109
|
|
|
1110
|
+
/* Toolbar settings panel: a Mantine Popover dropdown anchored on the gear button. */
|
|
1111
|
+
.likhari-toolbar-settings-panel {
|
|
1112
|
+
width: 280px;
|
|
1113
|
+
max-height: min(70vh, 480px);
|
|
1114
|
+
overflow-y: auto;
|
|
1115
|
+
padding: 8px;
|
|
1116
|
+
font-size: 13px;
|
|
1117
|
+
background: var(--editor-paper-dim);
|
|
1118
|
+
color: inherit;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
.likhari-toolbar-settings-groups {
|
|
1122
|
+
display: flex;
|
|
1123
|
+
flex-direction: column;
|
|
1124
|
+
gap: 10px;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
.likhari-toolbar-settings-group {
|
|
1128
|
+
border: 1px solid var(--editor-line);
|
|
1129
|
+
border-radius: 6px;
|
|
1130
|
+
padding: 6px 8px;
|
|
1131
|
+
margin: 0;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
.likhari-toolbar-settings-group legend {
|
|
1135
|
+
padding: 0 4px;
|
|
1136
|
+
font-size: 11px;
|
|
1137
|
+
text-transform: uppercase;
|
|
1138
|
+
letter-spacing: 0.02em;
|
|
1139
|
+
opacity: 0.7;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
.likhari-toolbar-settings-item {
|
|
1143
|
+
display: flex;
|
|
1144
|
+
align-items: center;
|
|
1145
|
+
gap: 6px;
|
|
1146
|
+
padding: 3px 2px;
|
|
1147
|
+
cursor: pointer;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
.likhari-toolbar-settings-item input {
|
|
1151
|
+
width: auto;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1100
1154
|
/* Autocomplete suggestions, shown under the caret while typing. */
|
|
1101
1155
|
.likhari-autocomplete {
|
|
1102
1156
|
z-index: 20;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which toolbar items the user has chosen to hide, kept in localStorage so the
|
|
3
|
+
* choice survives a reload. A feature a host turned off (`EditorFeatureConfig`)
|
|
4
|
+
* is never offered here and is unaffected by it — this only lets the user declutter
|
|
5
|
+
* what the host already made available, it does not re-gate availability.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useToolbarItemVisibility(): {
|
|
8
|
+
hidden: ReadonlySet<string>;
|
|
9
|
+
isHidden: (id: string) => boolean;
|
|
10
|
+
toggle: (id: string) => void;
|
|
11
|
+
};
|
|
12
|
+
/** One toggleable row in the toolbar settings panel. */
|
|
13
|
+
export interface ToolbarVisibilityItem {
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
}
|
|
17
|
+
/** A labelled group of toggleable rows, as shown in the toolbar settings panel. */
|
|
18
|
+
export interface ToolbarVisibilityGroup {
|
|
19
|
+
id: string;
|
|
20
|
+
label: string;
|
|
21
|
+
items: ToolbarVisibilityItem[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=toolbarVisibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolbarVisibility.d.ts","sourceRoot":"","sources":["../../src/toolbar/toolbarVisibility.ts"],"names":[],"mappings":"AAqBA;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI;IAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAc3I;AAED,wDAAwD;AACxD,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,mFAAmF;AACnF,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,qBAAqB,EAAE,CAAC;CAChC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
const STORAGE_KEY = 'likhari-toolbar-hidden-items';
|
|
3
|
+
function readHidden() {
|
|
4
|
+
try {
|
|
5
|
+
const parsed = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]');
|
|
6
|
+
return new Set(Array.isArray(parsed) ? parsed.filter((id) => typeof id === 'string') : []);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return new Set();
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function writeHidden(hidden) {
|
|
13
|
+
try {
|
|
14
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify([...hidden]));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// Storage disabled or full: the choice applies for this session only.
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Which toolbar items the user has chosen to hide, kept in localStorage so the
|
|
22
|
+
* choice survives a reload. A feature a host turned off (`EditorFeatureConfig`)
|
|
23
|
+
* is never offered here and is unaffected by it — this only lets the user declutter
|
|
24
|
+
* what the host already made available, it does not re-gate availability.
|
|
25
|
+
*/
|
|
26
|
+
export function useToolbarItemVisibility() {
|
|
27
|
+
const [hidden, setHidden] = useState(() => (typeof localStorage === 'undefined' ? new Set() : readHidden()));
|
|
28
|
+
const toggle = (id) => {
|
|
29
|
+
setHidden((prev) => {
|
|
30
|
+
const next = new Set(prev);
|
|
31
|
+
if (next.has(id))
|
|
32
|
+
next.delete(id);
|
|
33
|
+
else
|
|
34
|
+
next.add(id);
|
|
35
|
+
writeHidden(next);
|
|
36
|
+
return next;
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
return { hidden, isHidden: (id) => hidden.has(id), toggle };
|
|
40
|
+
}
|