Add shared WebUI layout primitives

This commit is contained in:
2026-08-18 10:42:55 +02:00
parent dd7ad4d9c7
commit 6814a41ae4
22 changed files with 574 additions and 111 deletions
+16 -14
View File
@@ -1,3 +1,4 @@
import { FormGrid } from "./ContentGrid";
import {
mergeAttributes,
Node,
@@ -36,6 +37,7 @@ import {
type MouseEvent
} from "react";
import { usePlatformLanguage } from "../i18n/LanguageContext";
import ActionToolbar, { ToolbarGroup } from "./ActionToolbar";
import Button from "./Button";
import Dialog from "./Dialog";
import FormField from "./FormField";
@@ -478,8 +480,8 @@ const WysiwygEditor = forwardRef<WysiwygEditorHandle, WysiwygEditorProps>(functi
<div className={rootClassName} style={editorStyle} role="group" aria-label={translatedAriaLabel}>
<div className="wysiwyg-editor-header">
{mode === "visual" && (
<div className="wysiwyg-editor-toolbar" role="toolbar" aria-label={translatedLabels.editor}>
<div className="wysiwyg-toolbar-group">
<ActionToolbar className="wysiwyg-editor-toolbar" label={translatedLabels.editor}>
<ToolbarGroup className="wysiwyg-toolbar-group">
<IconButton
variant="ghost"
className="wysiwyg-toolbar-button"
@@ -498,7 +500,7 @@ const WysiwygEditor = forwardRef<WysiwygEditorHandle, WysiwygEditorProps>(functi
onMouseDown={preserveSelection}
onClick={() => editor.chain().focus().redo().run()}
/>
</div>
</ToolbarGroup>
<label className="wysiwyg-block-style">
<span className="sr-only">{translatedLabels.blockStyle}</span>
<select
@@ -513,25 +515,25 @@ const WysiwygEditor = forwardRef<WysiwygEditorHandle, WysiwygEditorProps>(functi
<option value="heading-3">{translatedLabels.heading3}</option>
</select>
</label>
<div className="wysiwyg-toolbar-group">
<ToolbarGroup className="wysiwyg-toolbar-group">
<ToolbarButton active={toolbarState.bold} disabled={disabled} label={translatedLabels.bold} icon={<Bold />} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().toggleBold().run()} />
<ToolbarButton active={toolbarState.italic} disabled={disabled} label={translatedLabels.italic} icon={<Italic />} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().toggleItalic().run()} />
<ToolbarButton active={toolbarState.underline} disabled={disabled} label={translatedLabels.underline} icon={<Underline />} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().toggleUnderline().run()} />
<ToolbarButton active={toolbarState.strike} disabled={disabled} label={translatedLabels.strike} icon={<Strikethrough />} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().toggleStrike().run()} />
<ToolbarButton active={toolbarState.code} disabled={disabled} label={translatedLabels.inlineCodeLabel} icon={<Code2 />} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().toggleCode().run()} />
</div>
<div className="wysiwyg-toolbar-group">
</ToolbarGroup>
<ToolbarGroup className="wysiwyg-toolbar-group">
<ToolbarButton active={toolbarState.bulletList} disabled={disabled} label={translatedLabels.bulletList} icon={<List />} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().toggleBulletList().run()} />
<ToolbarButton active={toolbarState.numberedList} disabled={disabled} label={translatedLabels.numberedList} icon={<ListOrdered />} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().toggleOrderedList().run()} />
<ToolbarButton active={toolbarState.quote} disabled={disabled} label={translatedLabels.quote} icon={<Quote />} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().toggleBlockquote().run()} />
</div>
<div className="wysiwyg-toolbar-group">
</ToolbarGroup>
<ToolbarGroup className="wysiwyg-toolbar-group">
<IconButton variant="ghost" className="wysiwyg-toolbar-button" label={translatedLabels.insertLink} icon={<Link2 />} disabled={disabled} onMouseDown={preserveSelection} onClick={openLinkDialog} />
<IconButton variant="ghost" className="wysiwyg-toolbar-button" label={translatedLabels.removeLink} icon={<Link2Off />} disabled={disabled || !toolbarState.link} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().unsetLink().run()} />
<IconButton variant="ghost" className="wysiwyg-toolbar-button" label={translatedLabels.insertImage} icon={<ImagePlus />} disabled={disabled} onMouseDown={preserveSelection} onClick={openImageDialog} />
<IconButton variant="ghost" className="wysiwyg-toolbar-button" label={translatedLabels.clearFormatting} icon={<RemoveFormatting />} disabled={disabled} onMouseDown={preserveSelection} onClick={() => editor.chain().focus().unsetAllMarks().clearNodes().run()} />
</div>
</div>
</ToolbarGroup>
</ActionToolbar>
)}
{allowSourceMode && (
<SegmentedControl
@@ -579,7 +581,7 @@ const WysiwygEditor = forwardRef<WysiwygEditorHandle, WysiwygEditorProps>(functi
</>
)}
>
<div className="form-grid">
<FormGrid columns={1} collapseAt="standard" className="">
{linkSelectionRef.current.from === linkSelectionRef.current.to && (
<FormField label={translatedLabels.linkText}>
<input value={linkText} onChange={(event) => setLinkText(event.target.value)} />
@@ -589,7 +591,7 @@ const WysiwygEditor = forwardRef<WysiwygEditorHandle, WysiwygEditorProps>(functi
<input value={linkUrl} inputMode="url" onChange={(event) => setLinkUrl(event.target.value)} />
</FormField>
{linkError && <p className="wysiwyg-editor-dialog-error" role="alert">{linkError}</p>}
</div>
</FormGrid>
</Dialog>
<Dialog
@@ -604,7 +606,7 @@ const WysiwygEditor = forwardRef<WysiwygEditorHandle, WysiwygEditorProps>(functi
</>
)}
>
<div className="form-grid">
<FormGrid columns={1} collapseAt="standard" className="">
<FormField label={translatedLabels.imageUrlLabel}>
<input value={imageUrl} inputMode="url" onChange={(event) => setImageUrl(event.target.value)} />
</FormField>
@@ -612,7 +614,7 @@ const WysiwygEditor = forwardRef<WysiwygEditorHandle, WysiwygEditorProps>(functi
<input value={imageAlt} onChange={(event) => setImageAlt(event.target.value)} />
</FormField>
{imageError && <p className="wysiwyg-editor-dialog-error" role="alert">{imageError}</p>}
</div>
</FormGrid>
</Dialog>
</div>
);