-
Notifications
You must be signed in to change notification settings - Fork 309
fix: scale selection label arrow for narrow labels #165
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -10,12 +10,12 @@ import type { Component } from "solid-js"; | |
| import type { ArrowPosition, SelectionLabelProps } from "../../types.js"; | ||
| import { | ||
| VIEWPORT_MARGIN_PX, | ||
| ARROW_HEIGHT_PX, | ||
| ARROW_CENTER_PERCENT, | ||
| ARROW_LABEL_MARGIN_PX, | ||
| LABEL_GAP_PX, | ||
| PANEL_STYLES, | ||
| } from "../../constants.js"; | ||
| import { getArrowSize } from "../../utils/get-arrow-size.js"; | ||
| import { isKeyboardEventTriggeredByInput } from "../../utils/is-keyboard-event-triggered-by-input.js"; | ||
| import { cn } from "../../utils/cn.js"; | ||
| import { getTagDisplay } from "../../utils/get-tag-display.js"; | ||
|
|
@@ -40,6 +40,7 @@ const DEFAULT_OFFSCREEN_POSITION = { | |
|
|
||
| export const SelectionLabel: Component<SelectionLabelProps> = (props) => { | ||
| let containerRef: HTMLDivElement | undefined; | ||
| let panelRef: HTMLDivElement | undefined; | ||
| let inputRef: HTMLTextAreaElement | undefined; | ||
| let isTagCurrentlyHovered = false; | ||
| let lastValidPosition: { | ||
|
|
@@ -53,6 +54,7 @@ export const SelectionLabel: Component<SelectionLabelProps> = (props) => { | |
|
|
||
| const [measuredWidth, setMeasuredWidth] = createSignal(0); | ||
| const [measuredHeight, setMeasuredHeight] = createSignal(0); | ||
| const [panelWidth, setPanelWidth] = createSignal(0); | ||
| const [arrowPosition, setArrowPosition] = | ||
| createSignal<ArrowPosition>("bottom"); | ||
| const [viewportVersion, setViewportVersion] = createSignal(0); | ||
|
|
@@ -89,6 +91,9 @@ export const SelectionLabel: Component<SelectionLabelProps> = (props) => { | |
| setMeasuredWidth(rect.width); | ||
| setMeasuredHeight(rect.height); | ||
| } | ||
| if (panelRef) { | ||
| setPanelWidth(panelRef.getBoundingClientRect().width); | ||
| } | ||
| }; | ||
|
|
||
| const handleTagHoverChange = (hovered: boolean) => { | ||
|
|
@@ -215,11 +220,13 @@ export const SelectionLabel: Component<SelectionLabelProps> = (props) => { | |
| const selectionBottom = bounds.y + bounds.height; | ||
| const selectionTop = bounds.y; | ||
|
|
||
| const actualArrowHeight = getArrowSize(panelWidth()); | ||
|
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. This uses |
||
|
|
||
| // HACK: Use cursorX as anchor point, CSS transform handles centering via translateX(-50%) | ||
| // This avoids the flicker when content changes because centering doesn't depend on JS measurement | ||
| const anchorX = cursorX; | ||
| let edgeOffsetX = 0; | ||
| let positionTop = selectionBottom + ARROW_HEIGHT_PX + LABEL_GAP_PX; | ||
| let positionTop = selectionBottom + actualArrowHeight + LABEL_GAP_PX; | ||
|
|
||
| // Calculate edge clamping offset (only applied when we have valid measurements) | ||
| if (labelWidth > 0) { | ||
|
|
@@ -234,7 +241,7 @@ export const SelectionLabel: Component<SelectionLabelProps> = (props) => { | |
| } | ||
| } | ||
|
|
||
| const totalHeightNeeded = labelHeight + ARROW_HEIGHT_PX + LABEL_GAP_PX; | ||
| const totalHeightNeeded = labelHeight + actualArrowHeight + LABEL_GAP_PX; | ||
| const fitsBelow = | ||
| positionTop + labelHeight <= viewportHeight - VIEWPORT_MARGIN_PX; | ||
|
|
||
|
|
@@ -371,6 +378,7 @@ export const SelectionLabel: Component<SelectionLabelProps> = (props) => { | |
| position={arrowPosition()} | ||
| leftPercent={computedPosition().arrowLeftPercent} | ||
| leftOffsetPx={computedPosition().arrowLeftOffset} | ||
| labelWidth={panelWidth()} | ||
|
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. Critical bug: The The arrow will only get the correct size on subsequent re-renders after Solution: Move the Arrow after the panelRef div, or add a conditional render that waits for |
||
| /> | ||
|
|
||
| <Show when={isCompletedStatus() && !props.error}> | ||
|
|
@@ -394,6 +402,7 @@ export const SelectionLabel: Component<SelectionLabelProps> = (props) => { | |
| </Show> | ||
|
|
||
| <div | ||
| ref={panelRef} | ||
| class={cn( | ||
| "contain-layout flex items-center gap-[5px] rounded-[10px] antialiased w-fit h-fit p-0 [font-synthesis:none] [corner-shape:superellipse(1.25)]", | ||
| PANEL_STYLES, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,6 +57,8 @@ export const FROZEN_GLOW_COLOR = `rgba(${GRAB_PURPLE_RGB}, 0.15)`; | |
| export const FROZEN_GLOW_EDGE_PX = 50; | ||
|
|
||
| export const ARROW_HEIGHT_PX = 8; | ||
| export const ARROW_MIN_SIZE_PX = 4; | ||
| export const ARROW_MAX_LABEL_WIDTH_RATIO = 0.2; | ||
|
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. The 20% ratio seems arbitrary. For a 30px label, arrow becomes 6px. Was this tested visually? Consider documenting the rationale. |
||
| export const ARROW_CENTER_PERCENT = 50; | ||
| export const ARROW_LABEL_MARGIN_PX = 16; | ||
| export const LABEL_GAP_PX = 4; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { | ||
| ARROW_HEIGHT_PX, | ||
| ARROW_MIN_SIZE_PX, | ||
| ARROW_MAX_LABEL_WIDTH_RATIO, | ||
| } from "../constants.js"; | ||
|
|
||
| export const getArrowSize = (labelWidth: number): number => { | ||
| if (labelWidth <= 0) return ARROW_HEIGHT_PX; | ||
| const scaledSize = labelWidth * ARROW_MAX_LABEL_WIDTH_RATIO; | ||
| return Math.max(ARROW_MIN_SIZE_PX, Math.min(ARROW_HEIGHT_PX, scaledSize)); | ||
|
Comment on lines
+9
to
+10
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. For very narrow labels (15px wide), this produces 3px which gets clamped to 4px. Is 4px arrow still too large for the narrowest cases? The ratio and minimum should be validated against actual short tag names like |
||
| }; | ||
Uh oh!
There was an error while loading. Please reload this page.