feat: F4.8b the documentation mode in the editor
Java's third mode button, the sidebar's text and structure field (dropped with its middle under the pointer), items over the network that are moved, resized by Java's rule, typed into on their Y.Text, coloured and set in size and style from Java's menu, deleted; Java's paint per mode, measured in F4.8a. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
// The field a focused text is typed into (Java's JDocuTextArea): over the
|
||||
// text, at its size, in its font and colour, scaled with the view. It
|
||||
// follows the document's Y.Text — what others type comes in, the caret kept —
|
||||
// and writes what is typed with this editor's origin. Escape ends the focus;
|
||||
// Ctrl+Delete removes the text, as in Java (Delete alone types).
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
import type * as Y from 'yjs';
|
||||
import { replaceText, type DocumentationView } from '@mdg-filius/doc';
|
||||
import type { ScreenFrame } from '../canvas/Canvas.js';
|
||||
import { fontFamily, textColor } from '../canvas/documentationPaint.js';
|
||||
import { followText } from '../desktop/textBinding.js';
|
||||
import { useTranslate } from '../i18n/i18n.js';
|
||||
|
||||
export interface DocumentationTextProps {
|
||||
readonly item: DocumentationView;
|
||||
readonly frame: ScreenFrame;
|
||||
readonly text: Y.Text;
|
||||
readonly origin: object;
|
||||
readonly onDone: () => void;
|
||||
readonly onRemove: () => void;
|
||||
}
|
||||
|
||||
export function DocumentationText({ item, frame, text, origin, onDone, onRemove }: DocumentationTextProps) {
|
||||
const t = useTranslate();
|
||||
const area = useRef<HTMLTextAreaElement>(null);
|
||||
useEffect(() => {
|
||||
const element = area.current;
|
||||
if (element === null) return undefined;
|
||||
const stop = followText(element, text, origin);
|
||||
// Java gives a text the focus when it gets it (a new one at once).
|
||||
element.focus();
|
||||
return stop;
|
||||
}, [text, origin]);
|
||||
return (
|
||||
<textarea
|
||||
ref={area}
|
||||
aria-label={t('docu.text')}
|
||||
data-doc-text={item.id}
|
||||
spellCheck={false}
|
||||
onInput={(event) => {
|
||||
const next = event.currentTarget.value;
|
||||
text.doc?.transact(() => replaceText(text, next), origin);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
onDone();
|
||||
} else if (event.key === 'Delete' && (event.ctrlKey || event.metaKey)) {
|
||||
event.preventDefault();
|
||||
onRemove();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: frame.left,
|
||||
top: frame.top,
|
||||
width: item.width,
|
||||
height: item.height,
|
||||
transform: `scale(${frame.scale})`,
|
||||
transformOrigin: 'top left',
|
||||
boxSizing: 'border-box',
|
||||
margin: 0,
|
||||
padding: 1,
|
||||
border: 'none',
|
||||
outline: 'none',
|
||||
resize: 'none',
|
||||
overflow: 'hidden',
|
||||
background: 'transparent',
|
||||
color: textColor(item.color),
|
||||
font: `${item.italic ? 'italic ' : ''}${item.bold ? 'bold ' : ''}${item.size}px ${fontFamily(item.font)}`,
|
||||
lineHeight: 'normal',
|
||||
whiteSpace: 'pre-wrap',
|
||||
overflowWrap: 'break-word',
|
||||
zIndex: 3,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user