Просмотр исходного кода

feat: update off-screen indicator styles for improved layout and visibility

Yuki Takei 1 неделя назад
Родитель
Сommit
caa2d6f695

+ 35 - 6
packages/editor/src/client/services-internal/extensions/y-rich-cursors/theme.ts

@@ -82,15 +82,20 @@ export const richCursorsTheme = EditorView.baseTheme({
   },
 
   // --- Off-screen containers ---
-  // Height = avatar + compact arrow with no extra padding.
+  // height: 0 so the containers themselves take no layout space.
+  // Indicators use position:absolute and overflow beyond the 0-height boundary
+  // (default overflow:visible), anchored to the edge via top/bottom on the indicator.
   '.cm-offScreenTop, .cm-offScreenBottom': {
     position: 'absolute',
     left: '0',
     right: '0',
-    height: `calc(${AVATAR_SIZE} + 14px)`,
+    height: '0',
     pointerEvents: 'none',
     zIndex: '10',
   },
+  // top/bottom: 0 keeps the container at the editor's inner border edge.
+  // Indicators have z-index:10 and are children of .cm-editor, so they paint
+  // in front of .cm-editor's own border — no clipping from parent overflow:hidden.
   '.cm-offScreenTop': {
     top: '0',
   },
@@ -100,9 +105,7 @@ export const richCursorsTheme = EditorView.baseTheme({
 
   // Off-screen indicator — absolutely positioned; left/transform set by plugin
   // via requestMeasure to reflect the remote cursor's column position.
-  // Opacity is intentionally NOT set here — it lives on the avatar/initials only
-  // so the arrow always renders fully opaque (CSS opacity cannot be "cancelled"
-  // on children; mixing opaque arrow + faded avatar requires separate rules).
+  // Default anchor: top:0 (used by topContainer — arrow touches the top edge).
   '.cm-offScreenIndicator': {
     position: 'absolute',
     top: '0',
@@ -110,15 +113,41 @@ export const richCursorsTheme = EditorView.baseTheme({
     flexDirection: 'column',
     alignItems: 'center',
   },
+  // In the bottom container the indicator hangs upward from the bottom edge,
+  // so the arrow (last child) sits right at/overlapping the editor's bottom border.
+  '.cm-offScreenBottom .cm-offScreenIndicator': {
+    top: 'auto',
+    bottom: '0',
+  },
 
   // Arrow — always fully opaque; cursor color applied via inline style in JS.
+  //
+  // Material Symbols icons have ~20% internal whitespace on each side of the
+  // bounding box. clip-path trims both top and bottom simultaneously so the
+  // visible triangle is flush with both the avatar AND the editor edge.
+  // Negative margins compensate the clip so the flex layout stays correct.
   '.cm-offScreenArrow': {
     fontFamily: 'var(--grw-font-family-material-symbols-outlined)',
-    fontSize: '14px',
+    fontSize: '20px',
     lineHeight: '1',
+    display: 'block',
     userSelect: 'none',
     opacity: '1',
   },
+  // "above" indicator: arrow (first child) → avatar (second child)
+  //   top clip  = trim the whitespace at the editor edge
+  //   bottom clip = trim the gap between arrow and avatar
+  '.cm-offScreenArrow:first-child': {
+    marginTop: '-8px',
+    marginBottom: '-8px',
+  },
+  // "below" indicator: avatar (first child) → arrow (last child)
+  //   top clip  = trim the gap between avatar and arrow
+  //   bottom clip = trim the whitespace at the editor edge
+  '.cm-offScreenArrow:last-child': {
+    marginTop: '-8px',
+    marginBottom: '-8px',
+  },
 
   // Avatar and initials fade when idle; full opacity when active.
   '.cm-offScreenAvatar': {