-
Notifications
You must be signed in to change notification settings - Fork 12
Clip markdown editor toolbar corners to the rounded outline #5765
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0be9701
c7ce9a8
8a88e2f
e973eda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -527,15 +527,54 @@ export default class CodeMirrorEditor extends GlimmerComponent<CodeMirrorEditorS | |||||||||||||||||||||||||||||||
| // ── Markdown embed chooser (toolbar) ──────────────────────────────────── | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| @tracked _embedPopoverOpen = false; | ||||||||||||||||||||||||||||||||
| // Inline style pinning the popover under its trigger. The popover is | ||||||||||||||||||||||||||||||||
| // `position: fixed` (see below) so it escapes the `.codemirror-body` corner | ||||||||||||||||||||||||||||||||
| // clip, which means it needs explicit viewport coordinates rather than the | ||||||||||||||||||||||||||||||||
| // `top: 100%` an in-flow absolute box would get for free. | ||||||||||||||||||||||||||||||||
| @tracked _embedPopoverStyle = ''; | ||||||||||||||||||||||||||||||||
| _embedTriggerEl: HTMLElement | null = null; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| get _currentBfmRef(): BfmRefRange | undefined { | ||||||||||||||||||||||||||||||||
| return this._selectionInfo?.currentRef; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| _toggleEmbedPopover = () => { | ||||||||||||||||||||||||||||||||
| this._embedPopoverOpen = !this._embedPopoverOpen; | ||||||||||||||||||||||||||||||||
| // Pin the popover directly under the trigger, in viewport coordinates. The | ||||||||||||||||||||||||||||||||
| // trigger is inside a sticky toolbar, so this is recomputed on scroll/resize | ||||||||||||||||||||||||||||||||
| // (see `_trackEmbedPopover`) to keep the two glued together. | ||||||||||||||||||||||||||||||||
| _positionEmbedPopover = () => { | ||||||||||||||||||||||||||||||||
| let trigger = this._embedTriggerEl; | ||||||||||||||||||||||||||||||||
| if (!trigger) return; | ||||||||||||||||||||||||||||||||
| let r = trigger.getBoundingClientRect(); | ||||||||||||||||||||||||||||||||
| this._embedPopoverStyle = `position: fixed; top: ${r.bottom + 4}px; left: ${r.left}px;`; | ||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| _toggleEmbedPopover = (e: Event) => { | ||||||||||||||||||||||||||||||||
| if (this._embedPopoverOpen) { | ||||||||||||||||||||||||||||||||
| this._embedPopoverOpen = false; | ||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| this._embedTriggerEl = e.currentTarget as HTMLElement; | ||||||||||||||||||||||||||||||||
| this._positionEmbedPopover(); | ||||||||||||||||||||||||||||||||
| this._embedPopoverOpen = true; | ||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // While the popover is open, keep it pinned under the trigger as the outer | ||||||||||||||||||||||||||||||||
| // panel scrolls or the window resizes. Installed on the popover element, so | ||||||||||||||||||||||||||||||||
| // its lifecycle tracks the popover's presence in the DOM. | ||||||||||||||||||||||||||||||||
| _trackEmbedPopover = modifier(() => { | ||||||||||||||||||||||||||||||||
| this._positionEmbedPopover(); | ||||||||||||||||||||||||||||||||
| let reposition = () => this._positionEmbedPopover(); | ||||||||||||||||||||||||||||||||
| window.addEventListener('scroll', reposition, { | ||||||||||||||||||||||||||||||||
| capture: true, | ||||||||||||||||||||||||||||||||
| passive: true, | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
| window.addEventListener('resize', reposition); | ||||||||||||||||||||||||||||||||
| return () => { | ||||||||||||||||||||||||||||||||
| window.removeEventListener('scroll', reposition, { capture: true }); | ||||||||||||||||||||||||||||||||
| window.removeEventListener('resize', reposition); | ||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| _openEmbedChooser = async (defaultTab: 'card' | 'file') => { | ||||||||||||||||||||||||||||||||
| this._embedPopoverOpen = false; | ||||||||||||||||||||||||||||||||
| let chooser = this.cardContext?.markdownEmbedChooser; | ||||||||||||||||||||||||||||||||
|
|
@@ -938,129 +977,134 @@ export default class CodeMirrorEditor extends GlimmerComponent<CodeMirrorEditorS | |||||||||||||||||||||||||||||||
| data-test-codemirror-editor | ||||||||||||||||||||||||||||||||
| ...attributes | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| {{! ── Docked toolbar ── }} | ||||||||||||||||||||||||||||||||
| {{! template-lint-disable no-pointer-down-event-binding }} | ||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||
| class='codemirror-toolbar' | ||||||||||||||||||||||||||||||||
| data-overlay-clip-header | ||||||||||||||||||||||||||||||||
| data-test-markdown-toolbar | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| {{yield to='leadingControls'}} | ||||||||||||||||||||||||||||||||
| {{#if (has-block 'leadingControls')}} | ||||||||||||||||||||||||||||||||
| <span class='toolbar-divider'></span> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| {{#if this._currentBfmRef}} | ||||||||||||||||||||||||||||||||
| <Tooltip @placement='top' data-test-toolbar-tooltip='edit-embed'> | ||||||||||||||||||||||||||||||||
| <:trigger> | ||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||
| class='toolbar-btn' | ||||||||||||||||||||||||||||||||
| data-test-toolbar='edit-embed' | ||||||||||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||||||||||
| aria-label='Edit embed' | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._preventFocusLoss}} | ||||||||||||||||||||||||||||||||
| {{on 'click' this._openEditEmbed}} | ||||||||||||||||||||||||||||||||
| ><PencilIcon width='16' height='16' /></button> | ||||||||||||||||||||||||||||||||
| </:trigger> | ||||||||||||||||||||||||||||||||
| <:content> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip'> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip__label'>Edit embed</span> | ||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||
| </:content> | ||||||||||||||||||||||||||||||||
| </Tooltip> | ||||||||||||||||||||||||||||||||
| {{else}} | ||||||||||||||||||||||||||||||||
| <div class='toolbar-embed-trigger'> | ||||||||||||||||||||||||||||||||
| <Tooltip @placement='top' data-test-toolbar-tooltip='add-embed'> | ||||||||||||||||||||||||||||||||
| <div class='codemirror-body' data-test-codemirror-body> | ||||||||||||||||||||||||||||||||
| {{! ── Docked toolbar ── }} | ||||||||||||||||||||||||||||||||
| {{! template-lint-disable no-pointer-down-event-binding }} | ||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||
| class='codemirror-toolbar' | ||||||||||||||||||||||||||||||||
| data-overlay-clip-header | ||||||||||||||||||||||||||||||||
| data-test-markdown-toolbar | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| {{yield to='leadingControls'}} | ||||||||||||||||||||||||||||||||
| {{#if (has-block 'leadingControls')}} | ||||||||||||||||||||||||||||||||
| <span class='toolbar-divider'></span> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| {{#if this._currentBfmRef}} | ||||||||||||||||||||||||||||||||
| <Tooltip @placement='top' data-test-toolbar-tooltip='edit-embed'> | ||||||||||||||||||||||||||||||||
| <:trigger> | ||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||
| class='toolbar-btn | ||||||||||||||||||||||||||||||||
| {{if this._embedPopoverOpen "toolbar-btn--active"}}' | ||||||||||||||||||||||||||||||||
| data-test-toolbar='add-embed' | ||||||||||||||||||||||||||||||||
| class='toolbar-btn' | ||||||||||||||||||||||||||||||||
| data-test-toolbar='edit-embed' | ||||||||||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||||||||||
| aria-label='Add embed' | ||||||||||||||||||||||||||||||||
| aria-expanded={{if this._embedPopoverOpen 'true' 'false'}} | ||||||||||||||||||||||||||||||||
| aria-label='Edit embed' | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._preventFocusLoss}} | ||||||||||||||||||||||||||||||||
| {{on 'click' this._toggleEmbedPopover}} | ||||||||||||||||||||||||||||||||
| ><PlusIcon width='16' height='16' /></button> | ||||||||||||||||||||||||||||||||
| {{on 'click' this._openEditEmbed}} | ||||||||||||||||||||||||||||||||
| ><PencilIcon width='16' height='16' /></button> | ||||||||||||||||||||||||||||||||
| </:trigger> | ||||||||||||||||||||||||||||||||
| <:content> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip'> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip__label'>Add embed</span> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip__label'>Edit embed</span> | ||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||
| </:content> | ||||||||||||||||||||||||||||||||
| </Tooltip> | ||||||||||||||||||||||||||||||||
| {{#if this._embedPopoverOpen}} | ||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||
| class='toolbar-embed-popover' | ||||||||||||||||||||||||||||||||
| data-test-toolbar-embed-popover | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||||||||||
| class='toolbar-embed-popover__item' | ||||||||||||||||||||||||||||||||
| data-test-toolbar-embed='card' | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._preventFocusLoss}} | ||||||||||||||||||||||||||||||||
| {{on 'click' (fn this._openEmbedChooser 'card')}} | ||||||||||||||||||||||||||||||||
| >Add a card</button> | ||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||||||||||
| class='toolbar-embed-popover__item' | ||||||||||||||||||||||||||||||||
| data-test-toolbar-embed='file' | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._preventFocusLoss}} | ||||||||||||||||||||||||||||||||
| {{on 'click' (fn this._openEmbedChooser 'file')}} | ||||||||||||||||||||||||||||||||
| >Add a file</button> | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
| <span class='toolbar-divider'></span> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| {{#each this.toolbarButtons as |btn|}} | ||||||||||||||||||||||||||||||||
| {{#if btn.divider}} | ||||||||||||||||||||||||||||||||
| <span class='toolbar-divider'></span> | ||||||||||||||||||||||||||||||||
| {{else}} | ||||||||||||||||||||||||||||||||
| {{! Every item gets a styled tooltip — the label, plus a shortcut | ||||||||||||||||||||||||||||||||
| <div class='toolbar-embed-trigger'> | ||||||||||||||||||||||||||||||||
| <Tooltip @placement='top' data-test-toolbar-tooltip='add-embed'> | ||||||||||||||||||||||||||||||||
| <:trigger> | ||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||
| class='toolbar-btn | ||||||||||||||||||||||||||||||||
| {{if this._embedPopoverOpen "toolbar-btn--active"}}' | ||||||||||||||||||||||||||||||||
| data-test-toolbar='add-embed' | ||||||||||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||||||||||
| aria-label='Add embed' | ||||||||||||||||||||||||||||||||
| aria-expanded={{if this._embedPopoverOpen 'true' 'false'}} | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._preventFocusLoss}} | ||||||||||||||||||||||||||||||||
| {{on 'click' this._toggleEmbedPopover}} | ||||||||||||||||||||||||||||||||
| ><PlusIcon width='16' height='16' /></button> | ||||||||||||||||||||||||||||||||
| </:trigger> | ||||||||||||||||||||||||||||||||
| <:content> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip'> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip__label'>Add embed</span> | ||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||
| </:content> | ||||||||||||||||||||||||||||||||
| </Tooltip> | ||||||||||||||||||||||||||||||||
| {{#if this._embedPopoverOpen}} | ||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||
| class='toolbar-embed-popover' | ||||||||||||||||||||||||||||||||
| style={{htmlSafe this._embedPopoverStyle}} | ||||||||||||||||||||||||||||||||
| data-test-toolbar-embed-popover | ||||||||||||||||||||||||||||||||
| {{this._trackEmbedPopover}} | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||||||||||
| class='toolbar-embed-popover__item' | ||||||||||||||||||||||||||||||||
| data-test-toolbar-embed='card' | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._preventFocusLoss}} | ||||||||||||||||||||||||||||||||
| {{on 'click' (fn this._openEmbedChooser 'card')}} | ||||||||||||||||||||||||||||||||
| >Add a card</button> | ||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||||||||||
| class='toolbar-embed-popover__item' | ||||||||||||||||||||||||||||||||
| data-test-toolbar-embed='file' | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._preventFocusLoss}} | ||||||||||||||||||||||||||||||||
| {{on 'click' (fn this._openEmbedChooser 'file')}} | ||||||||||||||||||||||||||||||||
| >Add a file</button> | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
| <span class='toolbar-divider'></span> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| {{#each this.toolbarButtons as |btn|}} | ||||||||||||||||||||||||||||||||
| {{#if btn.divider}} | ||||||||||||||||||||||||||||||||
| <span class='toolbar-divider'></span> | ||||||||||||||||||||||||||||||||
| {{else}} | ||||||||||||||||||||||||||||||||
| {{! Every item gets a styled tooltip — the label, plus a shortcut | ||||||||||||||||||||||||||||||||
| key badge when the item has a CodeMirror binding. The tooltip | ||||||||||||||||||||||||||||||||
| is suppressed while the control is disabled. }} | ||||||||||||||||||||||||||||||||
| <Tooltip | ||||||||||||||||||||||||||||||||
| @placement='top' | ||||||||||||||||||||||||||||||||
| @disabled={{btn.disabled}} | ||||||||||||||||||||||||||||||||
| data-test-toolbar-tooltip={{btn.testId}} | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| <:trigger> | ||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||
| class='toolbar-btn {{if btn.active "toolbar-btn--active"}}' | ||||||||||||||||||||||||||||||||
| data-test-toolbar={{btn.testId}} | ||||||||||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||||||||||
| aria-label={{btn.label}} | ||||||||||||||||||||||||||||||||
| aria-pressed={{btn.ariaPressed}} | ||||||||||||||||||||||||||||||||
| disabled={{btn.disabled}} | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._preventFocusLoss}} | ||||||||||||||||||||||||||||||||
| {{on 'click' btn.action}} | ||||||||||||||||||||||||||||||||
| >{{#let btn.icon as |Icon|}}<Icon | ||||||||||||||||||||||||||||||||
| width='16' | ||||||||||||||||||||||||||||||||
| height='16' | ||||||||||||||||||||||||||||||||
| />{{/let}}</button> | ||||||||||||||||||||||||||||||||
| </:trigger> | ||||||||||||||||||||||||||||||||
| <:content> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip'> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip__label'>{{btn.label}}</span> | ||||||||||||||||||||||||||||||||
| {{#if btn.shortcut}} | ||||||||||||||||||||||||||||||||
| <kbd class='shortcut-key'>{{btn.shortcut}}</kbd> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||
| </:content> | ||||||||||||||||||||||||||||||||
| </Tooltip> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
| {{/each}} | ||||||||||||||||||||||||||||||||
| <Tooltip | ||||||||||||||||||||||||||||||||
| @placement='top' | ||||||||||||||||||||||||||||||||
| @disabled={{btn.disabled}} | ||||||||||||||||||||||||||||||||
| data-test-toolbar-tooltip={{btn.testId}} | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| <:trigger> | ||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||
| class='toolbar-btn | ||||||||||||||||||||||||||||||||
| {{if btn.active "toolbar-btn--active"}}' | ||||||||||||||||||||||||||||||||
| data-test-toolbar={{btn.testId}} | ||||||||||||||||||||||||||||||||
| type='button' | ||||||||||||||||||||||||||||||||
| aria-label={{btn.label}} | ||||||||||||||||||||||||||||||||
| aria-pressed={{btn.ariaPressed}} | ||||||||||||||||||||||||||||||||
| disabled={{btn.disabled}} | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._preventFocusLoss}} | ||||||||||||||||||||||||||||||||
| {{on 'click' btn.action}} | ||||||||||||||||||||||||||||||||
| >{{#let btn.icon as |Icon|}}<Icon | ||||||||||||||||||||||||||||||||
| width='16' | ||||||||||||||||||||||||||||||||
| height='16' | ||||||||||||||||||||||||||||||||
| />{{/let}}</button> | ||||||||||||||||||||||||||||||||
| </:trigger> | ||||||||||||||||||||||||||||||||
| <:content> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip'> | ||||||||||||||||||||||||||||||||
| <span class='toolbar-tooltip__label'>{{btn.label}}</span> | ||||||||||||||||||||||||||||||||
| {{#if btn.shortcut}} | ||||||||||||||||||||||||||||||||
| <kbd class='shortcut-key'>{{btn.shortcut}}</kbd> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||
| </:content> | ||||||||||||||||||||||||||||||||
| </Tooltip> | ||||||||||||||||||||||||||||||||
| {{/if}} | ||||||||||||||||||||||||||||||||
| {{/each}} | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| {{! template-lint-disable no-invalid-interactive }} | ||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||
| class='codemirror-mount' | ||||||||||||||||||||||||||||||||
| data-test-codemirror-mount | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._focusEditorOnPointerDown}} | ||||||||||||||||||||||||||||||||
| {{this.mountEditor this.cm @content @onUpdate this.livePreview}} | ||||||||||||||||||||||||||||||||
| ></div> | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| {{! template-lint-disable no-invalid-interactive }} | ||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||
| class='codemirror-mount' | ||||||||||||||||||||||||||||||||
| data-test-codemirror-mount | ||||||||||||||||||||||||||||||||
| {{on 'mousedown' this._focusEditorOnPointerDown}} | ||||||||||||||||||||||||||||||||
| {{this.mountEditor this.cm @content @onUpdate this.livePreview}} | ||||||||||||||||||||||||||||||||
| ></div> | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| {{#if this.livePreview}} | ||||||||||||||||||||||||||||||||
|
|
@@ -1169,6 +1213,32 @@ export default class CodeMirrorEditor extends GlimmerComponent<CodeMirrorEditorS | |||||||||||||||||||||||||||||||
| outline-color: var(--ring, var(--boxel-highlight)); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /* Wraps the sticky toolbar + editor mount so the editor's rounded | ||||||||||||||||||||||||||||||||
| corners clip the toolbar's square bottom corners when it docks at | ||||||||||||||||||||||||||||||||
| the bottom on scroll. `overflow: clip` (not `hidden`) does this | ||||||||||||||||||||||||||||||||
| without establishing a scroll container, so the toolbar keeps | ||||||||||||||||||||||||||||||||
| sticking to the outer scroll panel. The radius is inset by the 1px | ||||||||||||||||||||||||||||||||
| border so it hugs the border's inner curve. | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| The toolbar's two menus must escape this clip: when the toolbar | ||||||||||||||||||||||||||||||||
| docks at the bottom there is zero room below it inside the box, so a | ||||||||||||||||||||||||||||||||
| menu rendered here would be swallowed while its trigger still looks | ||||||||||||||||||||||||||||||||
| normal. Both are kept out — the mode selector wormholes out of place | ||||||||||||||||||||||||||||||||
| (BoxelSelect without `renderInPlace`) and the Add-embed popover is | ||||||||||||||||||||||||||||||||
| `position: fixed` (its containing block is the viewport, so this | ||||||||||||||||||||||||||||||||
| clip can't reach it). */ | ||||||||||||||||||||||||||||||||
| .codemirror-body { | ||||||||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||||||||
| flex-direction: column; | ||||||||||||||||||||||||||||||||
| flex: 1; | ||||||||||||||||||||||||||||||||
| min-height: 0; | ||||||||||||||||||||||||||||||||
| /* Inset by the 1px border; clamped at 0 so a card that themes | ||||||||||||||||||||||||||||||||
| `--boxel-border-radius` below 1px doesn't drive the calc negative | ||||||||||||||||||||||||||||||||
| (which would invalidate the declaration). */ | ||||||||||||||||||||||||||||||||
| border-radius: max(0px, calc(var(--boxel-border-radius) - 1px)); | ||||||||||||||||||||||||||||||||
| overflow: clip; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
Comment on lines
+1230
to
+1240
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Claude Code 🤖] Blocking — regression. This clip box swallows both menus that live in the toolbar, not just the Add-embed dropdown the comment above accounts for. The one that isn't mentioned anywhere in this change is the Compose / Source / Preview mode selector — the control this change's own summary names as the left end of the grey bar. Background: what Both toolbar menus land on the clipped side of that rule.
Measured, using this repo's real CSS and tokens. I rebuilt the box structure in Chromium from the declarations in this file,
The toolbar is still fully on screen in every one of those rows — the trigger looks and behaves normally, and the menu it opens is simply not there. On a one-line body field that state is ~57px of outer-panel scroll away. With a long body the failure window is the last ~100px of scroll, i.e. precisely the bottom-docked state this change exists to fix. Flipping the menu upward is not an escape either: ember-basic-dropdown's in-place positioning measures The way out. The menus have to live outside whatever box does the clipping — any clip that contains the toolbar clips the toolbar's positioned descendants, so moving or resizing the wrapper won't help.
Generated by Claude Code
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Claude Code 🤖] Fixed in 8a88e2f. Dropped |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /* Fill the field so clicking anywhere below the text focuses it. */ | ||||||||||||||||||||||||||||||||
| .codemirror-mount { | ||||||||||||||||||||||||||||||||
| flex: 1; | ||||||||||||||||||||||||||||||||
|
|
@@ -1483,11 +1553,13 @@ export default class CodeMirrorEditor extends GlimmerComponent<CodeMirrorEditorS | |||||||||||||||||||||||||||||||
| position: relative; | ||||||||||||||||||||||||||||||||
| display: inline-flex; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| /* `position: fixed` (coordinates set inline from the trigger's rect) | ||||||||||||||||||||||||||||||||
| so the popover escapes the `.codemirror-body` corner clip — its | ||||||||||||||||||||||||||||||||
| containing block is the viewport, which that clip can't reach. An | ||||||||||||||||||||||||||||||||
| absolute popover here would be swallowed once the toolbar docks at | ||||||||||||||||||||||||||||||||
| the bottom, where there is no room left below it inside the clip. */ | ||||||||||||||||||||||||||||||||
| .toolbar-embed-popover { | ||||||||||||||||||||||||||||||||
| position: absolute; | ||||||||||||||||||||||||||||||||
| top: 100%; | ||||||||||||||||||||||||||||||||
| left: 0; | ||||||||||||||||||||||||||||||||
| margin-top: 4px; | ||||||||||||||||||||||||||||||||
| position: fixed; | ||||||||||||||||||||||||||||||||
| min-width: 140px; | ||||||||||||||||||||||||||||||||
| background: var(--boxel-light); | ||||||||||||||||||||||||||||||||
| color: var(--boxel-dark); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new
overflow: clipalso clips.toolbar-embed-popover, which remains inside this wrapper and is positioned below the toolbar withtop: 100%. When the outer edit panel is scrolled far enough that the sticky toolbar is constrained against the editor's bottom edge—the state this change targets—there is no room below it inside the wrapper, so opening Add embed hides part or all of the menu and can make its actions unclickable. The added test only verifies that the menu exists in the DOM, not that it is visible; the popover should escape the clipped subtree or flip above the toolbar near the bottom.Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Claude Code 🤖] Fixed in 8a88e2f. The Add-embed popover is now
position: fixed, pinned under its trigger fromgetBoundingClientRect()and repositioned on scroll/resize while it's open. Its containing block is the viewport, so.codemirror-body'soverflow: clipcan no longer reach it — the menu stays visible and clickable when the toolbar docks at the bottom. The test was inverted to assert the popover is fixed-positioned rather than merely present in the DOM.You were right and it under-counted: the mode selector had the same problem (its menu is taller), and it's fixed too — it now renders in the shared dropdown wormhole instead of in place.