feat: focus highlight, delete-btn visibility isolation, multi_select crash fix
- Move delete-btn to top-right of smart-field-wrapper via absolute positioning - Add template-editor-mode class to TemplateManage editor for CSS isolation - Show delete-btn only on hover/focus-within inside template-editor-mode - Add .field-value:focus highlight with background darken and blue glow - Sync defaultContent.ts smartField() HTML structure - Fix ReportEditor multi_select .map crash with Array.isArray guard
This commit is contained in:
@@ -127,24 +127,35 @@
|
||||
.smart-field-wrapper .field-value:empty::before {
|
||||
content: '\200b';
|
||||
}
|
||||
.smart-field-wrapper .field-value:focus {
|
||||
background-color: #e2e8f0;
|
||||
border-color: #94a3b8;
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.25);
|
||||
}
|
||||
.smart-field-wrapper .delete-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 2px;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
display: none;
|
||||
z-index: 10;
|
||||
}
|
||||
.smart-field-wrapper .delete-btn:hover {
|
||||
background: #dc2626;
|
||||
}
|
||||
.template-editor-mode .smart-field-wrapper:hover .delete-btn,
|
||||
.template-editor-mode .smart-field-wrapper:focus-within .delete-btn {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
@@ -1224,6 +1224,8 @@ export default function ReportEditor() {
|
||||
if (field.type === 'multi_select') {
|
||||
const isOpen = openDropdown === field.key;
|
||||
const opts = field.options || multiSelectOptions[field.key] || [];
|
||||
const rawValue = (reportData as any)[field.key];
|
||||
const tags = Array.isArray(rawValue) ? rawValue : (rawValue ? [String(rawValue)] : []);
|
||||
return (
|
||||
<div key={field.key} className="space-y-1 select-dropdown-root relative">
|
||||
<label className="block text-xs font-bold text-text-main">{field.label}</label>
|
||||
@@ -1231,7 +1233,7 @@ export default function ReportEditor() {
|
||||
className="w-full px-3 py-2 border border-border rounded-lg bg-white flex flex-wrap gap-1 items-center min-h-[42px] cursor-text"
|
||||
onClick={() => setOpenDropdown(field.key)}
|
||||
>
|
||||
{((reportData as any)[field.key] || []).map((tag: string) => (
|
||||
{tags.map((tag: string) => (
|
||||
<span key={tag} className="px-2 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-700 flex items-center gap-1">
|
||||
{tag}
|
||||
<span className="cursor-pointer hover:text-amber-900" onClick={(e) => { e.stopPropagation(); removeTag(field.key, tag); }}>×</span>
|
||||
|
||||
@@ -249,7 +249,7 @@ export default function TemplateManage() {
|
||||
alert(`字段 "${field.label}" 已存在,请勿重复插入。`);
|
||||
return;
|
||||
}
|
||||
const html = `<span class="smart-field-wrapper" contenteditable="false" style="white-space:nowrap;"><span class="delete-btn" contenteditable="false">×</span><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;position:relative;"><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;outline:none;"> </span><span class="delete-btn" contenteditable="false">×</span></span>`;
|
||||
document.execCommand('insertHTML', false, html);
|
||||
editorRef.current?.focus();
|
||||
};
|
||||
@@ -577,7 +577,7 @@ export default function TemplateManage() {
|
||||
<div
|
||||
ref={editorRef}
|
||||
contentEditable
|
||||
className="editor-content print-content"
|
||||
className="editor-content print-content template-editor-mode"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const smartField = (key: string) => `<span class="smart-field-wrapper" contenteditable="false" style="white-space:nowrap;"><span class="delete-btn" contenteditable="false">×</span><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;position:relative;"><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;outline:none;"> </span><span class="delete-btn" contenteditable="false">×</span></span>`;
|
||||
|
||||
export const defaultReportContent = `
|
||||
<!-- 医院Logo -->
|
||||
|
||||
Reference in New Issue
Block a user