@inshapardaz/likhari-react 0.1.10 → 0.1.11-dev.105
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 +1 -1
- package/dist/EditorRoot.d.ts.map +1 -1
- package/dist/EditorRoot.js +18 -8
- package/dist/blocks/PageBreakNode.d.ts +30 -0
- package/dist/blocks/PageBreakNode.d.ts.map +1 -0
- package/dist/blocks/PageBreakNode.js +112 -0
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +9 -3
- package/dist/i18n/strings.d.ts +3 -0
- package/dist/i18n/strings.d.ts.map +1 -1
- package/dist/i18n/strings.js +6 -0
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +2 -0
- package/dist/plugins/EditorInstancePlugin.d.ts +7 -0
- package/dist/plugins/EditorInstancePlugin.d.ts.map +1 -0
- package/dist/plugins/EditorInstancePlugin.js +13 -0
- package/dist/plugins/PageBreakPlugin.d.ts +3 -0
- package/dist/plugins/PageBreakPlugin.d.ts.map +1 -0
- package/dist/plugins/PageBreakPlugin.js +19 -0
- package/dist/theme/editor.css +39 -0
- package/dist/theme/editorTheme.d.ts.map +1 -1
- package/dist/theme/editorTheme.js +1 -0
- package/package.json +1 -1
package/dist/EditorRoot.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { type Locale } from './i18n/index.js';
|
|
|
8
8
|
/** What happens when the user is about to leave with unsaved changes. */
|
|
9
9
|
export type NavigationGuardMode = 'confirm' | 'save-draft' | 'off';
|
|
10
10
|
export interface EditorInitialContent {
|
|
11
|
-
format:
|
|
11
|
+
format: FormatId;
|
|
12
12
|
value: string;
|
|
13
13
|
}
|
|
14
14
|
export interface EditorRootProps {
|
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,
|
|
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;AAGjE,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAYhF,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,uGAqXrB,CAAC"}
|
package/dist/EditorRoot.js
CHANGED
|
@@ -11,6 +11,7 @@ import { TablePlugin } from '@lexical/react/LexicalTablePlugin';
|
|
|
11
11
|
import { HorizontalRulePlugin } from '@lexical/react/LexicalHorizontalRulePlugin';
|
|
12
12
|
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
|
|
13
13
|
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
|
|
14
|
+
import { EditorInstancePlugin } from './plugins/EditorInstancePlugin.js';
|
|
14
15
|
import { defaultFormatRegistry } from '@inshapardaz/likhari-converters';
|
|
15
16
|
import { resolveFeatureConfig } from '@inshapardaz/likhari-core';
|
|
16
17
|
import { EDITOR_NODES } from './nodes.js';
|
|
@@ -19,6 +20,7 @@ import { EditorThemeProvider } from './theme/EditorThemeProvider.js';
|
|
|
19
20
|
import { Toolbar } from './components/Toolbar.js';
|
|
20
21
|
import { injectUrduWebFontsCss } from './fonts/index.js';
|
|
21
22
|
import { LinkPastePlugin } from './plugins/LinkPastePlugin.js';
|
|
23
|
+
import { PageBreakPlugin } from './plugins/PageBreakPlugin.js';
|
|
22
24
|
import { DraftRestore } from './components/DraftRestore.js';
|
|
23
25
|
import { LeaveDialog } from './components/LeaveDialog.js';
|
|
24
26
|
import { clearDraft, createDraftId, hasDraftContent, pruneDrafts, writeDraft, } from './persistence/draftStorage.js';
|
|
@@ -199,13 +201,20 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
|
|
|
199
201
|
return defaultFormatRegistry.serialize(format, json);
|
|
200
202
|
},
|
|
201
203
|
setContent(value, format) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
const editor = editorInstanceRef.current;
|
|
205
|
+
if (!editor)
|
|
206
|
+
return;
|
|
207
|
+
const parsed = editor.parseEditorState(JSON.stringify(defaultFormatRegistry.parse(format, value)));
|
|
208
|
+
// The host's value is the new baseline: clean, and no stale draft of
|
|
209
|
+
// whatever it replaces should be offered back later.
|
|
210
|
+
lastSavedJsonRef.current = JSON.stringify(parsed.toJSON());
|
|
211
|
+
if (autosaveTimerRef.current) {
|
|
212
|
+
clearTimeout(autosaveTimerRef.current);
|
|
213
|
+
autosaveTimerRef.current = null;
|
|
214
|
+
}
|
|
215
|
+
pendingDraftRef.current = null;
|
|
216
|
+
editor.setEditorState(parsed);
|
|
217
|
+
setIsDirty(false);
|
|
209
218
|
},
|
|
210
219
|
hasUnsavedChanges() {
|
|
211
220
|
return isDirty;
|
|
@@ -218,6 +227,7 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
|
|
|
218
227
|
},
|
|
219
228
|
}), [isDirty]);
|
|
220
229
|
const rootElementRef = useRef(null);
|
|
230
|
+
const editorInstanceRef = useRef(null);
|
|
221
231
|
const handleChange = (state) => {
|
|
222
232
|
editorStateRef.current = state;
|
|
223
233
|
const json = JSON.stringify(state.toJSON());
|
|
@@ -267,7 +277,7 @@ export const EditorRoot = forwardRef(function EditorRoot({ documentId, initialCo
|
|
|
267
277
|
const portalTargetSelector = `#${CSS.escape(portalTargetId)}`;
|
|
268
278
|
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
|
|
269
279
|
? { currentId: draftId, maxBytes: autosaveMaxBytes, adoptOnRestore: !documentId, onRestored: handleDraftRestored }
|
|
270
|
-
: 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.tables && _jsx(TablePlugin, { hasCellMerge: false, hasTabHandler: true }), config.blocks.horizontalRule && _jsx(HorizontalRulePlugin, {}), _jsx(OnChangePlugin, { onChange: handleChange })] }) }), _jsx(LeaveDialog, { opened: leavePrompt !== null, canSave: Boolean(onSave), canSaveDraft: autosave || navigationGuard === 'save-draft', draftFailed: leavePrompt?.draftFailed ?? false, onSave: () => {
|
|
280
|
+
: 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.tables && _jsx(TablePlugin, { hasCellMerge: false, 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: () => {
|
|
271
281
|
handleSave();
|
|
272
282
|
settleLeave(true);
|
|
273
283
|
}, onSaveDraft: () => {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ReactElement } from 'react';
|
|
2
|
+
import { DecoratorNode, type DOMConversionMap, type DOMExportOutput, type EditorConfig, type LexicalCommand, type LexicalNode, type SerializedLexicalNode } from 'lexical';
|
|
3
|
+
export declare const INSERT_PAGE_BREAK_COMMAND: LexicalCommand<void>;
|
|
4
|
+
export type SerializedPageBreakNode = SerializedLexicalNode;
|
|
5
|
+
/**
|
|
6
|
+
* A manual page break — a print/paginated-export concept with no native
|
|
7
|
+
* Lexical node (lexical-editor-spec.md §4.3/§4.6). Renders as a visible
|
|
8
|
+
* dashed marker while editing, and as `page-break-after: always` both live
|
|
9
|
+
* (a print stylesheet, editor.css) and in exported HTML (`exportDOM`).
|
|
10
|
+
*
|
|
11
|
+
* Mirrors @lexical/react's HorizontalRuleNode pattern: `createDOM` returns
|
|
12
|
+
* the actual visible element (the click target `PageBreakComponent` wires
|
|
13
|
+
* selection/delete against), rather than `decorate()` rendering visuals.
|
|
14
|
+
*/
|
|
15
|
+
export declare class PageBreakNode extends DecoratorNode<ReactElement> {
|
|
16
|
+
static getType(): string;
|
|
17
|
+
static clone(node: PageBreakNode): PageBreakNode;
|
|
18
|
+
static importJSON(): PageBreakNode;
|
|
19
|
+
exportJSON(): SerializedPageBreakNode;
|
|
20
|
+
static importDOM(): DOMConversionMap | null;
|
|
21
|
+
exportDOM(): DOMExportOutput;
|
|
22
|
+
createDOM(config: EditorConfig): HTMLElement;
|
|
23
|
+
getTextContent(): string;
|
|
24
|
+
isInline(): false;
|
|
25
|
+
updateDOM(): boolean;
|
|
26
|
+
decorate(): import("react").JSX.Element;
|
|
27
|
+
}
|
|
28
|
+
export declare function $createPageBreakNode(): PageBreakNode;
|
|
29
|
+
export declare function $isPageBreakNode(node: LexicalNode | null | undefined): node is PageBreakNode;
|
|
30
|
+
//# sourceMappingURL=PageBreakNode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageBreakNode.d.ts","sourceRoot":"","sources":["../../src/blocks/PageBreakNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAKlE,OAAO,EAOL,aAAa,EAGb,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAEhB,KAAK,qBAAqB,EAC3B,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,yBAAyB,EAAE,cAAc,CAAC,IAAI,CAA8C,CAAC;AAE1G,MAAM,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AA6D5D;;;;;;;;;GASG;AACH,qBAAa,aAAc,SAAQ,aAAa,CAAC,YAAY,CAAC;IAC5D,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa;IAIhD,MAAM,CAAC,UAAU,IAAI,aAAa;IAIlC,UAAU,IAAI,uBAAuB;IAIrC,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAS3C,SAAS,IAAI,eAAe;IAO5B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAM5C,cAAc,IAAI,MAAM;IAIxB,QAAQ,IAAI,KAAK;IAIjB,SAAS,IAAI,OAAO;IAIpB,QAAQ;CAGT;AAED,wBAAgB,oBAAoB,IAAI,aAAa,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,aAAa,CAE5F"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect } from 'react';
|
|
3
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
4
|
+
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
|
|
5
|
+
import { addClassNamesToElement, mergeRegister, removeClassNamesFromElement } from '@lexical/utils';
|
|
6
|
+
import { useUiStrings } from '../i18n/useStrings.js';
|
|
7
|
+
import { $applyNodeReplacement, $getSelection, $isNodeSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, createCommand, DecoratorNode, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, } from 'lexical';
|
|
8
|
+
export const INSERT_PAGE_BREAK_COMMAND = createCommand('INSERT_PAGE_BREAK_COMMAND');
|
|
9
|
+
const SELECTED_CLASS_NAME = 'likhari-page-break-selected';
|
|
10
|
+
function PageBreakComponent({ nodeKey }) {
|
|
11
|
+
const [editor] = useLexicalComposerContext();
|
|
12
|
+
const strings = useUiStrings();
|
|
13
|
+
const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey);
|
|
14
|
+
const onDelete = useCallback((event) => {
|
|
15
|
+
const selection = $getSelection();
|
|
16
|
+
if (isSelected && $isNodeSelection(selection)) {
|
|
17
|
+
event.preventDefault();
|
|
18
|
+
editor.update(() => {
|
|
19
|
+
selection.getNodes().forEach((node) => {
|
|
20
|
+
if ($isPageBreakNode(node))
|
|
21
|
+
node.remove();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}, [editor, isSelected]);
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
return mergeRegister(editor.registerCommand(CLICK_COMMAND, (event) => {
|
|
29
|
+
const element = editor.getElementByKey(nodeKey);
|
|
30
|
+
// The marker is made of child spans (the label and two lines), so a
|
|
31
|
+
// click almost never lands on the outer element itself.
|
|
32
|
+
if (!element || !element.contains(event.target))
|
|
33
|
+
return false;
|
|
34
|
+
if (!event.shiftKey)
|
|
35
|
+
clearSelection();
|
|
36
|
+
setSelected(!isSelected);
|
|
37
|
+
return true;
|
|
38
|
+
}, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_DELETE_COMMAND, onDelete, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_BACKSPACE_COMMAND, onDelete, COMMAND_PRIORITY_LOW));
|
|
39
|
+
}, [clearSelection, editor, isSelected, nodeKey, onDelete, setSelected]);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
const element = editor.getElementByKey(nodeKey);
|
|
42
|
+
if (!element)
|
|
43
|
+
return;
|
|
44
|
+
if (isSelected)
|
|
45
|
+
addClassNamesToElement(element, SELECTED_CLASS_NAME);
|
|
46
|
+
else
|
|
47
|
+
removeClassNamesFromElement(element, SELECTED_CLASS_NAME);
|
|
48
|
+
}, [editor, isSelected, nodeKey]);
|
|
49
|
+
return (_jsxs(_Fragment, { children: [_jsx("span", { className: "likhari-page-break-line", "aria-hidden": "true" }), _jsx("span", { className: "likhari-page-break-label", children: strings.editor.pageBreakLabel }), _jsx("span", { className: "likhari-page-break-line", "aria-hidden": "true" })] }));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A manual page break — a print/paginated-export concept with no native
|
|
53
|
+
* Lexical node (lexical-editor-spec.md §4.3/§4.6). Renders as a visible
|
|
54
|
+
* dashed marker while editing, and as `page-break-after: always` both live
|
|
55
|
+
* (a print stylesheet, editor.css) and in exported HTML (`exportDOM`).
|
|
56
|
+
*
|
|
57
|
+
* Mirrors @lexical/react's HorizontalRuleNode pattern: `createDOM` returns
|
|
58
|
+
* the actual visible element (the click target `PageBreakComponent` wires
|
|
59
|
+
* selection/delete against), rather than `decorate()` rendering visuals.
|
|
60
|
+
*/
|
|
61
|
+
export class PageBreakNode extends DecoratorNode {
|
|
62
|
+
static getType() {
|
|
63
|
+
return 'page-break';
|
|
64
|
+
}
|
|
65
|
+
static clone(node) {
|
|
66
|
+
return new PageBreakNode(node.__key);
|
|
67
|
+
}
|
|
68
|
+
static importJSON() {
|
|
69
|
+
return $createPageBreakNode();
|
|
70
|
+
}
|
|
71
|
+
exportJSON() {
|
|
72
|
+
return { type: 'page-break', version: 1 };
|
|
73
|
+
}
|
|
74
|
+
static importDOM() {
|
|
75
|
+
return {
|
|
76
|
+
div: (domNode) => {
|
|
77
|
+
if (!domNode.hasAttribute('data-likhari-page-break'))
|
|
78
|
+
return null;
|
|
79
|
+
return { conversion: () => ({ node: $createPageBreakNode() }), priority: 2 };
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
exportDOM() {
|
|
84
|
+
const element = document.createElement('div');
|
|
85
|
+
element.setAttribute('data-likhari-page-break', '');
|
|
86
|
+
element.style.pageBreakAfter = 'always';
|
|
87
|
+
return { element };
|
|
88
|
+
}
|
|
89
|
+
createDOM(config) {
|
|
90
|
+
const element = document.createElement('div');
|
|
91
|
+
addClassNamesToElement(element, config.theme.pageBreak ?? 'likhari-page-break');
|
|
92
|
+
return element;
|
|
93
|
+
}
|
|
94
|
+
getTextContent() {
|
|
95
|
+
return '\n';
|
|
96
|
+
}
|
|
97
|
+
isInline() {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
updateDOM() {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
decorate() {
|
|
104
|
+
return _jsx(PageBreakComponent, { nodeKey: this.__key });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function $createPageBreakNode() {
|
|
108
|
+
return $applyNodeReplacement(new PageBreakNode());
|
|
109
|
+
}
|
|
110
|
+
export function $isPageBreakNode(node) {
|
|
111
|
+
return node instanceof PageBreakNode;
|
|
112
|
+
}
|
|
@@ -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":"AAuDA,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+YvD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,2BAA2B,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,wFAAwF;IACxF,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAED,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAkC,EAAE,SAAiB,EAAE,MAAa,EAAE,MAAM,EAAE,EAAE,YAAY,+BAg7BxJ"}
|
|
@@ -11,6 +11,7 @@ import { $findMatchingParent, $insertNodeToNearestRoot } from '@lexical/utils';
|
|
|
11
11
|
import { INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/react/LexicalHorizontalRuleNode';
|
|
12
12
|
import { ImageDialog } from '../image/ImageDialog.js';
|
|
13
13
|
import { $createImageNode } from '../image/ImageNode.js';
|
|
14
|
+
import { INSERT_PAGE_BREAK_COMMAND } from '../blocks/PageBreakNode.js';
|
|
14
15
|
import { TableDialog } from './TableDialog.js';
|
|
15
16
|
import { $getTableCellNodeFromLexicalNode, $isTableSelection, INSERT_TABLE_COMMAND } from '@lexical/table';
|
|
16
17
|
import { $deleteTable, $deleteTableColumns, $deleteTableRows, $getTableSelectionSize, $insertTableColumns, $insertTableRows, } from '../table/tableActions.js';
|
|
@@ -22,7 +23,7 @@ import { CANVAS_FONT_DEFAULTS, DEFAULT_FONT_OPTIONS, FONT_SIZES_PX } from '../fo
|
|
|
22
23
|
import { setStyleProperty } from '../utils/style.js';
|
|
23
24
|
import { useStrings } from '../i18n/useStrings.js';
|
|
24
25
|
import { usePortalTarget } from '../PortalTargetContext.js';
|
|
25
|
-
import { IconAbc, IconAlignCenter, IconAlignJustified, IconAlignLeft, IconAlignRight, IconArrowBackUp, IconArrowForwardUp, IconBold, IconClearFormatting, IconDeviceFloppy, IconDots, IconHistory, IconExternalLink, IconFeather, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconIndentDecrease, IconIndentIncrease, IconItalic, IconLetterCase, IconLetterCaseLower, IconLetterCaseUpper, IconLink, IconLinkOff, IconList, IconListCheck, IconListNumbers, IconPencil, IconPhoto, IconPilcrow, IconQuote, IconSeparatorHorizontal, IconSparkles, IconStrikethrough, IconSubscript, IconSuperscript, IconColumnInsertLeft, IconColumnInsertRight, IconColumnRemove, IconRowInsertBottom, IconRowInsertTop, IconRowRemove, IconTable, IconTableMinus, IconTableOptions, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
|
|
26
|
+
import { IconAbc, IconAlignCenter, IconAlignJustified, IconAlignLeft, IconAlignRight, IconArrowBackUp, IconArrowForwardUp, IconBold, IconClearFormatting, IconDeviceFloppy, IconDots, 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, IconColumnInsertLeft, IconColumnInsertRight, IconColumnRemove, IconRowInsertBottom, IconRowInsertTop, IconRowRemove, IconTable, IconTableMinus, IconTableOptions, IconTextSize, IconTypography, IconUnderline, IconWand, } from '@tabler/icons-react';
|
|
26
27
|
/** Sentinel for "no inline style": Lexical returns the default it is given when
|
|
27
28
|
* the selection has none, so this tells "unstyled" (show the canvas default)
|
|
28
29
|
* apart from "styled with a value the dropdown doesn't list" (show nothing). */
|
|
@@ -525,7 +526,12 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
525
526
|
const showFormattingGroup = headingLevels.length > 0 || config.lists.bullet || config.lists.numbered || config.lists.check || config.blocks.quote;
|
|
526
527
|
const showInlineGroup = fmt.bold || fmt.italic || fmt.underline;
|
|
527
528
|
const showAlignGroup = config.alignment.start || config.alignment.center || config.alignment.justify || config.alignment.left || config.alignment.right;
|
|
528
|
-
const showStubInsertGroup = config.images.linked ||
|
|
529
|
+
const showStubInsertGroup = config.images.linked ||
|
|
530
|
+
config.images.embedded ||
|
|
531
|
+
config.tables ||
|
|
532
|
+
config.blocks.horizontalRule ||
|
|
533
|
+
config.blocks.pageBreak ||
|
|
534
|
+
config.poetry.enabled;
|
|
529
535
|
const showLanguageGroup = config.language.autocorrect || config.language.textCleanup || config.language.spellCheck;
|
|
530
536
|
// The "script & cleanup" and "indent/outdent" groups (UI spec §3.3) render
|
|
531
537
|
// as normal inline toolbar groups whenever there's room, and only move
|
|
@@ -695,7 +701,7 @@ export function Toolbar({ config, onSave, isDirty, showSave, fontOptions = DEFAU
|
|
|
695
701
|
restoreSelection();
|
|
696
702
|
openLinkDialog();
|
|
697
703
|
}, onRemove: removeLink, strings: strings }) })] })) : (_jsx(ToolbarButton, { icon: IconLink, title: strings.toolbar.insertLink, onClick: openLinkDialog })) }, "link")),
|
|
698
|
-
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.tables && _jsx(ToolbarButton, { icon: IconTable, title: strings.toolbar.insertTable, onClick: openTableDialog }), config.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.poetry.enabled && _jsx(StubButton, { icon: IconFeather, title: strings.toolbar.poetryBlocks, comingSoon: strings.toolbar.comingSoon })] }, "stubInsert")),
|
|
704
|
+
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.blocks.horizontalRule && (_jsx(ToolbarButton, { icon: IconSeparatorHorizontal, title: strings.toolbar.insertHorizontalRule, onClick: () => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined) })), config.poetry.enabled && _jsx(StubButton, { icon: IconFeather, title: strings.toolbar.poetryBlocks, comingSoon: strings.toolbar.comingSoon })] }, "stubInsert")),
|
|
699
705
|
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, onAction: runTableAction }) })] }) }, "tableActions")),
|
|
700
706
|
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")),
|
|
701
707
|
];
|
package/dist/i18n/strings.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface Strings {
|
|
|
13
13
|
placeholder: string;
|
|
14
14
|
/** aria-label on the contenteditable itself. */
|
|
15
15
|
contentLabel: string;
|
|
16
|
+
/** Label shown on a page-break marker's dashed line while editing. */
|
|
17
|
+
pageBreakLabel: string;
|
|
16
18
|
};
|
|
17
19
|
common: {
|
|
18
20
|
cancel: string;
|
|
@@ -42,6 +44,7 @@ export interface Strings {
|
|
|
42
44
|
tableOptions: string;
|
|
43
45
|
insertLink: string;
|
|
44
46
|
insertImage: string;
|
|
47
|
+
insertPageBreak: string;
|
|
45
48
|
insertTable: string;
|
|
46
49
|
insertHorizontalRule: string;
|
|
47
50
|
poetryBlocks: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/i18n/strings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;+DAC+D;AAC/D,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,cAAc,CAAC;AAElD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE;QACN,mGAAmG;QACnG,WAAW,EAAE,MAAM,CAAC;QACpB,gDAAgD;QAChD,YAAY,EAAE,MAAM,CAAC;
|
|
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
|
@@ -8,6 +8,7 @@ const en = {
|
|
|
8
8
|
editor: {
|
|
9
9
|
placeholder: 'Start writing…',
|
|
10
10
|
contentLabel: 'Editor content',
|
|
11
|
+
pageBreakLabel: 'Page break',
|
|
11
12
|
},
|
|
12
13
|
common: {
|
|
13
14
|
cancel: 'Cancel',
|
|
@@ -34,6 +35,7 @@ const en = {
|
|
|
34
35
|
tableOptions: 'Table options',
|
|
35
36
|
insertLink: 'Insert link (Ctrl+K)',
|
|
36
37
|
insertImage: 'Insert image',
|
|
38
|
+
insertPageBreak: 'Insert page break',
|
|
37
39
|
insertTable: 'Insert table',
|
|
38
40
|
insertHorizontalRule: 'Insert horizontal rule',
|
|
39
41
|
poetryBlocks: 'Poetry blocks',
|
|
@@ -199,6 +201,7 @@ const ur = {
|
|
|
199
201
|
editor: {
|
|
200
202
|
placeholder: 'لکھنا شروع کریں…',
|
|
201
203
|
contentLabel: 'ایڈیٹر کا مواد',
|
|
204
|
+
pageBreakLabel: 'صفحے کی تقسیم',
|
|
202
205
|
},
|
|
203
206
|
common: {
|
|
204
207
|
cancel: 'منسوخ کریں',
|
|
@@ -225,6 +228,7 @@ const ur = {
|
|
|
225
228
|
tableOptions: 'جدول کے اختیارات',
|
|
226
229
|
insertLink: 'لنک شامل کریں (Ctrl+K)',
|
|
227
230
|
insertImage: 'تصویر شامل کریں',
|
|
231
|
+
insertPageBreak: 'صفحے کی تقسیم شامل کریں',
|
|
228
232
|
insertTable: 'جدول شامل کریں',
|
|
229
233
|
insertHorizontalRule: 'افقی لکیر شامل کریں',
|
|
230
234
|
poetryBlocks: 'شاعری کے بلاکس',
|
|
@@ -390,6 +394,7 @@ const paShahmukhi = {
|
|
|
390
394
|
editor: {
|
|
391
395
|
placeholder: 'لکھنا شروع کرو…',
|
|
392
396
|
contentLabel: 'ایڈیٹر دی سامگری',
|
|
397
|
+
pageBreakLabel: 'صفحے دی ونڈ',
|
|
393
398
|
},
|
|
394
399
|
common: {
|
|
395
400
|
cancel: 'رد کرو',
|
|
@@ -416,6 +421,7 @@ const paShahmukhi = {
|
|
|
416
421
|
tableOptions: 'ٹیبل دے اختیار',
|
|
417
422
|
insertLink: 'لنک پاؤ (Ctrl+K)',
|
|
418
423
|
insertImage: 'تصویر پاؤ',
|
|
424
|
+
insertPageBreak: 'صفحے دی ونڈ پاؤ',
|
|
419
425
|
insertTable: 'ٹیبل پاؤ',
|
|
420
426
|
insertHorizontalRule: 'لیٹی لکیر پاؤ',
|
|
421
427
|
poetryBlocks: 'شاعری بلاک',
|
package/dist/nodes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../src/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../src/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AASlD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAY5C,CAAC"}
|
package/dist/nodes.js
CHANGED
|
@@ -4,6 +4,7 @@ import { LinkNode } from '@lexical/link';
|
|
|
4
4
|
import { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';
|
|
5
5
|
import { TableCellNode, TableNode, TableRowNode } from '@lexical/table';
|
|
6
6
|
import { ImageNode } from './image/ImageNode.js';
|
|
7
|
+
import { PageBreakNode } from './blocks/PageBreakNode.js';
|
|
7
8
|
/**
|
|
8
9
|
* Node types registered on the editor at construction time. Per
|
|
9
10
|
* editor-architecture-design.md §2, node registration cannot be conditional
|
|
@@ -24,4 +25,5 @@ export const EDITOR_NODES = [
|
|
|
24
25
|
TableRowNode,
|
|
25
26
|
TableCellNode,
|
|
26
27
|
ImageNode,
|
|
28
|
+
PageBreakNode,
|
|
27
29
|
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type MutableRefObject } from 'react';
|
|
2
|
+
import type { LexicalEditor } from 'lexical';
|
|
3
|
+
/** Hands the composer's editor to the component that owns the imperative ref. */
|
|
4
|
+
export declare function EditorInstancePlugin({ instanceRef }: {
|
|
5
|
+
instanceRef: MutableRefObject<LexicalEditor | null>;
|
|
6
|
+
}): null;
|
|
7
|
+
//# sourceMappingURL=EditorInstancePlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditorInstancePlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/EditorInstancePlugin.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,EAAE,WAAW,EAAE,EAAE;IAAE,WAAW,EAAE,gBAAgB,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;CAAE,GAAG,IAAI,CASnH"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
+
/** Hands the composer's editor to the component that owns the imperative ref. */
|
|
4
|
+
export function EditorInstancePlugin({ instanceRef }) {
|
|
5
|
+
const [editor] = useLexicalComposerContext();
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
instanceRef.current = editor;
|
|
8
|
+
return () => {
|
|
9
|
+
instanceRef.current = null;
|
|
10
|
+
};
|
|
11
|
+
}, [editor, instanceRef]);
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageBreakPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/PageBreakPlugin.tsx"],"names":[],"mappings":"AAMA,+FAA+F;AAC/F,wBAAgB,eAAe,SAiB9B"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
+
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR } from 'lexical';
|
|
4
|
+
import { $insertNodeToNearestRoot } from '@lexical/utils';
|
|
5
|
+
import { $createPageBreakNode, INSERT_PAGE_BREAK_COMMAND } from '../blocks/PageBreakNode.js';
|
|
6
|
+
/** Registers INSERT_PAGE_BREAK_COMMAND — mirrors @lexical/react's own HorizontalRulePlugin. */
|
|
7
|
+
export function PageBreakPlugin() {
|
|
8
|
+
const [editor] = useLexicalComposerContext();
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
return editor.registerCommand(INSERT_PAGE_BREAK_COMMAND, () => {
|
|
11
|
+
const selection = $getSelection();
|
|
12
|
+
if (!$isRangeSelection(selection))
|
|
13
|
+
return false;
|
|
14
|
+
$insertNodeToNearestRoot($createPageBreakNode());
|
|
15
|
+
return true;
|
|
16
|
+
}, COMMAND_PRIORITY_EDITOR);
|
|
17
|
+
}, [editor]);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
package/dist/theme/editor.css
CHANGED
|
@@ -259,6 +259,45 @@
|
|
|
259
259
|
margin: 1.5em 0;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
/* Page break — a print/export concept with no visual meaning while editing
|
|
263
|
+
on screen, so it gets its own clearly-labeled dashed marker rather than
|
|
264
|
+
masquerading as a horizontal rule. The actual page-break behavior only
|
|
265
|
+
takes effect when printing (lexical-editor-spec.md §4.3/§4.6). */
|
|
266
|
+
.likhari-page-break {
|
|
267
|
+
display: flex;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: 8px;
|
|
270
|
+
margin: 1.5em 0;
|
|
271
|
+
font-size: 12px;
|
|
272
|
+
cursor: default;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.likhari-page-break-line {
|
|
276
|
+
flex: 1 1 auto;
|
|
277
|
+
border-top: 1px dashed var(--editor-line);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.likhari-page-break-label {
|
|
281
|
+
color: var(--editor-ink-soft);
|
|
282
|
+
white-space: nowrap;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.likhari-page-break-selected {
|
|
286
|
+
outline: 2px solid var(--editor-accent);
|
|
287
|
+
outline-offset: 2px;
|
|
288
|
+
border-radius: 4px;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
@media print {
|
|
292
|
+
.likhari-page-break {
|
|
293
|
+
page-break-after: always;
|
|
294
|
+
/* Hide the on-screen marker itself when actually printing — the
|
|
295
|
+
browser's own pagination (triggered by page-break-after) is what
|
|
296
|
+
matters there, not the editing-time label. */
|
|
297
|
+
visibility: hidden;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
262
301
|
/* Tables — cell merge/split is deliberately out of scope for now (a flagged
|
|
263
302
|
open risk, lexical-editor-spec.md §12 item 3, needing its own scope
|
|
264
303
|
decision); TablePlugin is configured with hasCellMerge={false} to keep
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editorTheme.d.ts","sourceRoot":"","sources":["../../src/theme/editorTheme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"editorTheme.d.ts","sourceRoot":"","sources":["../../src/theme/editorTheme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,kBAoCzB,CAAC"}
|