@inshapardaz/likhari-react 0.1.18-dev.165 → 0.1.18-dev.169
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.map +1 -1
- package/dist/EditorRoot.js +4 -2
- package/dist/components/FindReplaceBar.d.ts +6 -2
- package/dist/components/FindReplaceBar.d.ts.map +1 -1
- package/dist/components/FindReplaceBar.js +37 -23
- package/dist/components/Toolbar.d.ts +4 -1
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +3 -5
- package/dist/theme/editor.css +52 -17
- package/package.json +1 -1
package/dist/EditorRoot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAY1D,OAAO,KAAK,EAA8B,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEjF,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,EAAwB,KAAK,mBAAmB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAKzH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAOjE,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"EditorRoot.d.ts","sourceRoot":"","sources":["../src/EditorRoot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAY1D,OAAO,KAAK,EAA8B,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEjF,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,EAAwB,KAAK,mBAAmB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAKzH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAOjE,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAahF,OAAO,EAAgC,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAMnE,yEAAyE;AACzE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,YAAY,GAAG,KAAK,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAClD;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrD;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,uGAAuG;IACvG,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3E,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IACrC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IAClD,iBAAiB,IAAI,OAAO,CAAC;IAC7B,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,KAAK,IAAI,IAAI,CAAC;CACf;AAQD,eAAO,MAAM,UAAU,uGA2XrB,CAAC"}
|
package/dist/EditorRoot.js
CHANGED
|
@@ -26,6 +26,7 @@ import { FootnotePlugin } from './plugins/FootnotePlugin.js';
|
|
|
26
26
|
import { PoetryPlugin } from './plugins/PoetryPlugin.js';
|
|
27
27
|
import { PoetryResizer } from './blocks/PoetryResizer.js';
|
|
28
28
|
import { DraftRestore } from './components/DraftRestore.js';
|
|
29
|
+
import { FindReplaceBar } from './components/FindReplaceBar.js';
|
|
29
30
|
import { LeaveDialog } from './components/LeaveDialog.js';
|
|
30
31
|
import { clearDraft, createDraftId, hasDraftContent, pruneDrafts, writeDraft, } from './persistence/draftStorage.js';
|
|
31
32
|
import { ImageOptionsContext } from './image/ImageOptionsContext.js';
|
|
@@ -67,6 +68,7 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
|
|
|
67
68
|
const editorStateRef = useRef(null);
|
|
68
69
|
const lastSavedJsonRef = useRef(null);
|
|
69
70
|
const [isDirty, setIsDirty] = useState(false);
|
|
71
|
+
const [findOpen, setFindOpen] = useState(false);
|
|
70
72
|
const isDirtyRef = useRef(isDirty);
|
|
71
73
|
isDirtyRef.current = isDirty;
|
|
72
74
|
const autosaveTimerRef = useRef(null);
|
|
@@ -279,9 +281,9 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
|
|
|
279
281
|
// rather than colliding on a shared one.
|
|
280
282
|
const portalTargetId = useId();
|
|
281
283
|
const portalTargetSelector = `#${CSS.escape(portalTargetId)}`;
|
|
282
|
-
return (_jsx(EditorThemeProvider, { theme: theme, colorScheme: colorScheme, accentColor: accentColor, scopeElementId: portalTargetId, children: _jsxs("div", { className: "likhari-root", dir: dir, ref: rootElementRef, "data-document-id": documentId, style: { height: typeof height === 'number' ? `${height}px` : height }, children: [_jsx("div", { id: portalTargetId, className: "likhari-portal-target" }), _jsx(PortalTargetContext.Provider, { value: portalTargetSelector, children: _jsxs(UiStringsContext.Provider, { value: strings, children: [_jsx(ImageOptionsContext.Provider, { value: imageOptions, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Toolbar, { config: config, onSave: handleSave, isDirty: isDirty, showSave: showSave, fontOptions: fontOptions, direction: dir, locale: locale, drafts: autosave
|
|
284
|
+
return (_jsx(EditorThemeProvider, { theme: theme, colorScheme: colorScheme, accentColor: accentColor, scopeElementId: portalTargetId, children: _jsxs("div", { className: "likhari-root", dir: dir, ref: rootElementRef, "data-document-id": documentId, style: { height: typeof height === 'number' ? `${height}px` : height }, children: [_jsx("div", { id: portalTargetId, className: "likhari-portal-target" }), _jsx(PortalTargetContext.Provider, { value: portalTargetSelector, children: _jsxs(UiStringsContext.Provider, { value: strings, children: [_jsx(ImageOptionsContext.Provider, { value: imageOptions, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Toolbar, { config: config, onSave: handleSave, findOpen: findOpen, onToggleFind: () => setFindOpen((v) => !v), isDirty: isDirty, showSave: showSave, fontOptions: fontOptions, direction: dir, locale: locale, drafts: autosave
|
|
283
285
|
? { currentId: draftId, maxBytes: autosaveMaxBytes, adoptOnRestore: !documentId, onRestored: handleDraftRestored }
|
|
284
|
-
: undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsx("div", { className: "likhari-canvas", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "likhari-content-editable", dir: dir, "aria-label": strings.editor.contentLabel }), placeholder: _jsx("div", { className: "likhari-placeholder", children: resolvedPlaceholder }), ErrorBoundary: LexicalErrorBoundary }) }), config.history && _jsx(HistoryPlugin, {}), (config.lists.bullet || config.lists.numbered || config.lists.check) && _jsx(ListPlugin, {}), config.lists.check && _jsx(CheckListPlugin, {}), config.links && _jsx(LinkPlugin, {}), config.links && _jsx(LinkPastePlugin, {}), config.blocks.pageBreak && _jsx(PageBreakPlugin, {}), config.columns && _jsx(LayoutPlugin, {}), config.footnotes && _jsx(FootnotePlugin, {}), config.poetry.enabled && _jsx(PoetryPlugin, {}), config.poetry.enabled && _jsx(PoetryResizer, {}), config.tables && _jsx(TablePlugin, { hasCellMerge: true, hasTabHandler: true }), config.blocks.horizontalRule && _jsx(HorizontalRulePlugin, {}), _jsx(EditorInstancePlugin, { instanceRef: editorInstanceRef }), _jsx(OnChangePlugin, { onChange: handleChange })] }) }), _jsx(LeaveDialog, { opened: leavePrompt !== null, canSave: Boolean(onSave), canSaveDraft: autosave || navigationGuard === 'save-draft', draftFailed: leavePrompt?.draftFailed ?? false, onSave: () => {
|
|
286
|
+
: undefined }), documentId && (_jsx(DraftRestore, { draftId: documentId, mode: restoreDraft, initialJson: initialContentJsonRef.current, locale: locale, onRestored: handleDraftRestored })), _jsxs("div", { className: "likhari-canvas-frame", children: [config.findReplace && findOpen && _jsx(FindReplaceBar, { strings: strings, onClose: () => setFindOpen(false) }), _jsx("div", { className: "likhari-canvas", children: _jsx(RichTextPlugin, { contentEditable: _jsx(ContentEditable, { className: "likhari-content-editable", dir: dir, "aria-label": strings.editor.contentLabel }), placeholder: _jsx("div", { className: "likhari-placeholder", children: resolvedPlaceholder }), ErrorBoundary: LexicalErrorBoundary }) })] }), config.history && _jsx(HistoryPlugin, {}), (config.lists.bullet || config.lists.numbered || config.lists.check) && _jsx(ListPlugin, {}), config.lists.check && _jsx(CheckListPlugin, {}), config.links && _jsx(LinkPlugin, {}), config.links && _jsx(LinkPastePlugin, {}), config.blocks.pageBreak && _jsx(PageBreakPlugin, {}), config.columns && _jsx(LayoutPlugin, {}), config.footnotes && _jsx(FootnotePlugin, {}), config.poetry.enabled && _jsx(PoetryPlugin, {}), config.poetry.enabled && _jsx(PoetryResizer, {}), config.tables && _jsx(TablePlugin, { hasCellMerge: true, hasTabHandler: true }), config.blocks.horizontalRule && _jsx(HorizontalRulePlugin, {}), _jsx(EditorInstancePlugin, { instanceRef: editorInstanceRef }), _jsx(OnChangePlugin, { onChange: handleChange })] }) }), _jsx(LeaveDialog, { opened: leavePrompt !== null, canSave: Boolean(onSave), canSaveDraft: autosave || navigationGuard === 'save-draft', draftFailed: leavePrompt?.draftFailed ?? false, onSave: () => {
|
|
285
287
|
handleSave();
|
|
286
288
|
settleLeave(true);
|
|
287
289
|
}, onSaveDraft: () => {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { Strings } from '../i18n/strings.js';
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
2
|
+
/**
|
|
3
|
+
* A compact find widget, right-aligned above the canvas (VS Code style). The
|
|
4
|
+
* first row is search; a chevron reveals the second row for replace. Typing
|
|
5
|
+
* only counts matches — the editor's selection moves to a match only when the
|
|
6
|
+
* user asks (next, previous, replace), so typing keeps going into the bar.
|
|
7
|
+
*/
|
|
4
8
|
export declare function FindReplaceBar({ strings, onClose }: {
|
|
5
9
|
strings: Strings;
|
|
6
10
|
onClose: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FindReplaceBar.d.ts","sourceRoot":"","sources":["../../src/components/FindReplaceBar.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C;
|
|
1
|
+
{"version":3,"file":"FindReplaceBar.d.ts","sourceRoot":"","sources":["../../src/components/FindReplaceBar.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,+BAyH7F"}
|
|
@@ -1,57 +1,71 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
4
|
-
import { IconX } from '@tabler/icons-react';
|
|
4
|
+
import { IconChevronDown, IconChevronRight, IconX } from '@tabler/icons-react';
|
|
5
5
|
import { $findMatches, $replaceAll, $replaceMatch, $selectMatch } from '../find/findReplaceActions.js';
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
6
|
+
/**
|
|
7
|
+
* A compact find widget, right-aligned above the canvas (VS Code style). The
|
|
8
|
+
* first row is search; a chevron reveals the second row for replace. Typing
|
|
9
|
+
* only counts matches — the editor's selection moves to a match only when the
|
|
10
|
+
* user asks (next, previous, replace), so typing keeps going into the bar.
|
|
11
|
+
*/
|
|
8
12
|
export function FindReplaceBar({ strings, onClose }) {
|
|
9
13
|
const [editor] = useLexicalComposerContext();
|
|
10
14
|
const t = strings.findReplace;
|
|
11
15
|
const [query, setQuery] = useState('');
|
|
12
16
|
const [replacement, setReplacement] = useState('');
|
|
17
|
+
const [showReplace, setShowReplace] = useState(false);
|
|
13
18
|
const [index, setIndex] = useState(0);
|
|
14
19
|
const [count, setCount] = useState(0);
|
|
15
|
-
|
|
16
|
-
//
|
|
17
|
-
// the
|
|
20
|
+
const findInput = useRef(null);
|
|
21
|
+
// Runs `action` against the current matches inside a committed update, then
|
|
22
|
+
// syncs the count and index. Selecting a match is up to the action, so
|
|
23
|
+
// typing never moves the editor's selection.
|
|
18
24
|
const run = (action) => {
|
|
19
|
-
let result = { nextIndex: 0, matches: [] };
|
|
25
|
+
let result = { nextIndex: 0, matches: [], select: false };
|
|
20
26
|
editor.update(() => {
|
|
21
27
|
result = action($findMatches(query));
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
const match = result.matches[result.nextIndex];
|
|
29
|
+
if (result.select && match)
|
|
30
|
+
$selectMatch(match);
|
|
24
31
|
}, { discrete: true });
|
|
25
32
|
setCount(result.matches.length);
|
|
26
33
|
setIndex(result.nextIndex);
|
|
27
|
-
const
|
|
28
|
-
if (
|
|
29
|
-
editor.getElementByKey(
|
|
34
|
+
const match = result.matches[result.nextIndex];
|
|
35
|
+
if (result.select && match) {
|
|
36
|
+
editor.getElementByKey(match.anchorKey)?.scrollIntoView({ block: 'center' });
|
|
37
|
+
findInput.current?.focus();
|
|
38
|
+
}
|
|
30
39
|
};
|
|
31
40
|
useEffect(() => {
|
|
32
|
-
run((matches) => ({ nextIndex: 0, matches }));
|
|
33
|
-
// Re-
|
|
41
|
+
run((matches) => ({ nextIndex: 0, matches, select: false }));
|
|
42
|
+
// Re-count when the query changes; `run` closes over it.
|
|
34
43
|
}, [query]);
|
|
35
44
|
const step = (delta) => run((matches) => ({
|
|
36
45
|
matches,
|
|
37
46
|
nextIndex: matches.length === 0 ? 0 : (index + delta + matches.length) % matches.length,
|
|
47
|
+
select: true,
|
|
38
48
|
}));
|
|
39
49
|
const replaceCurrent = () => run((matches) => {
|
|
40
50
|
const match = matches[index];
|
|
41
51
|
if (match)
|
|
42
52
|
$replaceMatch(match, replacement);
|
|
43
53
|
const after = $findMatches(query);
|
|
44
|
-
return { matches: after, nextIndex: Math.min(index, Math.max(0, after.length - 1)) };
|
|
54
|
+
return { matches: after, nextIndex: Math.min(index, Math.max(0, after.length - 1)), select: true };
|
|
45
55
|
});
|
|
46
56
|
const replaceEverything = () => run(() => {
|
|
47
57
|
$replaceAll(query, replacement);
|
|
48
|
-
return { matches: $findMatches(query), nextIndex: 0 };
|
|
58
|
+
return { matches: $findMatches(query), nextIndex: 0, select: false };
|
|
49
59
|
});
|
|
50
60
|
const status = query === '' ? '' : count === 0 ? t.noMatches : `${index + 1} / ${count}`;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
const Chevron = showReplace ? IconChevronDown : IconChevronRight;
|
|
62
|
+
return (_jsxs("div", { className: "likhari-find-widget", role: "search", children: [_jsxs("div", { className: "likhari-find-row", children: [_jsx("button", { type: "button", className: "likhari-find-icon", onClick: () => setShowReplace((v) => !v), "aria-label": t.replace, "aria-expanded": showReplace, title: t.replace, children: _jsx(Chevron, { size: 14, stroke: 1.75 }) }), _jsx("input", { ref: findInput, "aria-label": t.find, placeholder: t.findPlaceholder, value: query, onChange: (e) => setQuery(e.target.value), onKeyDown: (e) => {
|
|
63
|
+
if (e.key === 'Enter')
|
|
64
|
+
step(e.shiftKey ? -1 : 1);
|
|
65
|
+
if (e.key === 'Escape')
|
|
66
|
+
onClose();
|
|
67
|
+
}, autoFocus: true }), _jsx("span", { className: "likhari-find-status", "aria-live": "polite", children: status }), _jsx("button", { type: "button", className: "likhari-find-icon", onClick: () => step(-1), disabled: count === 0, "aria-label": t.previous, title: t.previous, children: _jsx(IconChevronDown, { size: 14, stroke: 1.75, style: { transform: 'rotate(180deg)' } }) }), _jsx("button", { type: "button", className: "likhari-find-icon", onClick: () => step(1), disabled: count === 0, "aria-label": t.next, title: t.next, children: _jsx(IconChevronDown, { size: 14, stroke: 1.75 }) }), _jsx("button", { type: "button", className: "likhari-find-icon", onClick: onClose, "aria-label": t.close, title: t.close, children: _jsx(IconX, { size: 14, stroke: 1.75 }) })] }), showReplace && (_jsxs("div", { className: "likhari-find-row", children: [_jsx("span", { className: "likhari-find-icon-spacer", "aria-hidden": "true" }), _jsx("input", { "aria-label": t.replace, placeholder: t.replacePlaceholder, value: replacement, onChange: (e) => setReplacement(e.target.value), onKeyDown: (e) => {
|
|
68
|
+
if (e.key === 'Enter' && count > 0)
|
|
69
|
+
replaceCurrent();
|
|
70
|
+
} }), _jsx("button", { type: "button", onClick: replaceCurrent, disabled: count === 0, children: t.replaceOne }), _jsx("button", { type: "button", onClick: replaceEverything, disabled: count === 0, children: t.replaceAll })] }))] }));
|
|
57
71
|
}
|
|
@@ -4,6 +4,9 @@ import { type FontOption } from '../fonts/index.js';
|
|
|
4
4
|
import type { Locale } from '../i18n/strings.js';
|
|
5
5
|
export interface ToolbarProps {
|
|
6
6
|
config: ResolvedEditorFeatureConfig;
|
|
7
|
+
/** Whether the find-and-replace widget is open, and how to toggle it (owned by EditorRoot). */
|
|
8
|
+
findOpen?: boolean;
|
|
9
|
+
onToggleFind?: () => void;
|
|
7
10
|
onSave?: () => void;
|
|
8
11
|
isDirty?: boolean;
|
|
9
12
|
showSave?: boolean;
|
|
@@ -16,5 +19,5 @@ export interface ToolbarProps {
|
|
|
16
19
|
/** Autosave drafts: when set, the toolbar offers a Drafts button that lists and restores them. */
|
|
17
20
|
drafts?: DraftsToolbarOptions;
|
|
18
21
|
}
|
|
19
|
-
export declare function Toolbar({ config, onSave, isDirty, showSave, fontOptions, direction, locale, drafts }: ToolbarProps): import("react").JSX.Element;
|
|
22
|
+
export declare function Toolbar({ config, onSave, isDirty, showSave, findOpen, onToggleFind, fontOptions, direction, locale, drafts }: ToolbarProps): import("react").JSX.Element;
|
|
20
23
|
//# 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":"AAqFA,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAA6D,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAItG,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,iBAAiB,CAAC;AA+gBvD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,2BAA2B,CAAC;IACpC,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,wFAAwF;IACxF,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAED,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAgB,EAAE,YAAY,EAAE,WAAkC,EAAE,SAAiB,EAAE,MAAa,EAAE,MAAM,EAAE,EAAE,YAAY,+BAskCxL"}
|
|
@@ -8,7 +8,6 @@ import { $createParagraphNode } from 'lexical';
|
|
|
8
8
|
import { $createHeadingNode, $createQuoteNode, $isHeadingNode, $isQuoteNode } from '@lexical/rich-text';
|
|
9
9
|
import { $isListNode, INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, } from '@lexical/list';
|
|
10
10
|
import { $findMatchingParent, $insertNodeToNearestRoot } from '@lexical/utils';
|
|
11
|
-
import { FindReplaceBar } from './FindReplaceBar.js';
|
|
12
11
|
import { INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/react/LexicalHorizontalRuleNode';
|
|
13
12
|
import { ImageDialog } from '../image/ImageDialog.js';
|
|
14
13
|
import { $createImageNode } from '../image/ImageNode.js';
|
|
@@ -183,7 +182,7 @@ function PoetryMenuItems({ strings, layout, scale, centered, onAction, }) {
|
|
|
183
182
|
};
|
|
184
183
|
return (_jsxs(_Fragment, { children: [_jsx(Menu.Label, { children: t.menuLabel }), item(IconColumns1, t.singleColumn, setLayout('single'), layout === 'single'), item(IconColumns2, t.twoColumn, setLayout('two-column'), layout === 'two-column'), item(IconArrowsShuffle, t.staggered, setLayout('staggered'), layout === 'staggered'), _jsx(Menu.Divider, {}), _jsx(Menu.Divider, {}), item(IconRowInsertTop, t.insertCoupletBefore, () => $insertCoupletRelativeToSelection('before')), item(IconRowInsertBottom, t.insertCoupletAfter, () => $insertCoupletRelativeToSelection('after')), item(IconArrowsMinimize, t.tighterSpacing, () => $adjustPoetrySpacing(-1), !canStep(POETRY_SPACINGS, scale.spacing, -1)), item(IconArrowsMaximize, t.looserSpacing, () => $adjustPoetrySpacing(1), !canStep(POETRY_SPACINGS, scale.spacing, 1)), layout === 'staggered' && (_jsxs(_Fragment, { children: [item(IconArrowsMinimize, t.narrowerCouplets, () => $adjustPoetryStagger(-1), !canStep(POETRY_STAGGERS, scale.stagger, -1)), item(IconArrowsMaximize, t.widerCouplets, () => $adjustPoetryStagger(1), !canStep(POETRY_STAGGERS, scale.stagger, 1))] })), layout === 'two-column' && (_jsxs(_Fragment, { children: [item(IconAlignCenter, centered ? t.uncenterCouplet : t.centerCouplet, () => $setCoupletCentered(!centered)), item(IconColumns2, t.narrowerGutter, () => $adjustPoetryGutter(-1), !canStep(POETRY_GUTTERS, scale.gutter, -1)), item(IconColumns2, t.widerGutter, () => $adjustPoetryGutter(1), !canStep(POETRY_GUTTERS, scale.gutter, 1))] })), item(IconTrash, t.deleteCouplet, $deletePoetryCouplet, false, 'red'), item(IconTrash, t.deletePoetry, $deletePoetryBlock, false, 'red')] }));
|
|
185
184
|
}
|
|
186
|
-
export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
|
|
185
|
+
export function Toolbar({ config, onSave, isDirty, showSave, findOpen = false, onToggleFind, fontOptions = DEFAULT_FONT_OPTIONS, direction = 'ltr', locale = 'en', drafts }) {
|
|
187
186
|
const [editor] = useLexicalComposerContext();
|
|
188
187
|
const [state, setState] = useState(INITIAL_STATE);
|
|
189
188
|
const strings = useStrings(locale);
|
|
@@ -386,7 +385,6 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
386
385
|
closeTableDialog();
|
|
387
386
|
};
|
|
388
387
|
const [layoutDialogOpen, setLayoutDialogOpen] = useState(false);
|
|
389
|
-
const [findOpen, setFindOpen] = useState(false);
|
|
390
388
|
const openLayoutDialog = () => {
|
|
391
389
|
snapshotSelection();
|
|
392
390
|
setLayoutDialogOpen(true);
|
|
@@ -810,7 +808,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
810
808
|
restoreSelection();
|
|
811
809
|
openLinkDialog();
|
|
812
810
|
}, onRemove: removeLink, strings: strings }) })] })) : (_jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.insertLink, onClick: openLinkDialog })) }, "link")),
|
|
813
|
-
showStubInsertGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [(config.images.linked || config.images.embedded) && (_jsx(ToolbarButton, { icon: IconPhoto, title: strings.toolbar.insertImage, onClick: openImageDialog })), config.blocks.pageBreak && (_jsx(ToolbarButton, { icon: IconPageBreak, title: strings.toolbar.insertPageBreak, onClick: () => editor.dispatchCommand(INSERT_PAGE_BREAK_COMMAND, undefined) })), config.tables && _jsx(ToolbarButton, { icon: IconTable, title: strings.toolbar.insertTable, onClick: openTableDialog }), config.columns && _jsx(ToolbarButton, { icon: IconColumns, title: strings.toolbar.insertColumns, onClick: openLayoutDialog }), config.footnotes && (_jsx(ToolbarButton, { icon: IconNumber1Small, title: strings.toolbar.insertFootnote, onClick: () => editor.dispatchCommand(INSERT_FOOTNOTE_COMMAND, undefined) })), config.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.findReplace && (_jsx(ToolbarButton, { icon: IconSearch, title: strings.findReplace.toggle, active: findOpen, onClick:
|
|
811
|
+
showStubInsertGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [(config.images.linked || config.images.embedded) && (_jsx(ToolbarButton, { icon: IconPhoto, title: strings.toolbar.insertImage, onClick: openImageDialog })), config.blocks.pageBreak && (_jsx(ToolbarButton, { icon: IconPageBreak, title: strings.toolbar.insertPageBreak, onClick: () => editor.dispatchCommand(INSERT_PAGE_BREAK_COMMAND, undefined) })), config.tables && _jsx(ToolbarButton, { icon: IconTable, title: strings.toolbar.insertTable, onClick: openTableDialog }), config.columns && _jsx(ToolbarButton, { icon: IconColumns, title: strings.toolbar.insertColumns, onClick: openLayoutDialog }), config.footnotes && (_jsx(ToolbarButton, { icon: IconNumber1Small, title: strings.toolbar.insertFootnote, onClick: () => editor.dispatchCommand(INSERT_FOOTNOTE_COMMAND, undefined) })), config.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.findReplace && (_jsx(ToolbarButton, { icon: IconSearch, title: strings.findReplace.toggle, active: findOpen, onClick: onToggleFind })), config.poetry.enabled && locale !== 'en' && (_jsx(ToolbarButton, { icon: IconFeather, title: strings.toolbar.insertPoetryCouplet, onClick: () => editor.dispatchCommand(INSERT_POETRY_COUPLET_COMMAND, { layout: config.poetry.defaultLayout }) }))] }, "stubInsert")),
|
|
814
812
|
config.tables && state.inTable && (_jsx("div", { className: "likhari-toolbar-group", children: _jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 240, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx("button", { type: "button", className: "likhari-toolbar-button", "data-active": "true", "aria-pressed": "true", "aria-haspopup": "menu", "aria-label": strings.toolbar.tableOptions, title: strings.toolbar.tableOptions, onMouseDown: (e) => e.preventDefault(), children: _jsx(IconTableOptions, { size: ICON_SIZE, stroke: ICON_STROKE }) }) }), _jsx(Menu.Dropdown, { children: _jsx(TableMenuItems, { strings: strings, direction: direction, rows: state.tableRows, columns: state.tableColumns, canMergeCells: state.canMergeCells, canUnmergeCell: state.canUnmergeCell, onAction: runMenuAction }) })] }) }, "tableActions")),
|
|
815
813
|
config.poetry.enabled && state.inPoetry && (_jsx("div", { className: "likhari-toolbar-group", children: _jsxs(Menu, { position: "bottom-start", withinPortal: true, portalProps: { target: portalTarget }, shadow: "sm", width: 200, onOpen: snapshotSelection, children: [_jsx(Menu.Target, { children: _jsx("button", { type: "button", className: "likhari-toolbar-button", "data-active": "true", "aria-pressed": "true", "aria-haspopup": "menu", "aria-label": strings.toolbar.poetryOptions, title: strings.toolbar.poetryOptions, onMouseDown: (e) => e.preventDefault(), children: _jsx(IconFeather, { size: ICON_SIZE, stroke: ICON_STROKE }) }) }), _jsx(Menu.Dropdown, { children: _jsx(PoetryMenuItems, { strings: strings, layout: state.poetryLayout, scale: state.poetryScale, centered: state.poetryCentered, onAction: runMenuAction }) })] }) }, "poetryActions")),
|
|
816
814
|
showLanguageGroup && (_jsxs("div", { className: "likhari-toolbar-group likhari-toolbar-group--collapse-tablet", children: [config.language.autocorrect && _jsx(StubButton, { icon: IconWand, title: strings.toolbar.autocorrect, comingSoon: strings.toolbar.comingSoon }), config.language.textCleanup && _jsx(StubButton, { icon: IconSparkles, title: strings.toolbar.textCleanup, comingSoon: strings.toolbar.comingSoon }), config.language.spellCheck && _jsx(StubButton, { icon: IconAbc, title: strings.toolbar.spellChecker, comingSoon: strings.toolbar.comingSoon })] }, "language")),
|
|
@@ -840,5 +838,5 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
840
838
|
display: 'flex',
|
|
841
839
|
flexWrap: 'nowrap',
|
|
842
840
|
gap: 8,
|
|
843
|
-
}, children: [fixedGroups, movableGroups.map((group) => (_jsx(MovableGroupButtons, { group: group }, group.key)))] }), (config.images.linked || config.images.embedded) && (_jsx(ImageDialog, { mode: "insert", opened: imageDialogOpen, onSubmit: insertImage, onClose: closeImageDialog })), config.tables && _jsx(TableDialog, { opened: tableDialogOpen, onSubmit: insertTable, onClose: closeTableDialog }), config.
|
|
841
|
+
}, children: [fixedGroups, movableGroups.map((group) => (_jsx(MovableGroupButtons, { group: group }, group.key)))] }), (config.images.linked || config.images.embedded) && (_jsx(ImageDialog, { mode: "insert", opened: imageDialogOpen, onSubmit: insertImage, onClose: closeImageDialog })), config.tables && _jsx(TableDialog, { opened: tableDialogOpen, onSubmit: insertTable, onClose: closeTableDialog }), config.columns && _jsx(LayoutDialog, { opened: layoutDialogOpen, onSubmit: insertLayout, onClose: closeLayoutDialog }), config.links && (_jsx(LinkDialog, { opened: linkDialogOpen, initialUrl: state.linkUrl, showTextField: linkNeedsText, onSubmit: applyLink, onRemove: state.isLink ? removeLink : undefined, onClose: closeLinkDialog })), drafts && _jsx(DraftsDialog, { opened: draftsOpen, locale: locale, onClose: () => setDraftsOpen(false), ...drafts })] }));
|
|
844
842
|
}
|
package/dist/theme/editor.css
CHANGED
|
@@ -160,6 +160,14 @@
|
|
|
160
160
|
/* Canvas — editor-ui-design-spec.md §4. flex: 1 1 auto + min-height: 0 lets
|
|
161
161
|
this pane absorb the root's height and scroll internally instead of the
|
|
162
162
|
editor (and the page around it) growing to fit the content. */
|
|
163
|
+
.likhari-canvas-frame {
|
|
164
|
+
position: relative;
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
flex: 1 1 auto;
|
|
168
|
+
min-height: 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
163
171
|
.likhari-canvas {
|
|
164
172
|
position: relative;
|
|
165
173
|
flex: 1 1 auto;
|
|
@@ -756,19 +764,34 @@
|
|
|
756
764
|
outline-offset: 1px;
|
|
757
765
|
}
|
|
758
766
|
|
|
759
|
-
|
|
767
|
+
/* Floats over the top-right of the canvas, so it takes no space from the
|
|
768
|
+
toolbar or the page. */
|
|
769
|
+
.likhari-find-widget {
|
|
770
|
+
position: absolute;
|
|
771
|
+
z-index: 5;
|
|
772
|
+
top: 8px;
|
|
773
|
+
inset-inline-end: 16px;
|
|
760
774
|
display: flex;
|
|
761
|
-
flex-
|
|
762
|
-
align-items: center;
|
|
775
|
+
flex-direction: column;
|
|
763
776
|
gap: 6px;
|
|
764
|
-
|
|
765
|
-
|
|
777
|
+
width: fit-content;
|
|
778
|
+
padding: 6px;
|
|
779
|
+
border: 1px solid var(--editor-line);
|
|
780
|
+
border-radius: 6px;
|
|
766
781
|
background: var(--editor-paper-dim);
|
|
782
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
767
783
|
font-size: 13px;
|
|
768
784
|
}
|
|
769
785
|
|
|
770
|
-
.likhari-find-
|
|
771
|
-
|
|
786
|
+
.likhari-find-row {
|
|
787
|
+
display: flex;
|
|
788
|
+
align-items: center;
|
|
789
|
+
justify-content: flex-end;
|
|
790
|
+
gap: 4px;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.likhari-find-widget input {
|
|
794
|
+
width: 180px;
|
|
772
795
|
padding: 3px 6px;
|
|
773
796
|
border: 1px solid var(--editor-line);
|
|
774
797
|
border-radius: 4px;
|
|
@@ -776,27 +799,39 @@
|
|
|
776
799
|
color: inherit;
|
|
777
800
|
}
|
|
778
801
|
|
|
779
|
-
.likhari-find-
|
|
780
|
-
padding:
|
|
802
|
+
.likhari-find-widget button {
|
|
803
|
+
padding: 2px 8px;
|
|
781
804
|
border: 1px solid var(--editor-line);
|
|
782
805
|
border-radius: 4px;
|
|
783
806
|
background: transparent;
|
|
784
807
|
color: inherit;
|
|
785
808
|
cursor: pointer;
|
|
809
|
+
white-space: nowrap;
|
|
786
810
|
}
|
|
787
811
|
|
|
788
|
-
.likhari-find-
|
|
812
|
+
.likhari-find-widget button:disabled {
|
|
789
813
|
opacity: 0.5;
|
|
790
814
|
cursor: default;
|
|
791
815
|
}
|
|
792
816
|
|
|
793
|
-
.likhari-find-
|
|
794
|
-
min-width: 64px;
|
|
795
|
-
color: var(--editor-ink-muted, inherit);
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
.likhari-find-close {
|
|
817
|
+
.likhari-find-widget .likhari-find-icon {
|
|
799
818
|
display: inline-flex;
|
|
800
819
|
align-items: center;
|
|
801
|
-
|
|
820
|
+
justify-content: center;
|
|
821
|
+
width: 24px;
|
|
822
|
+
height: 24px;
|
|
823
|
+
padding: 0;
|
|
824
|
+
border: none;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.likhari-find-icon-spacer {
|
|
828
|
+
display: inline-block;
|
|
829
|
+
width: 24px;
|
|
830
|
+
flex: 0 0 24px;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.likhari-find-status {
|
|
834
|
+
min-width: 56px;
|
|
835
|
+
text-align: end;
|
|
836
|
+
opacity: 0.8;
|
|
802
837
|
}
|