fix: smart field spacing/line-break in TemplateManage and default template
- Compress insertSmartField HTML to single-line, remove trailing - Compress smartField helper in defaultContent.ts to single-line - Add white-space: nowrap to .smart-field-wrapper (CSS + inline) - Add keydown interceptor in TemplateManage to prevent Backspace/Delete from removing whole <p> when adjacent to smart-field-wrapper - Update experience record (#14)
This commit is contained in:
@@ -102,6 +102,7 @@
|
||||
align-items: center;
|
||||
margin: 0 2px;
|
||||
vertical-align: text-bottom;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.smart-field-wrapper .field-label {
|
||||
color: #64748b;
|
||||
|
||||
@@ -162,6 +162,53 @@ export default function TemplateManage() {
|
||||
};
|
||||
}, [currentTemplateId, currentUser]);
|
||||
|
||||
// Intercept Backspace/Delete next to smart fields to avoid whole-line deletion
|
||||
useEffect(() => {
|
||||
const editor = editorRef.current;
|
||||
if (!editor) return;
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key !== 'Backspace' && e.key !== 'Delete') return;
|
||||
const sel = window.getSelection();
|
||||
if (!sel || !sel.isCollapsed || sel.rangeCount === 0) return;
|
||||
const range = sel.getRangeAt(0);
|
||||
const node = range.startContainer;
|
||||
if (node.nodeType !== Node.TEXT_NODE) return;
|
||||
const offset = range.startOffset;
|
||||
|
||||
if (e.key === 'Backspace' && offset === 0) {
|
||||
const prev = node.previousSibling;
|
||||
if (prev && prev.nodeType === Node.ELEMENT_NODE && (prev as Element).classList?.contains('smart-field-wrapper')) {
|
||||
e.preventDefault();
|
||||
prev.remove();
|
||||
const allTemplates = storage.get<Template[]>('templates', []);
|
||||
const updated = allTemplates.map(t =>
|
||||
t.id === currentTemplateId ? { ...t, content: editorRef.current!.innerHTML, updatedAt: new Date().toISOString() } : t
|
||||
);
|
||||
setTemplates(prevTemplates => prevTemplates.map(t => updated.find(u => u.id === t.id) || t));
|
||||
storage.set('templates', updated);
|
||||
}
|
||||
} else if (e.key === 'Delete' && offset === (node.textContent?.length || 0)) {
|
||||
const next = node.nextSibling;
|
||||
if (next && next.nodeType === Node.ELEMENT_NODE && (next as Element).classList?.contains('smart-field-wrapper')) {
|
||||
e.preventDefault();
|
||||
next.remove();
|
||||
const allTemplates = storage.get<Template[]>('templates', []);
|
||||
const updated = allTemplates.map(t =>
|
||||
t.id === currentTemplateId ? { ...t, content: editorRef.current!.innerHTML, updatedAt: new Date().toISOString() } : t
|
||||
);
|
||||
setTemplates(prevTemplates => prevTemplates.map(t => updated.find(u => u.id === t.id) || t));
|
||||
storage.set('templates', updated);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
editor.addEventListener('keydown', handleKeyDown, true);
|
||||
return () => {
|
||||
editor.removeEventListener('keydown', handleKeyDown, true);
|
||||
};
|
||||
}, [currentTemplateId]);
|
||||
|
||||
const execCmd = (command: string, value: string | undefined = undefined) => {
|
||||
editorRef.current?.focus();
|
||||
document.execCommand(command, false, value);
|
||||
@@ -170,15 +217,7 @@ export default function TemplateManage() {
|
||||
|
||||
const insertSmartField = (field: FormField) => {
|
||||
editorRef.current?.focus();
|
||||
const html = `
|
||||
<span class="smart-field-wrapper" contenteditable="false">
|
||||
<span class="field-value"
|
||||
data-bind="${field.key}"
|
||||
contenteditable="true"
|
||||
style="min-width: 32px; padding: 0 4px; margin: 0 2px; border: 1px solid #cbd5e1; border-radius: 2px; display: inline-block; background: #f8fafc; color: #0f172a; line-height: 1.2; font-size: inherit; vertical-align: text-bottom; box-sizing: border-box; min-height: 1.2em;">
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
const html = `<span class="smart-field-wrapper" contenteditable="false" style="white-space:nowrap;"><span class="field-value" data-bind="${field.key}" contenteditable="true" style="min-width:32px;padding:0 4px;margin:0 2px;border:1px solid #cbd5e1;border-radius:2px;display:inline-block;background:#f8fafc;color:#0f172a;line-height:1.2;font-size:inherit;vertical-align:text-bottom;box-sizing:border-box;min-height:1.2em;"> </span></span>`;
|
||||
document.execCommand('insertHTML', false, html);
|
||||
editorRef.current?.focus();
|
||||
};
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
const smartField = (key: string) => `
|
||||
<span class="smart-field-wrapper" contenteditable="false">
|
||||
<span class="field-value"
|
||||
data-bind="${key}"
|
||||
contenteditable="true"
|
||||
style="min-width: 32px; padding: 0 4px; margin: 0 2px; border: 1px solid #cbd5e1; border-radius: 2px; display: inline-block; background: #f8fafc; color: #0f172a; line-height: 1.2; font-size: inherit; vertical-align: text-bottom; box-sizing: border-box; min-height: 1.2em;">
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
const smartField = (key: string) => `<span class="smart-field-wrapper" contenteditable="false" style="white-space:nowrap;"><span class="field-value" data-bind="${key}" contenteditable="true" style="min-width:32px;padding:0 4px;margin:0 2px;border:1px solid #cbd5e1;border-radius:2px;display:inline-block;background:#f8fafc;color:#0f172a;line-height:1.2;font-size:inherit;vertical-align:text-bottom;box-sizing:border-box;min-height:1.2em;"> </span></span>`;
|
||||
|
||||
export const defaultReportContent = `
|
||||
<!-- 医院Logo -->
|
||||
|
||||
Reference in New Issue
Block a user