@inshapardaz/likhari-react 0.1.33 → 0.1.35
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LayoutNode.d.ts","sourceRoot":"","sources":["../../src/blocks/LayoutNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,qBAAqB,EAC1B,KAAK,MAAM,EAEX,WAAW,EACZ,MAAM,SAAS,CAAC;AAGjB;;2EAE2E;AAC3E,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAAC;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAA0C,CAAC;AAErH,MAAM,MAAM,6BAA6B,GAAG,MAAM,CAAC;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,EAAE,qBAAqB,CAAC,CAAC;AACvG,MAAM,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AAE7D;;sEAEsE;AACtE,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,iBAAiB,EAAE,MAAM,CAAC;gBAEd,eAAe,SAAmB,EAAE,GAAG,CAAC,EAAE,OAAO;IAK7D,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,mBAAmB,GAAG,mBAAmB;IAI5D,kBAAkB,IAAI,MAAM;IAI5B,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI;IAMjD,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,6BAA6B,GAAG,mBAAmB;IAIrF,UAAU,IAAI,6BAA6B;IAI3C,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAU3C,SAAS,IAAI,eAAe;IAQ5B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;
|
|
1
|
+
{"version":3,"file":"LayoutNode.d.ts","sourceRoot":"","sources":["../../src/blocks/LayoutNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,qBAAqB,EAC1B,KAAK,MAAM,EAEX,WAAW,EACZ,MAAM,SAAS,CAAC;AAGjB;;2EAE2E;AAC3E,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAAC;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAA0C,CAAC;AAErH,MAAM,MAAM,6BAA6B,GAAG,MAAM,CAAC;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,EAAE,qBAAqB,CAAC,CAAC;AACvG,MAAM,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AAE7D;;sEAEsE;AACtE,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,iBAAiB,EAAE,MAAM,CAAC;gBAEd,eAAe,SAAmB,EAAE,GAAG,CAAC,EAAE,OAAO;IAK7D,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,mBAAmB,GAAG,mBAAmB;IAI5D,kBAAkB,IAAI,MAAM;IAI5B,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI;IAMjD,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,6BAA6B,GAAG,mBAAmB;IAIrF,UAAU,IAAI,6BAA6B;IAI3C,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAU3C,SAAS,IAAI,eAAe;IAQ5B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAW5C,SAAS,CAAC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO;IAQnE,UAAU,IAAI,KAAK;IAInB,YAAY,IAAI,OAAO;CAGxB;AAED,wBAAgB,0BAA0B,CAAC,eAAe,SAAmB,GAAG,mBAAmB,CAElG;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,mBAAmB,CAExG;AAED;;oDAEoD;AACpD,qBAAa,cAAe,SAAQ,WAAW;IAC7C,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,cAAc,GAAG,cAAc;IAIlD,MAAM,CAAC,UAAU,IAAI,cAAc;IAInC,UAAU,IAAI,wBAAwB;IAItC,MAAM,CAAC,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAS3C,SAAS,IAAI,eAAe;IAM5B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAM5C,SAAS,IAAI,OAAO;IAIpB,UAAU,IAAI,KAAK;IAInB,SAAS,IAAI,KAAK;CAGnB;AAED,wBAAgB,qBAAqB,IAAI,cAAc,CAEtD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,cAAc,CAE9F;AAED;;mCAEmC;AACnC,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,CAOjF"}
|
|
@@ -53,12 +53,17 @@ export class LayoutContainerNode extends ElementNode {
|
|
|
53
53
|
const element = document.createElement('div');
|
|
54
54
|
addClassNamesToElement(element, config.theme.layoutContainer ?? 'likhari-layout-container');
|
|
55
55
|
element.style.gridTemplateColumns = this.__templateColumns;
|
|
56
|
+
// Lets a single-item row (a centered poetry couplet — poetryActions.ts's
|
|
57
|
+
// $setCoupletCentered) be styled from CSS alone, without a :has() selector
|
|
58
|
+
// (issue #25: :has() needs Firefox 121+).
|
|
59
|
+
element.toggleAttribute('data-likhari-single-column', this.getChildrenSize() === 1);
|
|
56
60
|
return element;
|
|
57
61
|
}
|
|
58
62
|
updateDOM(prevNode, dom) {
|
|
59
63
|
if (prevNode.__templateColumns !== this.__templateColumns) {
|
|
60
64
|
dom.style.gridTemplateColumns = this.__templateColumns;
|
|
61
65
|
}
|
|
66
|
+
dom.toggleAttribute('data-likhari-single-column', this.getChildrenSize() === 1);
|
|
62
67
|
return false;
|
|
63
68
|
}
|
|
64
69
|
canBeEmpty() {
|
|
@@ -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;AAgDtF,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAA6D,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAItG,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,iBAAiB,CAAC;
|
|
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;AAgDtF,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAA6D,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAItG,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,iBAAiB,CAAC;AA6iBvD,0FAA0F;AAC1F,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,2BAA2B,CAAC;IACpC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gCAAgC;IAChC,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,aAAa,EAAE,CAAC;IACnC,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;IACnE,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,wFAAwF;IACxF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,iGAAiG;IACjG,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,wFAAwF;IACxF,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAED,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,gBAAqB,EAAE,eAAoB,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAgB,EAAE,YAAY,EAAE,SAAiB,EAAE,aAAa,EAAE,eAAuB,EAAE,mBAAmB,EAAE,WAAkC,EAAE,SAAiB,EAAE,MAAa,EAAE,MAAM,EAAE,EAAE,YAAY,+BA+rCrV"}
|
|
@@ -65,6 +65,27 @@ const INITIAL_STATE = {
|
|
|
65
65
|
};
|
|
66
66
|
const ICON_SIZE = 17;
|
|
67
67
|
const ICON_STROKE = 1.75;
|
|
68
|
+
/** The CSS Custom Highlight name; editor.css paints it like a native text selection. */
|
|
69
|
+
const SELECTION_HIGHLIGHT = 'likhari-toolbar-selection';
|
|
70
|
+
/** Paints the current native selection through the CSS Custom Highlight API, so it
|
|
71
|
+
* stays visible once a toolbar control (a Select, a Menu, a dialog) takes focus —
|
|
72
|
+
* which, unlike a ToolbarButton's onMouseDown/preventDefault, it must be able to do.
|
|
73
|
+
* The browser clears `window.getSelection()` on blur; this is called at the one
|
|
74
|
+
* moment before that happens (mousedown, or opening a menu/dialog), alongside the
|
|
75
|
+
* Lexical-level selection snapshot these controls already restore from. */
|
|
76
|
+
function paintSelectionHighlight() {
|
|
77
|
+
if (typeof CSS === 'undefined' || !('highlights' in CSS))
|
|
78
|
+
return;
|
|
79
|
+
const domSelection = window.getSelection();
|
|
80
|
+
if (!domSelection || domSelection.isCollapsed || domSelection.rangeCount === 0) {
|
|
81
|
+
CSS.highlights.delete(SELECTION_HIGHLIGHT);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const ranges = [];
|
|
85
|
+
for (let i = 0; i < domSelection.rangeCount; i++)
|
|
86
|
+
ranges.push(domSelection.getRangeAt(i).cloneRange());
|
|
87
|
+
CSS.highlights.set(SELECTION_HIGHLIGHT, new Highlight(...ranges));
|
|
88
|
+
}
|
|
68
89
|
const ALIGN_ICONS_LTR = {
|
|
69
90
|
start: IconAlignLeft,
|
|
70
91
|
left: IconAlignLeft,
|
|
@@ -135,10 +156,17 @@ function setsEqual(a, b) {
|
|
|
135
156
|
/** Mantine Select (combobox) for the toolbar's dropdown controls. The icon
|
|
136
157
|
* labels the control itself, since a dropdown can't show one per option in
|
|
137
158
|
* its closed state. The dropdown portals to <body>, so it is not clipped by
|
|
138
|
-
* the editor's `overflow: hidden` frame.
|
|
139
|
-
|
|
159
|
+
* the editor's `overflow: hidden` frame.
|
|
160
|
+
*
|
|
161
|
+
* Unlike a ToolbarButton, this can't keep focus on the canvas with
|
|
162
|
+
* onMouseDown/preventDefault — a combobox needs focus to open. So picking an
|
|
163
|
+
* option blurs the canvas first, which clears Lexical's selection; `onMouseDown`
|
|
164
|
+
* is the caller's chance to snapshot it (the browser moves focus only after
|
|
165
|
+
* mousedown's listeners run), to restore before applying the change
|
|
166
|
+
* (see Toolbar's `withRefocus`). */
|
|
167
|
+
function ToolbarSelect({ icon: Icon, label, value, data, width, disabled, placeholder, searchable, renderOption, onChange, onMouseDown, comingSoon, noMatchMessage }) {
|
|
140
168
|
const portalTarget = usePortalTarget();
|
|
141
|
-
return (_jsx(Select, { size: "xs", w: width, "aria-label": label, title: disabled && comingSoon ? comingSoon(label) : label, data: data, value: value, placeholder: placeholder, disabled: disabled, searchable: searchable, renderOption: renderOption, nothingFoundMessage: searchable ? noMatchMessage : undefined, allowDeselect: false, leftSection: _jsx(Icon, { size: 15, stroke: ICON_STROKE }), comboboxProps: { withinPortal: true, position: 'bottom-start', middlewares: { flip: true, shift: true }, portalProps: { target: portalTarget } }, classNames: { input: 'likhari-toolbar-select-input', dropdown: 'likhari-toolbar-select-dropdown' }, onChange: (v) => v && onChange?.(v) }));
|
|
169
|
+
return (_jsx(Select, { size: "xs", w: width, "aria-label": label, title: disabled && comingSoon ? comingSoon(label) : label, data: data, value: value, placeholder: placeholder, disabled: disabled, searchable: searchable, onMouseDown: onMouseDown, renderOption: renderOption, nothingFoundMessage: searchable ? noMatchMessage : undefined, allowDeselect: false, leftSection: _jsx(Icon, { size: 15, stroke: ICON_STROKE }), comboboxProps: { withinPortal: true, position: 'bottom-start', middlewares: { flip: true, shift: true }, portalProps: { target: portalTarget } }, classNames: { input: 'likhari-toolbar-select-input', dropdown: 'likhari-toolbar-select-dropdown' }, onChange: (v) => v && onChange?.(v) }));
|
|
142
170
|
}
|
|
143
171
|
/** An item in the "..." menu. A mousedown here would blur the canvas, so it is kept. */
|
|
144
172
|
function MoreMenuItem({ icon: Icon, label, active, onClick, }) {
|
|
@@ -345,9 +373,24 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
345
373
|
const selection = $getSelection();
|
|
346
374
|
menuSelectionRef.current = selection ? selection.clone() : null;
|
|
347
375
|
});
|
|
376
|
+
paintSelectionHighlight();
|
|
348
377
|
};
|
|
349
378
|
const snapshotSelectionRef = useRef(snapshotSelection);
|
|
350
379
|
snapshotSelectionRef.current = snapshotSelection;
|
|
380
|
+
// Clears the stand-in highlight once the canvas has a real selection to show again.
|
|
381
|
+
useEffect(() => {
|
|
382
|
+
if (typeof CSS === 'undefined' || !('highlights' in CSS))
|
|
383
|
+
return;
|
|
384
|
+
const clear = () => CSS.highlights.delete(SELECTION_HIGHLIGHT);
|
|
385
|
+
const unregister = editor.registerRootListener((root, previous) => {
|
|
386
|
+
previous?.removeEventListener('focus', clear);
|
|
387
|
+
root?.addEventListener('focus', clear);
|
|
388
|
+
});
|
|
389
|
+
return () => {
|
|
390
|
+
unregister();
|
|
391
|
+
clear();
|
|
392
|
+
};
|
|
393
|
+
}, [editor]);
|
|
351
394
|
const runMenuItem = (action) => () => {
|
|
352
395
|
const saved = menuSelectionRef.current;
|
|
353
396
|
if (saved)
|
|
@@ -610,7 +653,12 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
610
653
|
return true;
|
|
611
654
|
}, COMMAND_PRIORITY_NORMAL);
|
|
612
655
|
}, [editor, config.links, openLinkDialog]);
|
|
656
|
+
// The Select has already blurred the canvas by the time this runs (see
|
|
657
|
+
// ToolbarSelect's doc comment), so the selection snapshotted on its
|
|
658
|
+
// mousedown is restored first, then the canvas regains focus afterward —
|
|
659
|
+
// the combobox otherwise keeps it, so typing after picking would go nowhere.
|
|
613
660
|
const withRefocus = (fn) => (value) => {
|
|
661
|
+
restoreSelection();
|
|
614
662
|
fn(value);
|
|
615
663
|
editor.focus();
|
|
616
664
|
};
|
|
@@ -753,9 +801,9 @@ export function Toolbar({ config, toolbarStyle, dictionaryStores = [], thesaurus
|
|
|
753
801
|
];
|
|
754
802
|
const formattingValue = state.listType ?? state.blockType;
|
|
755
803
|
const AlignIcon = ALIGN_ICONS[state.elementFormat] ?? IconAlignLeft;
|
|
756
|
-
const formatSection = (showFormattingGroup || fmt.bold || fmt.italic || fmt.underline || fmt.strikethrough || moreItems.length > 0) && (_jsxs(Fragment, { children: [showFormattingGroup && (_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), onChange: withRefocus((v) => applyFormatting(v)) }) })), (fmt.bold || fmt.italic || fmt.underline || fmt.strikethrough || moreItems.length > 0) && (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [fmt.bold && _jsx(ToolbarButton, { icon: IconBold, title: strings.toolbar.bold, active: state.activeFormats.has('bold'), onClick: () => formatText('bold') }), fmt.italic && (_jsx(ToolbarButton, { icon: IconItalic, title: strings.toolbar.italic, active: state.activeFormats.has('italic'), onClick: () => formatText('italic') })), fmt.underline && (_jsx(ToolbarButton, { icon: IconUnderline, title: strings.toolbar.underline, active: state.activeFormats.has('underline'), onClick: () => formatText('underline') })), fmt.strikethrough && (_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"));
|
|
757
|
-
const alignSection = (showAlignGroup || indentItems.length > 0) && (_jsxs(Fragment, { children: [showAlignGroup && (_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), 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"));
|
|
758
|
-
const fontSection = (config.font.family || config.font.size) && (_jsxs(MantineToolbar.Group, { children: [config.font.family && (_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 }), onChange: withRefocus((v) => applyFont('font-family', v)) })), config.font.size && (_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) })), onChange: withRefocus((v) => applyFont('font-size', v)) }))] }, "font"));
|
|
804
|
+
const formatSection = (showFormattingGroup || fmt.bold || fmt.italic || fmt.underline || fmt.strikethrough || moreItems.length > 0) && (_jsxs(Fragment, { children: [showFormattingGroup && (_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)) }) })), (fmt.bold || fmt.italic || fmt.underline || fmt.strikethrough || moreItems.length > 0) && (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [fmt.bold && _jsx(ToolbarButton, { icon: IconBold, title: strings.toolbar.bold, active: state.activeFormats.has('bold'), onClick: () => formatText('bold') }), fmt.italic && (_jsx(ToolbarButton, { icon: IconItalic, title: strings.toolbar.italic, active: state.activeFormats.has('italic'), onClick: () => formatText('italic') })), fmt.underline && (_jsx(ToolbarButton, { icon: IconUnderline, title: strings.toolbar.underline, active: state.activeFormats.has('underline'), onClick: () => formatText('underline') })), fmt.strikethrough && (_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"));
|
|
805
|
+
const alignSection = (showAlignGroup || indentItems.length > 0) && (_jsxs(Fragment, { children: [showAlignGroup && (_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"));
|
|
806
|
+
const fontSection = (config.font.family || config.font.size) && (_jsxs(MantineToolbar.Group, { children: [config.font.family && (_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: withRefocus((v) => applyFont('font-family', v)) })), config.font.size && (_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"));
|
|
759
807
|
const insertSection = showInsertGroup && (_jsxs(MantineToolbar.Group, { className: "likhari-toolbar-cluster", children: [config.links &&
|
|
760
808
|
(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: () => {
|
|
761
809
|
restoreSelection();
|
package/dist/theme/editor.css
CHANGED
|
@@ -457,8 +457,10 @@
|
|
|
457
457
|
|
|
458
458
|
/* A centered couplet: a two-column row holding one item (see poetryActions.ts's
|
|
459
459
|
$setCoupletCentered) — narrowed to the middle of the block, with no column
|
|
460
|
-
divider or gutter since there's only one column.
|
|
461
|
-
.
|
|
460
|
+
divider or gutter since there's only one column. The row carries this
|
|
461
|
+
itself (LayoutNode.tsx), rather than :has(), which needs Firefox 121+
|
|
462
|
+
(issue #25). */
|
|
463
|
+
.likhari-poetry--two-column > .likhari-layout-container[data-likhari-single-column] {
|
|
462
464
|
width: 60%;
|
|
463
465
|
margin-inline: auto;
|
|
464
466
|
}
|
|
@@ -934,6 +936,13 @@
|
|
|
934
936
|
text-decoration-skip-ink: none;
|
|
935
937
|
}
|
|
936
938
|
|
|
939
|
+
/* Stands in for the native text selection while a toolbar control (which must
|
|
940
|
+
take focus, e.g. a Select) has it — otherwise the browser clears it the
|
|
941
|
+
moment focus leaves the canvas, making a selection look lost mid-edit. */
|
|
942
|
+
::highlight(likhari-toolbar-selection) {
|
|
943
|
+
background-color: var(--editor-accent-soft);
|
|
944
|
+
}
|
|
945
|
+
|
|
937
946
|
.likhari-spell-nav {
|
|
938
947
|
display: flex;
|
|
939
948
|
align-items: center;
|