fix(sw): stabilize footer command layout and overflow alignment
This commit is contained in:
1 parent
41e963a12a
commit
73e30242f2
7 files changed
+36
-21
No files matched your search
@@ -32,8 +32,9 @@ export interface SWFooterProps extends Omit<HTMLAttributes<HTMLElement>, "childr
|
||||
/** A command was clicked. The host runs it and updates `activeToolId`. */
|
||||
onToolSelect?: (toolId: string, categoryId: string, tool: SWFooterTool) => void
|
||||
/**
|
||||
* Slots of the command row (commands + empty + slots). Default 17 (Figma 1920px frame), shrinking to the bar width.
|
||||
* With `command` the row keeps its own width: default commands + 2 empty slots.
|
||||
* Most slots of the command row (commands + empty + slots). The row width follows the bar width only (never the
|
||||
* command count of the category). Default 17 (Figma 1920px frame); with `command` no limit (the share of the
|
||||
* free width decides).
|
||||
*/
|
||||
slotCount?: number
|
||||
/** An empty + slot was clicked (register a command). `slotIndex` is 0-based in the row. Omitted: the empty slots are inert. */
|
||||
@@ -87,13 +88,17 @@ export const SWFooter = forwardRef<HTMLElement, SWFooterProps>(function SWFooter
|
||||
const panelId = `${uid}panel`
|
||||
const tabPrefix = `${uid}tab`
|
||||
|
||||
// Room for slots, measured (Figma 26:10097 has no narrow layout; the reference screens of 2026-10-20 do):
|
||||
// empty slots go first, then the commands that do not fit move to the ▲ panel above the last slot.
|
||||
// Room for slots comes from the bar width only, never from the current category's command count: switching
|
||||
// categories keeps the slot area, 명령어 전체보기 and the command line in place (2026-10-20). Without `command`
|
||||
// the group fills the bar (Figma 26:10097: up to 17 slots); with `command` the free width is shared by
|
||||
// --hm-sw-footer-slot-share (command line ≥ --hm-sw-footer-command-min-width). Commands beyond the room move
|
||||
// to the ▲ panel above the last slot; fewer commands leave empty slots.
|
||||
const rootRef = useRef<HTMLElement | null>(null)
|
||||
const groupRef = useRef<HTMLDivElement>(null)
|
||||
const auxRef = useRef<HTMLDivElement>(null)
|
||||
const embedded = command !== undefined && command !== null && command !== false
|
||||
const [fit, setFit] = useState(Number.POSITIVE_INFINITY)
|
||||
// Before the first measure: the Figma 1920 row (17 slots). Never infinite (the row renders this many slots).
|
||||
const [fit, setFit] = useState(slotCount ?? 17)
|
||||
useLayoutEffect(() => {
|
||||
const root = rootRef.current
|
||||
const group = groupRef.current
|
||||
@@ -104,8 +109,11 @@ export const SWFooter = forwardRef<HTMLElement, SWFooterProps>(function SWFooter
|
||||
if (embedded) {
|
||||
const aux = auxRef.current
|
||||
const auxWidth = aux ? aux.offsetWidth + parseFloat(getComputedStyle(aux).marginRight || "0") : 0
|
||||
const commandMin = parseFloat(getComputedStyle(root).getPropertyValue("--hm-sw-footer-command-min-width")) || 0
|
||||
room = root.clientWidth - auxWidth - commandMin - 4 - end - 2
|
||||
const style = getComputedStyle(root)
|
||||
const commandMin = parseFloat(style.getPropertyValue("--hm-sw-footer-command-min-width")) || 0
|
||||
const share = parseFloat(style.getPropertyValue("--hm-sw-footer-slot-share")) || 0.5
|
||||
const free = root.clientWidth - auxWidth - 4 - end - 2
|
||||
room = Math.min(free * share, free - commandMin)
|
||||
}
|
||||
setFit(Math.max(1, Math.floor((room - 1) / SLOT)))
|
||||
}
|
||||
@@ -116,11 +124,10 @@ export const SWFooter = forwardRef<HTMLElement, SWFooterProps>(function SWFooter
|
||||
if (auxRef.current) observer.observe(auxRef.current)
|
||||
return () => observer.disconnect()
|
||||
}, [embedded])
|
||||
const overflow = tools.length > fit
|
||||
const visible = overflow ? tools.slice(0, Math.max(0, fit - 1)) : tools
|
||||
const slots = Math.max(1, Math.min(slotCount ?? (embedded ? Number.POSITIVE_INFINITY : 17), fit))
|
||||
const overflow = tools.length > slots
|
||||
const visible = overflow ? tools.slice(0, Math.max(0, slots - 1)) : tools
|
||||
const hidden = overflow ? tools.slice(visible.length) : []
|
||||
const wanted = embedded ? slotCount ?? tools.length + 2 : slotCount ?? 17
|
||||
const slots = overflow ? fit : Math.max(tools.length, Math.min(wanted, fit))
|
||||
|
||||
// ▲ panel of the commands that do not fit (ico_arrow 26:10023: ▲ closed, ▼ open).
|
||||
const [moreOpen, setMoreOpen] = useState(false)
|
||||
|
||||
Reference in new issue
Block a user