style: Shape Format follows the caret, and carries vertical text
The tab only showed while the box was node-selected, so it vanished the moment you clicked in to type — the floating toolbar stayed. It now reads findTextBox(), the same box that toolbar reads; an image selected inside a box still shows Picture Format alone. Vertical text was the one control the tab was missing, now a Text group of its own.
This commit is contained in:
1 parent
7b3348ca6e
commit
2436deb3bf
2 files changed
+25
-3
No files matched your search
@@ -19,6 +19,7 @@
|
||||
import { t } from '../../i18n/i18n.svelte';
|
||||
import { withShortcut } from '../../i18n/shortcut';
|
||||
import { shortcutHint } from '../../editor/shortcuts';
|
||||
import { findTextBox } from '../../editor/extensions/textBox';
|
||||
import { loadRibbonCollapsed, saveRibbonCollapsed, type ChromeMode, type ThemeMode } from '../../storage/theme';
|
||||
import type { StyleFamily } from '../../styles/styleSheet';
|
||||
import { DEFAULT_MARGINS, type PageMargins } from '../../storage/pageMargins';
|
||||
@@ -146,17 +147,23 @@
|
||||
return sel instanceof NodeSelection ? sel.node.type.name : null;
|
||||
});
|
||||
|
||||
// A text box is worked on with the caret inside it just as often as with the box
|
||||
// selected, so the tab follows the caret — the floating toolbar reads the same box.
|
||||
let textBox = $derived.by(() => (tick >= 0 && editor ? findTextBox(editor.state) : null));
|
||||
let inTextBox = $derived(!!textBox && selectedNode !== 'image');
|
||||
|
||||
let frameAttrs = $derived.by<Record<string, unknown> | null>(() => {
|
||||
if (tick < 0 || !editor) return null;
|
||||
const sel = editor.state.selection;
|
||||
return sel instanceof NodeSelection ? sel.node.attrs : null;
|
||||
if (sel instanceof NodeSelection && !inTextBox) return sel.node.attrs;
|
||||
return textBox?.node.attrs ?? null;
|
||||
});
|
||||
|
||||
let shown = $derived([
|
||||
...TABS,
|
||||
...(inTable ? (['tableDesign', 'tableLayout'] as const) : []),
|
||||
...(selectedNode === 'image' ? (['pictureFormat'] as const) : []),
|
||||
...(selectedNode === 'textBox' ? (['shapeFormat'] as const) : []),
|
||||
...(inTextBox ? (['shapeFormat'] as const) : []),
|
||||
] as Tab[]);
|
||||
|
||||
$effect(() => {
|
||||
@@ -360,6 +367,7 @@
|
||||
fillColor={frameAttrs?.fillColor as string | null}
|
||||
strokeColor={frameAttrs?.strokeColor as string | null}
|
||||
strokeWidthPt={frameAttrs?.strokeWidthPt as number}
|
||||
textVertical={frameAttrs?.textVertical === true}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
// Word's Picture Format and Shape Format: the same wrap modes, plus a shape's
|
||||
// own fill, outline and kind.
|
||||
let { editor, which, wrap, alt = '', shapeKind, fillColor, strokeColor, strokeWidthPt }: {
|
||||
let { editor, which, wrap, alt = '', shapeKind, fillColor, strokeColor, strokeWidthPt, textVertical = false }: {
|
||||
editor: Editor | null;
|
||||
which: 'picture' | 'shape';
|
||||
wrap: WrapMode;
|
||||
@@ -21,6 +21,7 @@
|
||||
fillColor?: string | null;
|
||||
strokeColor?: string | null;
|
||||
strokeWidthPt?: number;
|
||||
textVertical?: boolean;
|
||||
} = $props();
|
||||
|
||||
const WRAPS: { key: WrapMode; icon: 'wrapInline' | 'wrapLeft' | 'wrapRight' | 'wrapTopBottom'; label: () => string }[] = [
|
||||
@@ -129,6 +130,19 @@
|
||||
/>
|
||||
</label>
|
||||
</RibbonGroup>
|
||||
|
||||
<div class="ribbon-sep"></div>
|
||||
|
||||
<RibbonGroup label={t().ribbon.groups.text}>
|
||||
<RibbonButton
|
||||
variant="big"
|
||||
icon="textDirection"
|
||||
label={t().textBox.verticalText}
|
||||
title={t().textBox.verticalText}
|
||||
active={textVertical}
|
||||
onclick={() => editor?.chain().focus().setTextBoxAttrs({ textVertical: !textVertical }).run()}
|
||||
/>
|
||||
</RibbonGroup>
|
||||
{/if}
|
||||
|
||||
<CaptionDialog bind:open={captionOpen} {editor} />
|
||||
|
||||
Reference in new issue
Block a user