Three editable NodeViews rendered a contentEditable=false "chrome" element IN FLOW BEFORE NodeViewContent. On macOS the browser's click hit-testing (posAtCoords → caretRangeFromPoint) then misses the contentDOM and snaps the caret to the previous node — the caret/selection lands a line (code block) or several lines (footnotes, into the body) above where the user clicked. Fix (the transclusion pattern / issue #146 plan): make the editable NodeViewContent the FIRST child in the DOM and move the non-editable chrome AFTER it, restoring its visual position with CSS: - code-block-view: <pre><NodeViewContent/></pre> first; the language/copy menu follows and is lifted above via flex `order` (.codeBlock is now a flex column). - footnotes-list-view: NodeViewContent first; the "Footnotes" heading follows and is lifted above via flex `order` (.list is a flex column; the separator border stays on the container). - footnote-definition-view: NodeViewContent first; the "N." marker follows with `order:-1` to stay on the left; the ↩ back-link stays on the right. Layout is visually unchanged. Verified in a real browser (Chromium): the contentDOM is now the first child of every editable NodeView wrapper (no contentEditable=false element precedes it), and the menu/heading/marker still render in their original positions. NOTE: the caret-offset itself is macOS-specific text hit-testing and does not reproduce in headless Chromium/WebKit on Linux (verified extensively), so the visible fix is best confirmed on macOS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
120 lines
2.7 KiB
CSS
120 lines
2.7 KiB
CSS
.ProseMirror {
|
|
.codeBlock {
|
|
/* #146: flex column so the menu (rendered AFTER <pre> in the DOM, so the
|
|
editable contentDOM is first) is lifted back above the code via `order`. */
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 4px;
|
|
border-radius: var(--mantine-radius-default);
|
|
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-8));
|
|
}
|
|
|
|
pre {
|
|
padding: var(--mantine-spacing-xs) var(--mantine-spacing-md);
|
|
margin: 4px;
|
|
font-family: "JetBrainsMono", var(--mantine-font-family-monospace);
|
|
border-radius: var(--mantine-radius-default);
|
|
tab-size: 4;
|
|
|
|
@mixin light {
|
|
background-color: var(--mantine-color-gray-0);
|
|
color: var(--mantine-color-gray-9);
|
|
}
|
|
|
|
@mixin dark {
|
|
background-color: var(--mantine-color-dark-8);
|
|
color: var(--mantine-color-dark-1);
|
|
}
|
|
|
|
code {
|
|
color: inherit;
|
|
padding: 0;
|
|
background: none;
|
|
font-size: var(--mantine-font-size-sm);
|
|
}
|
|
|
|
/* Code styling */
|
|
.hljs-comment,
|
|
.hljs-quote {
|
|
color: light-dark(
|
|
var(--mantine-color-gray-6),
|
|
var(--mantine-color-dark-2)
|
|
);
|
|
}
|
|
|
|
.hljs-variable,
|
|
.hljs-template-variable,
|
|
.hljs-attribute,
|
|
.hljs-tag,
|
|
.hljs-name,
|
|
.hljs-regexp,
|
|
.hljs-link,
|
|
.hljs-name,
|
|
.hljs-selector-id,
|
|
.hljs-selector-class {
|
|
color: light-dark(var(--mantine-color-red-7), var(--mantine-color-red-5));
|
|
}
|
|
|
|
.hljs-number,
|
|
.hljs-meta,
|
|
.hljs-built_in,
|
|
.hljs-builtin-name,
|
|
.hljs-literal,
|
|
.hljs-type,
|
|
.hljs-params {
|
|
color: light-dark(
|
|
var(--mantine-color-blue-7),
|
|
var(--mantine-color-cyan-5)
|
|
);
|
|
}
|
|
|
|
.hljs-string,
|
|
.hljs-symbol,
|
|
.hljs-bullet {
|
|
color: light-dark(var(--mantine-color-red-7), var(--mantine-color-red-5));
|
|
}
|
|
|
|
.hljs-title,
|
|
.hljs-section {
|
|
color: light-dark(
|
|
var(--mantine-color-pink-7),
|
|
var(--mantine-color-yellow-5)
|
|
);
|
|
}
|
|
|
|
.hljs-keyword,
|
|
.hljs-selector-tag {
|
|
color: light-dark(
|
|
var(--mantine-color-violet-7),
|
|
var(--mantine-color-violet-3)
|
|
);
|
|
}
|
|
|
|
.hljs-emphasis {
|
|
font-style: italic;
|
|
}
|
|
|
|
.hljs-strong {
|
|
font-weight: 700;
|
|
}
|
|
}
|
|
|
|
:not(pre) > code {
|
|
font-family: "JetBrainsMono", var(--mantine-font-family-monospace);
|
|
line-height: var(--mantine-line-height);
|
|
padding: 2px calc(var(--mantine-spacing-xs) / 2);
|
|
border-radius: var(--mantine-radius-sm);
|
|
margin: 0;
|
|
|
|
@mixin where-light {
|
|
background-color: var(--mantine-color-gray-1);
|
|
color: var(--mantine-color-text);
|
|
}
|
|
|
|
@mixin where-dark {
|
|
background-color: var(--mantine-color-dark-5) !important;
|
|
color: var(--mantine-color-text);
|
|
}
|
|
}
|
|
}
|